diff options
695 files changed, 93389 insertions, 0 deletions
@@ -63,6 +63,7 @@ <modules> <module>common-util</module> <module>rest-client</module> + <module>winery</module> </modules> <dependencyManagement> diff --git a/winery/.gitattributes b/winery/.gitattributes new file mode 100644 index 0000000..d64359b --- /dev/null +++ b/winery/.gitattributes @@ -0,0 +1 @@ +gradlew eol=lf diff --git a/winery/.gitignore b/winery/.gitignore new file mode 100644 index 0000000..698d54e --- /dev/null +++ b/winery/.gitignore @@ -0,0 +1,12 @@ +.gradle/ +.idea/ +.project +.settings/org.eclipse.m2e.core.prefs +bin/ +build/ +release.properties +**/*.iml +**/hs_err_pid*.log +**/pom.xml.* +**/rebel.xml +target/
\ No newline at end of file diff --git a/winery/CONTRIBUTING.md b/winery/CONTRIBUTING.md new file mode 100644 index 0000000..b88f2e5 --- /dev/null +++ b/winery/CONTRIBUTING.md @@ -0,0 +1,141 @@ +(This is based on the [Jetty Contributing Patches] documentation) + +# Contributing Patches +This file describes how to contribute a patch to the Winery project. +You should first familiarize yourself with the Eclipse wiki page on [contributing via Git]. + +## Sign a CLA +The Eclipse Foundation has a strong Intellectual Property policy which tracks contributions in detail to ensure that: + +* Did the contributor author 100% of the content? +* Does the contributor have the rights to contribute this content to Eclipse? +* Is the contribution under the project's license(s) (e.g. [EPL]) + +Thus a contributor needs to e-sign a [Contributor License Agreement] (for more explanation see the Eclipse [CLA FAQ]) regardless of how their contribution patch is provided. + +### Signing an Eclipse CLA +Log into the [Eclipse projects forge] (you will need to create an account with the Eclipse Foundation if you have not already done so); click on "Contributor License Agreement"; and Complete the form. Be sure to use the same email address when you create any Git commit records. + +## Use Bugzilla +Once a CLA has been signed, then patches should always be contributed with an associated [project bugzilla]. +The CLA symbol next to the contributors name in the bugzilla should be green to indicate the CLA is on record. +This will allow the authors contribution to both be tracked and acknowledged. + +## Git Diff +The simplest way to contribute a patch is to make a modification to a cloned copy of Winery and then generate a diff between the two versions. +We don't really like this approach, but it is difficult to ignore how easy it is for the contributer. +Just remember, you still need to create a CLA as mentioned above. + +From the top level of the cloned project: + + $ git diff > ######.patch + +The hash marks should be the bugzilla issue that you will be attaching the issue to. +All patches coming into Winery must come in through bugzilla for IP tracking purposes. +Depending on the size of the patch the patch itself may be flagged as `+iplog` where it is subject to lawyer review and inclusion with our iplog from here to eternity. +We are sorry we are unable to apply patches that we receive via email. +So if you have the bugzilla issue created already just attach the issue. +If there is no bugzilla issue yet, create one, make sure the patch is named appropriately and attach it. + +When the developer reviews the patch and goes to apply it they will use: + + $ git apply < ######.patch + +If you want to be a nice person, test your patch on a clean clone to ensure that it applies cleanly. Nothing frustrates a developer quite like a patch that doesn't apply. + +## RECOMMENDED - Git Format Patch +Another approach if you want your name in shiny lights in our commit logs is to use the format patch option. +With this approach you commit into your cloned copy of Winery and use the git format patch option to generate what looks like an email message containing all of the commit information. +This applies as a commit directly when we apply it so it should be obvious that as with the normal diff we must accept these sorts of patches only via bugzilla. +Make sure your commit is using the email that you registered in your CLA or no amount of pushing the in world from us will get past the eclipse git commit hooks. +When you do your commit to your local repo it is also vital that you "sign-off" on the commit using `git commit -s`. +Without the sign-off, your patch cannot be applied to the jetty repo because it will be rejected by the eclipse git commit hooks. + +From the top level of the cloned project: + +Make your changes and commit them locally using `git commit -s`: + + $ git commit -s + +Then use `git log` to identify the commit(s) you want to include in your patch: + + commit 70e29326fe904675f772b88a67128c0b3529565e + Author: John Doe <john.doe@who.com> + Date: Tue Aug 2 14:36:50 2011 +0200 353563: + HttpDestinationQueueTest too slow + +Use `git format-patch` to create the patch: + + $ git format-patch -M -B 70e29326fe904675f772b88a67128c0b3529565e + +This will create a single patch file for each commit since the specified commit. +The names will start with `0001-[commitmessage].patch`. +See http://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html for details. + +When a developer goes to apply this sort of patch then we must assume responsibility for applying it to our codebase from the IP perspective. +So we must be comfortable with the providence of the patch and that it is clear of potential issues. +This is not like a diff where you get to edit it and clean up issues before it gets applied. +The commit is recorded locally and the developer will then have a chance to make additional commits to address any lingering issues. +It is critically important that developers applying these sorts of patches are fully aware of what is being committed and what they are accepting. + +To apply the patch the developer will use a command like: + + $ git am 0001-353563-HttpDestinationQueueTest-too-slow.patch + +Providing it applies cleanly there will now be a commit in their local copy and they can either make additional commits or push it out. + +### Note +It is intended that developers are also able to counter-sign the patch by using the `-s` option with the `git am` command. +However as the git hook that processes the commit currently has a bug it is recommended that developers do NOT use the `-s` option. +See https://bugs.eclipse.org/bugs/show_bug.cgi?id=415307 + +## Git Amend +If a committer is having trouble applying the patch cleanly with git am, they can use `git commit --amend` to modify the author and signoff the commit. For example: + + $ git checkout -b patch + $ git apply john-doe.patch + $ git commit -a -m "<Original commit message from John Doe>" + +At this point the patch is committed with the committer's name on a local branch + + $ git commit --amend --author "John Doe <john.doe@who.com>" --signoff + +Now the patch has the right author and it has been signed off + + $ git checkout master + $ git merge patch + +Now the local branch has been merged into master with the right author + + $ git branch -d patch + $ git push + +## Contributing via Gerrit +Winery currently has no Gerrit infrastructure in place. +In case, we will receive a lot of patches, we will enable [the Eclipse Gerrit workflow](https://wiki.eclipse.org/Gerrit). + +## Contributing via Github PullRequests +The Winery eclipse git repository is mirrored to github at http://github.com/winery/winery. +Github has a suite of collaboration tools for submitting and reviewing contributions, but unfortunately the Eclipse Foundations IP policy prevents direct merging of github pull requests. +However, if a contributor makes a pull request and references that in a bugzilla with a signed CLA, then a Winery committer should be able to fetch, merge and commit the pull requests without the need to create a separate patch. + +## Github pull requests for Committers +A committer can prepare their repository for accepting Github pull requests as follows: + + $ git remote add github https://github.com/winery/winery.git + $ git config --add remote.github.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" + +A committer can then fetch the latest pull request and check them out as follows (for pull request #123): + + $ git fetch github + $ git checkout pr/123 + +The committer can then use normal git commands to merge the contribution back to the master branch. The commits may need to be signed off so they can be pushed using the git amend technique above. + + [CLA FAQ]: https://www.eclipse.org/legal/clafaq.php + [Contributor License Agreement]: https://www.eclipse.org/legal/CLA.php + [contributing via Git]: http://wiki.eclipse.org/Development_Resources/Contributing_via_Git + [Eclipse projects forge]: https://projects.eclipse.org/user/login/sso + [EPL]: https://www.eclipse.org/legal/epl-v10.html + [Jetty Contributing Patches]: https://www.eclipse.org/jetty/documentation/current/contributing-patches.html + [project bugzilla]: https://bugs.eclipse.org/bugs/describecomponents.cgi?product=Winery diff --git a/winery/LICENSE-ASL.txt b/winery/LICENSE-ASL.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/LICENSE-ASL.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/LICENSE-EPL.txt b/winery/LICENSE-EPL.txt new file mode 100644 index 0000000..5d80026 --- /dev/null +++ b/winery/LICENSE-EPL.txt @@ -0,0 +1,227 @@ +Eclipse Public License - v 1.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF + THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and + are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by such + Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include additions to the Program which: (i) are + separate modules of software distributed in conjunction with the + Program under their own license agreement, and (ii) are not derivative + works of the Program. + + "Contributor" means any person or entity that distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement, + including all Contributors. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. This patent license shall + apply to the combination of the Contribution and the Program if, at the + time the Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other combinations + which include the Contribution. No hardware per se is licensed + hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility to + secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow Recipient + to distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + + 3. REQUIREMENTS + + A Contributor may choose to distribute the Program in object code form + under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or conditions + of title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software exchange. + + When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + + Contributors may not remove or alter any copyright notices contained + within the Program. + + Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the + Indemnified Contributor to the extent caused by the acts or omissions + of such Commercial Contributor in connection with its distribution of + the Program in a commercial product offering. The obligations in this + section do not apply to any claims or Losses relating to any actual or + alleged intellectual property infringement. In order to qualify, an + Indemnified Contributor must: a) promptly notify the Commercial + Contributor in writing of such claim, and b) allow the Commercial + Contributor to control, and cooperate with the Commercial Contributor + in, the defense and any related settlement negotiations. The + Indemnified Contributor may participate in any such claim at its own + expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible + for determining the appropriateness of using and distributing the + Program and assumes all risks associated with its exercise of rights + under this Agreement , including but not limited to the risks and costs + of program errors, compliance with applicable laws, damage to or loss + of data, programs or equipment, and unavailability or interruption of + operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity (including + a cross-claim or counterclaim in a lawsuit) alleging that the Program + itself (excluding combinations of the Program with other software or + hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it fails + to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of time + after becoming aware of such noncompliance. If all Recipient's rights + under this Agreement terminate, Recipient agrees to cease use and + distribution of the Program as soon as reasonably practicable. However, + Recipient's obligations under this Agreement and any licenses granted + by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a + distinguishing version number. The Program (including Contributions) + may always be distributed subject to the version of the Agreement under + which it was received. In addition, after a new version of the + Agreement is published, Contributor may elect to distribute the Program + (including its Contributions) under the new version. Except as + expressly stated in Sections 2(a) and 2(b) above, Recipient receives no + rights or licenses to the intellectual property of any Contributor + under this Agreement, whether expressly, by implication, estoppel or + otherwise. All rights in the Program not expressly granted under this + Agreement are reserved. + + This Agreement is governed by the laws of the State of New York and the + intellectual property laws of the United States of America. No party to + this Agreement will bring a legal action under this Agreement more than + one year after the cause of action arose. Each party waives its rights + to a jury trial in any resulting litigation. diff --git a/winery/README.md b/winery/README.md new file mode 100644 index 0000000..7d3a95e --- /dev/null +++ b/winery/README.md @@ -0,0 +1,184 @@ +# Winery +Winery is a Web-based environment to graphically model TOSCA topologies and plans managing these topologies. +It is an Eclipse project and thus support is available through its project page https://projects.eclipse.org/projects/soa.winery. +Winery is also part of the OpenTOSCA ecosystem where more information is available at http://www.opentosca.org. + +**The code and the linked libraries are NOT approved by Eclipse Legal. Dependencies are fetched from external mirrors and not from an Eclipse repository.** + +## Runtime Requirements +* Java 7 +* Servlet 3.0 capable container (e.g., Tomcat 7) + +## Development Information + +Winery uses maven and [bower] for fetching dependencies and building. +Bower has to be installed manually as described in the next section. + +## Install bower + +1. Install [nodejs]. Just use the latest version to get the latest node package manager (npm). +1. Run `npm install -g bower` +1. Ensure that `git` is in your path: Some javascript libraries are fetched via git. + + +## Make models available + +The models are versioned aside from the main project. +Go into each model directory (`org.eclipse.winery.model.csar.toscametafile`, `org.eclipse.winery.model.selfservice`, `org.eclipse.winery.model.tosca`) and do a `mvn install`. + + +## Making the wars +Run `mvn clean package`. +In case [bower] fails, try to investigate using `mvn package -X`. +You can start bower manually in `org.eclipse.winery.repository` and `org.eclipse.winery.topologymodeler` by issuing `bower install`. + +There are two WARs generated: + +* `org.eclipse.winery.repository/target/winery.war` and +* `org.eclipse.winery.topologymodeler/target/winery-topologymodeler.war` + +They can be deployed on a Tomcat runtime environment. + +## Branches +The `master` branch is always compiling and all tests should go through. +It contains the most recent improvements. +All other branches are real development branches and might event not compile. + +There are no explicit branches for stable versions as winery is currently in development-only mode. + +## Projects + +### Model projects +Each of these projects are versioned separately. + +* org.eclipse.winery.model.csar.toscametafile: model for TOSCA meta files contained in a CSAR +* org.eclipse.winery.model.selfservice: model for the self service portal +* org.eclipse.winery.model.tosca: model for TOCSA + +### Support projects +* org.eclipse.winery.highlevelrestapi: support library to REST calls. + +### Winery itself +Versioned together to ease development. + +* org.eclipse.winery.common: Used in repository and topology modeler +* org.eclipse.winery.generators.ia: Implementation Artifact Generator, used as component in the repository +* org.eclipse.winery.repository: the repository including a JSP-based UI +* org.eclipse.winery.repository.client: Java-client for the repository +* org.eclipse.winery.topologymodeler: Graph-based modeler for topology templates + +## Next steps +Winery currently is far from being a production ready modeling tool. +The next steps are: + +* UI design improvements + * Have Orion support `XML` as language. See also [Bug 421284][bug421284] +* Add more usability features to the topology modeler +* Remove non-required files from components/ directory to reduce the file size of the WAR file + * This has to be done by submitting patches to `bower.json` of the upstream libraries +* Develop a plugin-system for user-defined editors. For instance, a constraint has a type. If a type is known to Winery, it can present a specific plugin to edit the type content instead of a generic XML editor. +* Rework file storage. Currently, files are stored along with their definitions. A new storage should store all files in one place and use an SHA1 id to uniquely identify the file. Then, it does not make any difference if storing a WAR, an XSD, or an WSDL. +* Add a real DAO layer to enable querying the available TOSCA contents using SQL or similar query language + +Currently, `.jsp` files package HTML and JS. +We plan to use frameworks such as [TerrificJS] to provide a better modularity. +This follows Nicholas Zakas' "[Scalable JavaScript Application Architecture]". + +## Known issues +* XSD Type declarations are not directly supported +** Declared types are converted to imports during a CSAR Import +** Editing of XSDs is not possible +* **The XSD of OASIS TOSCA v1.0 has been modified** +** An Implementation Artifact may carry a `name` attribute +** The contents of properties of Boundary Definitions are processed in `lax` mode + +## Eclipse setup +This howto is based on [Eclipse Standard 4.3]. +First of all, generate a war to have all dependencies fetched by maven. + +### Required plugins +* JST Server Adapters Extensions +* Eclipse Java EE Developer Tools +* Eclipse Java Web Developer Tools +* [m2e-wtp]: Maven Integration for WTP +* [AnyEdit](http://andrei.gmxhome.de/anyedit/) for ensuring that tabs are always used +** Configure: Window -> Preferences -> General / Editors / AnyEdit Tools -> "Auto - Convert EXCLUSION file list" -> "Add filter" -> "*.java", "Convert...": 4 spaces for a tab + +### Optional plugins +* [Eclipse Code Recommenders](http://www.eclipse.org/recommenders/) +* [VJET JavaScript IDE](http://www.eclipse.org/proposals/webtools.vjet/) + +### Make Winery projects known to Eclipse +1. Import all projects + * Use "Existing Maven Projects". `mvn eclips:m2eclipse` currently does not enable "maven" in eclipse. +2. For each project: right click, –> Team –> Share Project –> Git –> Next –> check "Use or create repository in parent folder of project" –> Finish +3. At `org.eclipse.winery.repository` and ` org.eclipse.winery.topologymodeler`: + * Right click -> Properties -> JavaScript -> Include Path -> Source -> Expand folder -> Select "Excluded" -> "Edit..." + * Exclusion Patterns: Add multiple -> Select "3rd party" -> "OK" + * Exclusion Patterns: Add multiple -> Select "components" -> "OK" + * "Finish" -> "OK" + +### Setup Tomcat +1. Open servers window: Window -> Show View -> Other -> Server -> Servers +2. New server wizard... -> Apache -> Tomcat v7.0 Server -> Next -> Winery -> Add -> Finish +3. Rename the Server to "Apache Tomcat v7.0" + +Now you can see the Tomcat v7.0 Server at localhost [Stopped, Republish] in your server window. +Select it and click on the green play button in the window. + +Now winery can be viewed at http://localhost:8080/winery/ + +### Configure Winery (optional) +The repository location can be changed: +Copy `winery.properties` to `path-to-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\winery`. + +### Trouble shooting +* In case some JavaScript libraries cannot be found by the browser, execute `bower prune`, `bower install`, `bower update` in both `org.eclipse.winery.repository` and `org.eclipse.winery.topologymodeler`. +* See [README.md of the repository](org.eclipse.winery.repository/README.md) +* See [README.md of the topology modeler](org.eclipse.winery.topologymodeler/README.md) + +#### Libraries + +* Do NOT update to jQuery 2.1.0. When using with firefox, line 5571 in jquery.js fails: `divStyle is null`. That means `window.getComputedStyle( div, null );` returned null, too. +* Do NOT update to jsPlumb 1.5.5. The new connection type determination does not play well together with Winery's usage of jsPlumb. + +## Acknowledgements +The initial code contribution has been supported by the [Federal Ministry of Economics and Technology] as part of the [CloudCycle project] (01MD11023). + +## License +Copyright (c) 2012-2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + +## Literature + +### About TOSCA +* Binz, T., Breiter, G., Leymann, F., Spatzier, T.: Portable Cloud Services Using TOSCA. IEEE Internet Computing 16(03), 80--85 (May 2012). [DOI:10.1109/MIC.2012.43] +* Topology and Orchestration Specification for Cloud Applications Version 1.0. 25 November 2013. OASIS Standard. http://docs.oasis-open.org/tosca/TOSCA/v1.0/os/TOSCA-v1.0-os.html +* OASIS: Topology and Orchestration Specification for Cloud Applications (TOSCA) Primer Version 1.0 (2013) + +See http://www.opentosca.org/#publications for a list of publications in the OpenTOSCA ecosystem. + +### Programming +* Joshua Bloch. Effective Java, 2nd edition. Addison-Wesley + + [bug421284]: https://bugs.eclipse.org/bugs/show_bug.cgi?id=421284 + [bower]: https://github.com/bower/bower + [DOI:10.1109/MIC.2012.43]: http://dx.doi.org/10.1109/MIC.2012.43 + [nodejs]: http://nodejs.org/download/ + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html + [Eclipse Standard 4.3]: http://www.eclipse.org/downloads/ + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html + [Federal Ministry of Economics and Technology]: http://www.bmwi.de/EN/root.html + [CloudCycle project]: http://www.cloudcycle.org/en/ + [m2eclipse]: http://eclipse.org/m2e/ + [m2e-wtp]: http://eclipse.org/m2e-wtp/ + [Scalable JavaScript Application Architecture]: http://www.slideshare.net/nzakas/scalable-javascript-application-architecture-2012 + [TerrificJS]: http://terrifically.org/ diff --git a/winery/documentation/CodeHeaders.md b/winery/documentation/CodeHeaders.md new file mode 100644 index 0000000..533dfe4 --- /dev/null +++ b/winery/documentation/CodeHeaders.md @@ -0,0 +1,45 @@ +# About this file + +This file explains how to create and maintain copyright headers in source files. + +# Initial header + +``` +/*********************************************************************** + * Copyright (c) {DATE} {INITIAL COPYRIGHT OWNER} {OTHER COPYRIGHT OWNERS}. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at + * http://www.opensource.org/licenses/apache2.0.php. + * You may elect to redistribute this code under either of these licenses. + * Contributors: + * {INITIAL AUTHOR} - initial API and implementation + ************************************************************************* +``` + +## Templates +* Company: John Smith (University of Stuttgart) +* Student: John Smith +* Copyright (c) 2013 John Smith (University of Stuttgart). + +# Full information + +Full information is available at: http://www.eclipse.org/legal/copyrightandlicensenotice.php + +# License +Copyright (c) 2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + + + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html diff --git a/winery/documentation/HowToRelease.md b/winery/documentation/HowToRelease.md new file mode 100644 index 0000000..859cf3a --- /dev/null +++ b/winery/documentation/HowToRelease.md @@ -0,0 +1,26 @@ +# How to do a release + +As the maven release plugin does not yet support bower, the versions in `bower.json` have to be adapted manually. + +- remove `-SNAPSHOT` in `/org.eclipse.repository/bower.json` +- remove `-SNAPSHOT` in `/org.eclipse.winery.topologymodeler/bower.json` +- execute `mvn -B release:prepare` +- increase version number in /org.eclipse.repository/bower.json and add `-SNAPSHOT` +- increase version number in /org.eclipse.winery.topologymodeler/bower.json and add `-SNAPSHOT` +- execute `mvn release:perform` + +# License +Copyright (c) 2013-2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + + + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html diff --git a/winery/documentation/RepositoryLayout.md b/winery/documentation/RepositoryLayout.md new file mode 100644 index 0000000..5256f3b --- /dev/null +++ b/winery/documentation/RepositoryLayout.md @@ -0,0 +1,71 @@ +# Layout of the filebased repository + +## Typical layout + +Typically, all TOSCA components have the path `componenttype/ns/id`. + +## Directory `imports` + +This directory stores files belonging to a CSAR. +That means, when a definitions points to an external reference, the file has to be stored at the external location and not inside the repository + +### Directory layout + +`imports/<encoded importtype>/<encoded namespace>/<id>/` + +In case no namespace is specified, then `__NONE__` is used as namespace. +Handling of that is currently not supported. + +`id` is a randomly generated id reflecting a single imported file. + +Inside the directory, a `.tosca` is stored containing the import element only. +In future, this can be used to contain the extensibility attributes, which are currently unsupported. + +`location` points to +i) the local file or +ii) to some external definition (absolute URL!) + +Currently, ii is not implemented and the storage is used as mirror only to be able to +a) offer choice of known XML Schema definitions +b) generate a UI for known XML Schemas (current idea: use http://sourceforge.net/projects/xsd2gui/) + +Typically, all TOSCA components have the path `componenttype/ns/id`. +We add `imports` before to group the imports. +The chosen ordering allows to present all available imports for a given import type +by just querying the contents of `<encoded importtype>`. + +### Handling of the extensibility parts + +Handling of the extensible part of `tImport` is not supported. +A first idea is to store the Import XML Element as file in the respective directory. + +### Special treatment of XSD definitions + +#### Knowing the definitions for a QName + +Currently, all contained XSDs are queried for their defined local names and this set is aggregated. + +The following is an implementation idea: + +Each namespace may contain multiple definitions. +Therefore, each folder `<enocded namespace>` contains a file `import.properties`, +which provides a mapping of local names to id. +For instance, if `theElement`is defined in `myxmldefs.xsd` (being the human-readable id of the folder), +`index.properties` contains `theElement = myxmldefs.xsd`. +The local name is sufficient as the namespace is given by the parent directory. + +## License +Copyright (c) 2013-2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + + + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html diff --git a/winery/documentation/TOSCA specification/.gitignore b/winery/documentation/TOSCA specification/.gitignore new file mode 100644 index 0000000..664db10 --- /dev/null +++ b/winery/documentation/TOSCA specification/.gitignore @@ -0,0 +1,2 @@ +*.png +*.svg diff --git a/winery/documentation/TOSCA specification/TOSCA-v1.0-os-attributes.xlsx b/winery/documentation/TOSCA specification/TOSCA-v1.0-os-attributes.xlsx Binary files differnew file mode 100644 index 0000000..fb03f8c --- /dev/null +++ b/winery/documentation/TOSCA specification/TOSCA-v1.0-os-attributes.xlsx diff --git a/winery/documentation/TOSCA specification/TOSCA-v1.0-os-class-diagram.pdf b/winery/documentation/TOSCA specification/TOSCA-v1.0-os-class-diagram.pdf Binary files differnew file mode 100644 index 0000000..3ed41fc --- /dev/null +++ b/winery/documentation/TOSCA specification/TOSCA-v1.0-os-class-diagram.pdf diff --git a/winery/documentation/TOSCA specification/TOSCA-v1.0-os-class-diagram.plantuml b/winery/documentation/TOSCA specification/TOSCA-v1.0-os-class-diagram.plantuml new file mode 100644 index 0000000..d186078 --- /dev/null +++ b/winery/documentation/TOSCA specification/TOSCA-v1.0-os-class-diagram.plantuml @@ -0,0 +1,470 @@ +/*********************************************************************** + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at + * http://www.opensource.org/licenses/apache2.0.php. + * You may elect to redistribute this code under either of these licenses. + * Contributors: + * Oliver Kopp - initial implementation + ************************************************************************* + +This model describes the XSD of TOSCA-v1.0.xsd as released by TOSCA v1.0 cos01. +URL: http://docs.oasis-open.org/tosca/TOSCA/v1.0/os/schemas/TOSCA-v1.0.xsd +Specification: http://docs.oasis-open.org/tosca/TOSCA/v1.0/TOSCA-v1.0.html + +@startuml + +'skinparam monochrome true +'Chooses LightGray as background color +'We're better off with manual setting + +skinparam class { + BackgroundColor White + ArrowColor Black + BorderColor Black + LegendBackgroundColor White +} + +skinparam stereotypeCBackgroundColor LightGray + +skinparam noteBackgroundColor White +skinparam noteBorderColor Black + +'required for SVG +skinparam defaultFontName sans-serif + + +Title <size:33>TOSCA v1.0 as UML class diagram. This is not an official OASIS document. No warranty. (c) University of Stuttgart. Dual-licensed under EPL and ASLv2. Version 2014-01-29. + +legend right +== Note on the model +The model stays close to the XSD with following exceptions: +* Containers such as tTags are ignored: A class is then wired using a 1:n relation to the elements nested in the container +* Relations to TOSCA artifacts are encoded. +** E.g., a QName modelling a substitutable Node Type is modeled as reference to a Node Type +** *Ref elements are not modeled, the association is drawn directly +*** E.g., tCapabilityRef is not contained in the model +* xsd types are presented more relaxed. E.g., xsd:string becomes String + +== Conventions +* green: required (+ prefix) +* all others: optional +endlegend + + + +'OS line 19 +class tExtensibleElements { + documentation + contents of other namespaces +} + +'OS line 26 +tExtensibleElements <|-- tImport +class tImport { + anyURI namespace + anyURI location + +(anyURI) importType +} + +'OS line 42 +tExtensibleElements <|-- tDefinitions +class tDefinitions { + +ID id + String name + anyURI targetNamespace + List<Object> Types +} +tDefinitions *-- "*" tExtension +tDefinitions *-- "*" tImport + +'OS line 61 +tDefinitions *-- "*" tServiceTemplate +tDefinitions *-- "*" tNodeType +tDefinitions *-- "*" tNodeTypeImplementation +tDefinitions *-- "*" tRelationshipType +tDefinitions *-- "*" tRelationshipTypeImplementation +tDefinitions *-- "*" tCapabilityType +tDefinitions *-- "*" tArtifactType +tDefinitions *-- "*" tArtifactTemplate +tDefinitions *-- "*" tPolicyType +tDefinitions *-- "*" tPolicyTemplate + +'OS line 81 +tExtensibleElements <|-- tServiceTemplate +class tServiceTemplate { + +ID id + String name + anyURI targetNamespace +} +tServiceTemplate *-- "*" tTag +tServiceTemplate *-- "*" tBoundaryDefinitions +tServiceTemplate *-- tTopologyTemplate +tServiceTemplate *-- "*" tPlan +tServiceTemplate --> "0..1" tNodeType : substitutable + +'OS line 102 +class tTag { + +String name + +String value +} + +'OS line 106 +class tBoundaryDefinitions { + Properties +} +tBoundaryDefinitions *-- "*" tPropertyMapping +tBoundaryDefinitions *-- "*" tPropertyConstraint +tBoundaryDefinitions --> "*" tRequirement +tBoundaryDefinitions --> "*" tCapability +tBoundaryDefinitions *-- "*" tPolicy +tBoundaryDefinitions *-- "*" tExportedInterface + +'OS line 159 +class tPropertyMapping { + +String serviceTemplatePropertyRef + +String targetPropertyRef +} +tPropertyMapping --> "0..1" tNodeTemplate +tPropertyMapping --> "0..1" tRelationshipTemplate +tPropertyMapping --> "0..1" tRequirement +tPropertyMapping --> "0..1" tCapability + +'OS lines 164 to 171 define tRequiermentRef and tCapabilityRef +'to enable referencing requirements and capabilities +'We directly point to the elements + +'OS line 172 +abstract class tEntityType +tExtensibleElements <|-- tEntityType +class tEntityType { +' DerivedFrom is rendered as self-association in all subclasses +' DerivedFrom + PropertiesDefinition + +NCName name + Boolean abstract [no] + Boolean final [no] + anyURI targetNamespace +} +tEntityType *-- "*" tTag + +'OS line 196 +abstract class tEntityTemplate +tExtensibleElements <|-- tEntityTemplate +class tEntityTemplate { + Properties + +xs:ID id + +QName type +} +tEntityTemplate *-- "*" tPropertyConstraint + +'OS line 219 +tEntityTemplate <|-- tNodeTemplate +class tNodeTemplate #DDDDDD/EEEEEE { + String name + int minInstances [1] + int|unbounded maxInstances [1] +} +tNodeTemplate *-- "*" tRequirement +tNodeTemplate *-- "*" tCapability +tNodeTemplate *-- "*" tPolicy +tNodeTemplate *-- "*" tDeploymentArtifact +'due to the subclassing of tEntityTemplate +'There, the type attribute references the parent class +tNodeTemplate --> tNodeType : type + +'OS line 268 +tExtensibleElements <|-- tTopologyTemplate +class tTopologyTemplate +'no attributes exist +tTopologyTemplate *-- "*" tNodeTemplate +tTopologyTemplate *-- "*" tRelationshipTemplate + +'OS line 278 +tEntityType <|-- tRelationshipType +class tRelationshipType #DDDDDD/EEEEEE +'no attributes +'InstanceStates +tRelationshipType *-- "*" tTopologyElementInstanceState +'SourceInterfaces +tRelationshipType *-- "*" tInterface : SourceInterface +'TargetInterfaces +tRelationshipType *-- "*" tInterface : TargetInterface +'ValidSource +tRelationshipType --> "0..1" tNodeType : ValidSource +tRelationshipType --> "0..1" tRequirementType : ValidSource +'ValidTarget +tRelationshipType --> "0..1" tNodeType : ValidTarget +tRelationshipType --> "0..1" tCapabilityType : ValidTarget +'DerivedFrom +tRelationshipType --> "0..1" tRelationshipType : DerivedFrom + + +'OS line 311 +tExtensibleElements <|-- tRelationshipTypeImplementation +class tRelationshipTypeImplementation { + +NCName name + anyURI targetNamespace + Boolean abstract + Boolean final +} +tRelationshipTypeImplementation --> tRelationshipType +tRelationshipTypeImplementation *-- "*" tTag +tRelationshipTypeImplementation --> "0..1" tRelationshipTypeImplementation : DerivedFrom +tRelationshipTypeImplementation *-- "*" tRequiredContainerFeature +tRelationshipTypeImplementation *-- "*" tImplementationArtifact + +'OS line 332 +tEntityTemplate <|-- tRelationshipTemplate +class tRelationshipTemplate #DDDDDD/EEEEEE { + String name +} +'SourceElement +tRelationshipTemplate --> "0..1" tNodeTemplate : SourceElement +tRelationshipTemplate --> "0..1" tRequirement : SourceElement +'TargetElement +tRelationshipTemplate --> "0..1" tNodeTemplate : TargetElement +tRelationshipTemplate --> "0..1" tCapability : TargetElement +' +tRelationshipTemplate *-- "*" tRelationshipConstraint +'due to the subclassing of tEntityTemplate +tRelationshipTemplate --> tRelationshipType + +'OS line 349 +'not modeled as t, but directly nested in tRelationshipTemplate +'We model it as t to be consistent with the other definitions +class tRelationshipConstraint { + +anyURI constraintType +} + +'OS line 365 +tEntityType <|-- tNodeType +class tNodeType #DDDDDD/EEEEEE +'No new attributes +' +tNodeType *-- "*" tRequirementDefinition +tNodeType *-- "*" tCapabilityDefinition +tNodeType *-- "*" tTopologyElementInstanceState +tNodeType *-- "*" tInterface +'DerivedFrom +tNodeType --> "0..1" tNodeType : DerivedFrom + +'OS line 395 +tExtensibleElements <|-- tNodeTypeImplementation +class tNodeTypeImplementation { + +NCname name + anyURI targetNamespace + Boolean abstract + Boolean final +} +tNodeTypeImplementation --> tNodeType +tNodeTypeImplementation *-- "*" tTag +tNodeTypeImplementation --> "0..1" tNodeTypeImplementation : DerivedFrom +tNodeTypeImplementation *-- "*" tRequiredContainerFeature +tNodeTypeImplementation *-- "*" tDeploymentArtifact +tNodeTypeImplementation *-- "*" tImplementationArtifact + +'OS line 417 +tEntityType <|-- tRequirementType +class tRequirementType +tRequirementType --> "0..1" tCapabilityType : requiredCapabilityType +'DerivedFrom +tRequirementType --> "0..1" tRequirementType : DerivedFrom + +'OS line 424 +tExtensibleElements <|-- tRequirementDefinition +class tRequirementDefinition { + +String name + int lowerBound [1] + int|unbounded upperBound [1] +} +tRequirementDefinition *-- "*" tConstraint +tRequirementDefinition --> tRequirementType + +'OS line 458 +tEntityTemplate <|-- tRequirement +class tRequirement { + +String name +} +'"name" is also used to point to tRequirementDefinition +tRequirement --> tRequirementDefinition : name +'due to the subclassing of tEntityTemplate +tRequirement --> tRequirementType + +'OS line 465 +tEntityType <|-- tCapabilityType +'DerivedFrom +tCapabilityType --> "0..1" tCapabilityType : DerivedFrom + +'OS line 470 +tExtensibleElements <|-- tCapabilityDefinition +class tCapabilityDefinition { + +String name + int lowerBound [1] + int|unbounded upperBound [1] +} +tCapabilityDefinition *-- "*" tConstraint +tCapabilityDefinition --> tCapabilityType + +'OS line 504 +tEntityTemplate <|-- tCapability +class tCapability { + +String name +} +'"name" is also used to point to tCapabilityDefinition +tCapability --> tCapabilityDefinition : name +'due to the subclassing of tEntityTemplate +tCapability --> tCapabilityType + +'OS line 511 +tEntityType <|-- tArtifactType +tArtifactType --> "0..1" tArtifactType : DerivedFrom + +'OS line 516 +tEntityTemplate <|-- tArtifactTemplate +'PDF line 2607 +class tArtifactTemplate { + String name +} +tArtifactTemplate *-- "*" tArtifactReference +'due to the subclassing of tEntityTemplate +tArtifactTemplate --> tArtifactType + +'OS line 537 +tExtensibleElements <|-- tDeploymentArtifact +class tDeploymentArtifact { + +String Name +} +tDeploymentArtifact --> tArtifactType +tDeploymentArtifact --> "0..1" tArtifactTemplate + +'OS line 557 +tExtensibleElements <|-- tImplementationArtifact +class tImplementationArtifact { + anyURI interfaceName + String operationName +} +tImplementationArtifact --> tArtifactType +tImplementationArtifact --> "0..1" tArtifactTemplate + +'OS line 573 +tExtensibleElements <|-- tPlan +class tPlan { + +ID id + String name + +anyURI planType + +anyURI languageUsed + PlanModel | PlanModelReference +} +tPlan *-- "0..1" tCondition : Precondition +tPlan *-- "*" tParameter : InputParamter +tPlan *-- "*" tParameter : OutputParamter + +'OS line 614 +tEntityType <|-- tPolicyType +class tPolicyType { + anyURI policyLanguage +} +'AppliesTo/NodeTypeReference: CS02 line 631 +tPolicyType --> "*" tNodeType : tAppliesTo/NodeTypeReference +'DerivedFrom +tPolicyType --> "0..1" tPolicyType : DerivedFrom + +'OS line 624 +tEntityTemplate <|-- tPolicyTemplate +class tPolicyTemplate { + String name +} +'due to inheritance of tEntityTemplate +tPolicyTemplate --> tPolicyType + +'OS line 640 +tExtensibleElements <|-- tPolicy +class tPolicy { + String name +} +tPolicy --> tPolicyType +tPolicy --> "0..1" tPolicyTemplate + +'OS line 649 +class tConstraint { + +anyURI constraintType +} + +'OS line 655 +tConstraint <|-- tPropertyConstraint +class tPropertyConstraint { + +String property +} + +'OS line 671 +tExtensibleElements <|-- tExtension +class tExtension { + +anyURI namespace + Boolean mustUnderstand [yes] +} + +'OS line 679 +class tParameter { + +String name + +String type + Boolean required [yes] +} + +'OS line 684 +class tInterface { + +anyURI name 'NCName is a subset of anyURI +} +tInterface *-- tOperation + +'OS line 690 +class tExportedInterface { + +anyURI name +} +tExportedInterface --> "1..*" tExportedOperation + +'OS line 696 +tExtensibleElements <|-- tOperation +class tOperation { + +NCName name +} +tOperation *-- "*" tParameter : InputParameters +tOperation *-- "*" tParameter : OutputParamters + +'OS line 719 +class tExportedOperation { + +NCName name + +anyURI interfaceName + +NCName operationName +} +tExportedOperation --> "0..1" tNodeTemplate +tExportedOperation --> "0..1" tRelationshipTemplate +tExportedOperation --> "0..1" tPlan + + +'OS line 743 +class tCondition { + +anyURI expressionLanguage +} + +'OS line 751 +'tTopologyElementInstanceState does not exist directly, but to be consistent with the others, we introduce it +class tTopologyElementInstanceState { + anyURI state +} + +'OS line 758 +class tArtifactReference { + Include + Exclude + +anyURI reference +} + +'OS line 773 +class tRequiredContainerFeature { + +anyURI feature +} +@enduml diff --git a/winery/documentation/TOSCA specification/startplantuml.bat b/winery/documentation/TOSCA specification/startplantuml.bat new file mode 100644 index 0000000..9da178a --- /dev/null +++ b/winery/documentation/TOSCA specification/startplantuml.bat @@ -0,0 +1,20 @@ +:/*********************************************************************** +: * Copyright (c) 2013-2014 University of Stuttgart. +: * All rights reserved. This program and the accompanying materials +: * are made available under the terms of the Eclipse Public License v1.0 +: * and Apache License v2.0 which accompanies this distribution. +: * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html +: * and the Apache License v2.0 is available at +: * http://www.opensource.org/licenses/apache2.0.php. +: * You may elect to redistribute this code under either of these licenses. +: * Contributors: +: * Oliver Kopp - initial implementation +: ************************************************************************* + +@echo off +echo Generating SVG... +SET PLANTUML=C:\Users\Oliver\BTSync\plantuml.jar +java -jar %PLANTUML% -tsvg TOSCA-v1.0-os-class-diagram.plantuml +echo Generating PDF... +inkscape -z -D --file=TOSCA-v1.0-os-class-diagram.svg --export-pdf=TOSCA-v1.0-os-class-diagram.pdf +echo Done diff --git a/winery/eclipse-config/README.md b/winery/eclipse-config/README.md new file mode 100644 index 0000000..2a9afd7 --- /dev/null +++ b/winery/eclipse-config/README.md @@ -0,0 +1,24 @@ +# Howto + +Java -> Code Style -> Clean Up: cleanup.xml +Formatter -> formatter_settings.xml +Code Templates: codetemplates.xml + +Java -> Editor -> Templates: java_editor_templates.xml + +Save Actions: follow eclipse_save_actions*.png + +# License +Copyright (c) 2012-2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/winery/eclipse-config/cleanup.xml b/winery/eclipse-config/cleanup.xml new file mode 100644 index 0000000..3f17ea0 --- /dev/null +++ b/winery/eclipse-config/cleanup.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<profiles version="2"> +<profile kind="CleanUpProfile" name="IAAS" version="2"> +<setting id="cleanup.format_source_code" value="true"/> +<setting id="cleanup.add_missing_annotations" value="true"/> +<setting id="cleanup.use_this_for_non_static_method_access_only_if_necessary" value="false"/> +<setting id="cleanup.remove_unused_private_types" value="true"/> +<setting id="cleanup.qualify_static_member_accesses_through_instances_with_declaring_class" value="true"/> +<setting id="cleanup.qualify_static_method_accesses_with_declaring_class" value="true"/> +<setting id="cleanup.add_generated_serial_version_id" value="false"/> +<setting id="cleanup.make_variable_declarations_final" value="false"/> +<setting id="cleanup.add_missing_methods" value="false"/> +<setting id="cleanup.always_use_this_for_non_static_field_access" value="true"/> +<setting id="cleanup.remove_trailing_whitespaces_ignore_empty" value="false"/> +<setting id="cleanup.correct_indentation" value="true"/> +<setting id="cleanup.never_use_parentheses_in_expressions" value="false"/> +<setting id="cleanup.add_serial_version_id" value="false"/> +<setting id="cleanup.remove_unused_private_methods" value="true"/> +<setting id="cleanup.use_this_for_non_static_field_access" value="true"/> +<setting id="cleanup.use_blocks_only_for_return_and_throw" value="false"/> +<setting id="cleanup.remove_unused_private_members" value="false"/> +<setting id="cleanup.add_missing_override_annotations_interface_methods" value="false"/> +<setting id="cleanup.remove_trailing_whitespaces_all" value="true"/> +<setting id="cleanup.make_type_abstract_if_missing_method" value="false"/> +<setting id="cleanup.always_use_this_for_non_static_method_access" value="true"/> +<setting id="cleanup.remove_unnecessary_nls_tags" value="true"/> +<setting id="cleanup.format_source_code_changes_only" value="false"/> +<setting id="cleanup.qualify_static_field_accesses_with_declaring_class" value="true"/> +<setting id="cleanup.add_missing_nls_tags" value="false"/> +<setting id="cleanup.use_this_for_non_static_field_access_only_if_necessary" value="false"/> +<setting id="cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class" value="true"/> +<setting id="cleanup.remove_unnecessary_casts" value="true"/> +<setting id="cleanup.qualify_static_member_accesses_with_declaring_class" value="true"/> +<setting id="cleanup.use_parentheses_in_expressions" value="true"/> +<setting id="cleanup.remove_unused_private_fields" value="true"/> +<setting id="cleanup.make_parameters_final" value="false"/> +<setting id="cleanup.remove_trailing_whitespaces" value="false"/> +<setting id="cleanup.remove_unused_imports" value="true"/> +<setting id="cleanup.organize_imports" value="true"/> +<setting id="cleanup.sort_members" value="false"/> +<setting id="cleanup.remove_private_constructors" value="true"/> +<setting id="cleanup.convert_to_enhanced_for_loop" value="false"/> +<setting id="cleanup.always_use_blocks" value="true"/> +<setting id="cleanup.never_use_blocks" value="false"/> +<setting id="cleanup.always_use_parentheses_in_expressions" value="true"/> +<setting id="cleanup.use_this_for_non_static_method_access" value="true"/> +<setting id="cleanup.remove_unused_local_variables" value="false"/> +<setting id="cleanup.make_private_fields_final" value="true"/> +<setting id="cleanup.add_missing_deprecated_annotations" value="true"/> +<setting id="cleanup.add_default_serial_version_id" value="true"/> +<setting id="cleanup.sort_members_all" value="false"/> +<setting id="cleanup.use_blocks" value="true"/> +<setting id="cleanup.add_missing_override_annotations" value="true"/> +<setting id="cleanup.make_local_variable_final" value="true"/> +</profile> +</profiles> diff --git a/winery/eclipse-config/codetemplates.xml b/winery/eclipse-config/codetemplates.xml new file mode 100644 index 0000000..4420690 --- /dev/null +++ b/winery/eclipse-config/codetemplates.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><templates><template autoinsert="true" context="gettercomment_context" deleted="false" description="Comment for getter method" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name="gettercomment">/** + * @return the ${bare_field_name} + */</template><template autoinsert="true" context="settercomment_context" deleted="false" description="Comment for setter method" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.settercomment" name="settercomment">/** + * @param ${param} the ${bare_field_name} to set + */</template><template autoinsert="true" context="constructorcomment_context" deleted="false" description="Comment for created constructors" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name="constructorcomment">/** + * ${tags} + */</template><template autoinsert="true" context="filecomment_context" deleted="false" description="Comment for created Java files" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.filecomment" name="filecomment">/** + * + */</template><template autoinsert="false" context="typecomment_context" deleted="false" description="Comment for created types" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.typecomment" name="typecomment">/** + * ${tags} + */</template><template autoinsert="true" context="fieldcomment_context" deleted="false" description="Comment for fields" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name="fieldcomment">/** + * + */</template><template autoinsert="false" context="methodcomment_context" deleted="false" description="Comment for non-overriding methods" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name="methodcomment">/** + * ${tags} + * {@inheritDoc} + */</template><template autoinsert="true" context="overridecomment_context" deleted="false" description="Comment for overriding methods" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name="overridecomment">/* (non-Javadoc) + * ${see_to_overridden} + */</template><template autoinsert="true" context="delegatecomment_context" deleted="false" description="Comment for delegate methods" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name="delegatecomment">/** + * ${tags} + * ${see_to_target} + */</template><template autoinsert="true" context="newtype_context" deleted="false" description="Newly created files" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.newtype" name="newtype">${filecomment} +${package_declaration} + +${typecomment} +${type_declaration}</template><template autoinsert="true" context="classbody_context" deleted="false" description="Code in new class type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.classbody" name="classbody"> +</template><template autoinsert="true" context="interfacebody_context" deleted="false" description="Code in new interface type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name="interfacebody"> +</template><template autoinsert="true" context="enumbody_context" deleted="false" description="Code in new enum type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.enumbody" name="enumbody"> +</template><template autoinsert="true" context="annotationbody_context" deleted="false" description="Code in new annotation type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name="annotationbody"> +</template><template autoinsert="false" context="catchblock_context" deleted="false" description="Code in new catch blocks" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.catchblock" name="catchblock">// ${todo} Auto-generated catch block +logger.debug(${exception_var}.getMessage(), ${exception_var});</template><template autoinsert="false" context="methodbody_context" deleted="false" description="Code in created method stubs" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.methodbody" name="methodbody">// ${todo} Auto-generated method stub +throw new IllegalStateException("Not yet implemented.");</template><template autoinsert="true" context="constructorbody_context" deleted="false" description="Code in created constructor stubs" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name="constructorbody">${body_statement} +// ${todo} Auto-generated constructor stub</template><template autoinsert="true" context="getterbody_context" deleted="false" description="Code in created getters" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.getterbody" name="getterbody">return ${field};</template><template autoinsert="true" context="setterbody_context" deleted="false" description="Code in created setters" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.setterbody" name="setterbody">${field} = ${param};</template></templates>
\ No newline at end of file diff --git a/winery/eclipse-config/eclipse_save_actions.png b/winery/eclipse-config/eclipse_save_actions.png Binary files differnew file mode 100644 index 0000000..f1f5d32 --- /dev/null +++ b/winery/eclipse-config/eclipse_save_actions.png diff --git a/winery/eclipse-config/eclipse_save_actions_1_code_organizing.png b/winery/eclipse-config/eclipse_save_actions_1_code_organizing.png Binary files differnew file mode 100644 index 0000000..0edc3d6 --- /dev/null +++ b/winery/eclipse-config/eclipse_save_actions_1_code_organizing.png diff --git a/winery/eclipse-config/eclipse_save_actions_2_code_style.png b/winery/eclipse-config/eclipse_save_actions_2_code_style.png Binary files differnew file mode 100644 index 0000000..11a5ed5 --- /dev/null +++ b/winery/eclipse-config/eclipse_save_actions_2_code_style.png diff --git a/winery/eclipse-config/eclipse_save_actions_3_member_accesses.png b/winery/eclipse-config/eclipse_save_actions_3_member_accesses.png Binary files differnew file mode 100644 index 0000000..62525bb --- /dev/null +++ b/winery/eclipse-config/eclipse_save_actions_3_member_accesses.png diff --git a/winery/eclipse-config/eclipse_save_actions_4_missing_code.png b/winery/eclipse-config/eclipse_save_actions_4_missing_code.png Binary files differnew file mode 100644 index 0000000..6210a52 --- /dev/null +++ b/winery/eclipse-config/eclipse_save_actions_4_missing_code.png diff --git a/winery/eclipse-config/eclipse_save_actions_5_unnecessary_code.png b/winery/eclipse-config/eclipse_save_actions_5_unnecessary_code.png Binary files differnew file mode 100644 index 0000000..7680ee4 --- /dev/null +++ b/winery/eclipse-config/eclipse_save_actions_5_unnecessary_code.png diff --git a/winery/eclipse-config/formatter_settings.xml b/winery/eclipse-config/formatter_settings.xml new file mode 100644 index 0000000..9ddaa00 --- /dev/null +++ b/winery/eclipse-config/formatter_settings.xml @@ -0,0 +1,291 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<profiles version="12"> +<profile kind="CodeFormatterProfile" name="Eclipse [Winery]" version="12"> +<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/> +<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/> +<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/> +<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/> +<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/> +<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/> +<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/> +<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/> +</profile> +</profiles> diff --git a/winery/eclipse-config/java_editor_templates.xml b/winery/eclipse-config/java_editor_templates.xml new file mode 100644 index 0000000..970fcfc --- /dev/null +++ b/winery/eclipse-config/java_editor_templates.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><templates><template autoinsert="true" context="java" deleted="false" description="JAX RS: one getter and setter for a property" enabled="true" name="JAXRSgettersetter">@GET +@Path("${name}") +public String get${name}() { + return this.configuration.getString(Property.${name}); +} + +@PUT +@Path("${name}") +public Response put${name}(@FormParam(value="${name}") String ${name}) { + return BackendUtils.setProperty(this.configuration, Property.${name}, ${name}); +} +</template><template autoinsert="true" context="java" deleted="false" description="Method for returning a subresource" enabled="true" name="JAXRSsubresource"> @Path("{id}/") + public ${thing}Resource get${thing}Resource(@PathParam("id") String id) { + XMLid xmlId = new XMLid(id, true); + ${thing}Id resId = new ${thing}Id((${thing}sId) this.id, xmlId); + return new ${thing}Resource(resId); + } +</template><template autoinsert="true" context="java" deleted="false" description="SLF4Jlogger" enabled="true" name="logger"> private static final Logger logger = LoggerFactory.getLogger(${enclosing_type}.class); +</template><template autoinsert="true" context="java" deleted="false" description="SLF4Jlogger" enabled="true" name="logger"> private static final Logger logger = LoggerFactory.getLogger(${enclosing_type}.class); +</template></templates>
\ No newline at end of file diff --git a/winery/graphics/winery_fav_icon.pptx b/winery/graphics/winery_fav_icon.pptx Binary files differnew file mode 100644 index 0000000..2037857 --- /dev/null +++ b/winery/graphics/winery_fav_icon.pptx diff --git a/winery/notice.html b/winery/notice.html new file mode 100644 index 0000000..f19c483 --- /dev/null +++ b/winery/notice.html @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> +<title>Eclipse Foundation Software User Agreement</title> +</head> + +<body lang="EN-US"> +<h2>Eclipse Foundation Software User Agreement</h2> +<p>February 1, 2011</p> + +<h3>Usage Of Content</h3> + +<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS + (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND + CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE + OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR + NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND + CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> + +<h3>Applicable Licenses</h3> + +<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 + ("EPL"). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + For purposes of the EPL, "Program" will mean the Content.</p> + +<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code + repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> + +<ul> + <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li> + <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</li> + <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins + and/or Fragments associated with that Feature.</li> + <li>Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.</li> +</ul> + +<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and +Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module +including, but not limited to the following locations:</p> + +<ul> + <li>The top-level (root) directory</li> + <li>Plug-in and Fragment directories</li> + <li>Inside Plug-ins and Fragments packaged as JARs</li> + <li>Sub-directories of the directory named "src" of certain Plug-ins</li> + <li>Feature directories</li> +</ul> + +<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the +installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or +inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature. +Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in +that directory.</p> + +<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE +OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> + +<ul> + <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li> + <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li> + <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li> + <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li> + <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li> + <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li> +</ul> + +<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please +contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> + + +<h3>Use of Provisioning Technology</h3> + +<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse + Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or + other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to + install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a + href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> + ("Specification").</p> + +<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the + applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology + in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the + Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> + +<ol> + <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology + on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based + product.</li> + <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be + accessed and copied to the Target Machine.</li> + <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable + Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target + Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern + the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such + indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li> +</ol> + +<h3>Cryptography</h3> + +<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to + another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, + possession, or use, and re-export of encryption software, to see if this is permitted.</p> + +<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p> +</body> +</html> diff --git a/winery/org.eclipse.winery.common/.gitignore b/winery/org.eclipse.winery.common/.gitignore new file mode 100644 index 0000000..4cac871 --- /dev/null +++ b/winery/org.eclipse.winery.common/.gitignore @@ -0,0 +1,14 @@ +/.gradle +.classpath +.project +.settings/org.eclipse.core.resources.prefs +.settings/org.eclipse.jdt.core.prefs +.settings/org.eclipse.m2e.core.prefs +.settings/org.eclipse.wst.common.component +.settings/org.eclipse.wst.common.project.facet.core.xml +.settings/org.eclipse.wst.validation.prefs +/.sonar +/bin +/build +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.common/about.html b/winery/org.eclipse.winery.common/about.html new file mode 100644 index 0000000..4e770b7 --- /dev/null +++ b/winery/org.eclipse.winery.common/about.html @@ -0,0 +1,143 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<h4>Java Libraries</h4> + +<h5>Apache Commons IO – Version 2.4</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-io/">http://commons.apache.org/proper/commons-io/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang3 – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>JSP Standard Tag Library – Version 1.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://jstl.java.net/">https://jstl.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Logback Classic – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: jcl-over-slf4j – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.tosca – Version 0.1.20</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.common/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.common/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.common/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.common/about_files/CDDL-v1.1.txt b/winery/org.eclipse.winery.common/about_files/CDDL-v1.1.txt new file mode 100644 index 0000000..7cc8719 --- /dev/null +++ b/winery/org.eclipse.winery.common/about_files/CDDL-v1.1.txt @@ -0,0 +1,129 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL - Version 1.1) +1. Definitions. + + 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + + 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + + 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + + 1.4. “Executable” means the Covered Software in any form other than Source Code. + + 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + + 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + + 1.7. “License” means this document. + + 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + + 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + + 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + + 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.common/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.common/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.common/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.common/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.common/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.common/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.common/pom.xml b/winery/org.eclipse.winery.common/pom.xml new file mode 100644 index 0000000..048ff04 --- /dev/null +++ b/winery/org.eclipse.winery.common/pom.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Unger - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.winery</groupId> + <artifactId>winery</artifactId> + <version>0.1.37-SNAPSHOT</version> + </parent> + <artifactId>org.eclipse.winery.common</artifactId> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.tosca</artifactId> + <version>0.1.21-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.7.6</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>jstl</groupId> + <artifactId>jstl</artifactId> + <version>1.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/winery/org.eclipse.winery.common/sonar-project.properties b/winery/org.eclipse.winery.common/sonar-project.properties new file mode 100644 index 0000000..09b7e2f --- /dev/null +++ b/winery/org.eclipse.winery.common/sonar-project.properties @@ -0,0 +1,24 @@ +# required metadata +sonar.projectKey=org.eclipse.winery.common +sonar.projectName=org.eclipse.winery.common +sonar.projectVersion=0.1.2 + +# path to source directories (required) +sonar.sources=src/main/java + +# path to test source directories (optional) +#sonar.tests= + +# path to project binaries (optional), for example directory of Java bytecode +#sonar.binaries=binDir + +# optional comma-separated list of paths to libraries. Only path to JAR file and path to directory of classes are supported. +#sonar.libraries=org.eclipse.jgit-2.1.0.201209190230-r.jar + +# The value of the property must be the key of the language. +sonar.language=java + +# enforece Java 1.7 to enable analysis of diamon operator by PMD +sonar.java.source=1.7 + +sonar.sourceEncoding=UTF-8 diff --git a/winery/org.eclipse.winery.common/src/main/java/META-INF/MANIFEST.MF b/winery/org.eclipse.winery.common/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..254272e --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ModelUtilities.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ModelUtilities.java new file mode 100644 index 0000000..92d8ec9 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ModelUtilities.java @@ -0,0 +1,670 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common; + +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.constants.QNames; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate.Capabilities; +import org.eclipse.winery.model.tosca.TNodeTemplate.Requirements; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlans; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement; +import org.eclipse.winery.model.tosca.TRelationshipTemplate.TargetElement; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +public class ModelUtilities { + + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ModelUtilities.class); + + + /** + * This is a special method for Winery. Winery allows to define a property + * definition by specifying name/type values. Instead of parsing the + * extensible elements returned TDefinitions, this method is a convenience + * method to access this information + * + * @param t the entitytype to read the properties definition from + * @return a WinerysPropertiesDefinition object, which includes a map of + * name/type-pairs denoting the associated property definitions. A + * default element name and namespace is added if it is not defined + * in the underlying XML. null if no Winery specific KV properties + * are defined for the given entity type + */ + public static WinerysPropertiesDefinition getWinerysPropertiesDefinition(TEntityType et) { + // similar implementation as org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource.getListFromEntityType(TEntityType) + WinerysPropertiesDefinition res = null; + for (Object o : et.getAny()) { + if (o instanceof WinerysPropertiesDefinition) { + res = (WinerysPropertiesDefinition) o; + } + } + + if (res != null) { + // we put defaults if elementname and namespace have not been set + + if (res.getElementName() == null) { + res.setElementName("Properties"); + } + + if (res.getNamespace() == null) { + // we use the targetnamespace of the original element + String ns = et.getTargetNamespace(); + if (!ns.endsWith("/")) { + ns += "/"; + } + ns += "propertiesdefinition/winery"; + res.setNamespace(ns); + } + } + + return res; + } + + /** + * This is a special method for Winery. Winery allows to define a property + * by specifying name/value values. Instead of parsing the XML contained in + * TNodeType, this method is a convenience method to access this information + * + * The return type "Properties" is used because of the key/value properties. + * + * @param template the node template to get the associated properties + */ + public static Properties getPropertiesKV(TEntityTemplate template) { + Properties properties = new Properties(); + org.eclipse.winery.model.tosca.TEntityTemplate.Properties tprops = template.getProperties(); + if (tprops != null) { + // no checking for validity, just reading + Element el = (Element) tprops.getAny(); + if (el == null) { + // somehow invalid .tosca. We return empty properties instead of throwing a NPE + return properties; + } + NodeList childNodes = el.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node item = childNodes.item(i); + if (item instanceof Element) { + String key = item.getLocalName(); + String value = item.getTextContent(); + properties.put(key, value); + } + } + } + return properties; + } + + /** + * This is a special method for Winery. Winery allows to define a property + * by specifying name/value values. We convert the given Properties to XML. + * + * @param wpd the Winery's properties definition of the type of the given + * template (i.e., wpd = + * getWinerysPropertiesDefinition(template.getType())) + * @param template the node template to set the associated properties + */ + public static void setPropertiesKV(WinerysPropertiesDefinition wpd, TEntityTemplate template, Properties properties) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + ModelUtilities.logger.debug(e.getMessage(), e); + throw new IllegalStateException("Could not instantiate document builder", e); + } + Document doc = db.newDocument(); + + Element root = doc.createElementNS(wpd.getNamespace(), wpd.getElementName()); + doc.appendChild(root); + + // we produce the serialization in the same order the XSD would be generated (because of the usage of xsd:sequence) + for (PropertyDefinitionKV prop : wpd.getPropertyDefinitionKVList()) { + // we always write the element tag as the XSD forces that + Element element = doc.createElementNS(wpd.getNamespace(), prop.getKey()); + root.appendChild(element); + String value = properties.getProperty(prop.getKey()); + if (value != null) { + Text text = doc.createTextNode(value); + element.appendChild(text); + } + } + + org.eclipse.winery.model.tosca.TEntityTemplate.Properties tprops = new org.eclipse.winery.model.tosca.TEntityTemplate.Properties(); + tprops.setAny(doc.getDocumentElement()); + template.setProperties(tprops); + } + + /** + * Generates a XSD when Winery's K/V properties are used. This method is put + * here instead of WinerysPropertiesDefinitionResource to avoid generating + * the subresource + * + * public because of the usage by TOSCAEXportUtil + * + * @return empty Document, if Winery's Properties Definition is not fully + * filled (e.g., no wrapping element defined) + */ + public static Document getWinerysPropertiesDefinitionXSDAsDocument(WinerysPropertiesDefinition wpd) { + /* + * This is a quick hack: an XML schema container is created for each + * element. Smarter solution: create a hash from namespace to XML schema + * element and re-use that for each new element + * Drawback of "smarter" solution: not a single XSD file any more + */ + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + try { + docBuilder = docFactory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + ModelUtilities.logger.debug(e.getMessage(), e); + throw new IllegalStateException("Could not instantiate document builder", e); + } + Document doc = docBuilder.newDocument(); + + if (!ModelUtilities.allRequiredFieldsNonNull(wpd)) { + // wpd not fully filled -> valid XSD cannot be provided + // fallback: add comment and return "empty" document + Comment comment = doc.createComment("Required fields are missing in Winery's key/value properties definition."); + doc.appendChild(comment); + return doc; + } + + // create XSD schema container + Element schemaElement = doc.createElementNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "schema"); + doc.appendChild(schemaElement); + schemaElement.setAttribute("elementFormDefault", "qualified"); + schemaElement.setAttribute("attributeFormDefault", "unqualified"); + schemaElement.setAttribute("targetNamespace", wpd.getNamespace()); + + // create XSD element itself + Element el = doc.createElementNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "element"); + schemaElement.appendChild(el); + el.setAttribute("name", wpd.getElementName()); + Element el2 = doc.createElementNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "complexType"); + el.appendChild(el2); + el = el2; + el2 = doc.createElementNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "sequence"); + el.appendChild(el2); + el = el2; + + // currently, "xsd" is a hardcoded prefix in the type definition + el.setAttribute("xmlns:xsd", XMLConstants.W3C_XML_SCHEMA_NS_URI); + + for (PropertyDefinitionKV prop : wpd.getPropertyDefinitionKVList()) { + el2 = doc.createElementNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "element"); + el.appendChild(el2); + el2.setAttribute("name", prop.getKey()); + // prop.getType has the prefix included + el2.setAttribute("type", prop.getType()); + } + + return doc; + } + + /** + * Removes an existing Winery's Properties definition. If no such definition + * exists, the TEntityType is not modified + */ + public static void removeWinerysPropertiesDefinition(TEntityType et) { + for (Iterator<Object> iterator = et.getAny().iterator(); iterator.hasNext();) { + Object o = iterator.next(); + if (o instanceof WinerysPropertiesDefinition) { + iterator.remove(); + break; + } + } + } + + public static void replaceWinerysPropertiesDefinition(TEntityType et, WinerysPropertiesDefinition wpd) { + ModelUtilities.removeWinerysPropertiesDefinition(et); + et.getAny().add(wpd); + } + + public static String getBorderColor(TNodeType nt) { + String borderColor = nt.getOtherAttributes().get(QNames.QNAME_BORDER_COLOR); + if (borderColor == null) { + borderColor = Util.getColor(nt.getName()); + } + return borderColor; + } + + public static String getColor(TRelationshipType rt) { + String color = rt.getOtherAttributes().get(QNames.QNAME_COLOR); + if (color == null) { + color = Util.getColor(rt.getName()); + } + return color; + } + + /** + * Returns the Properties. If no properties exist, the element is created + * + * @return + */ + public static org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties getProperties(TBoundaryDefinitions defs) { + org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties properties = defs.getProperties(); + if (properties == null) { + properties = new org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties(); + defs.setProperties(properties); + } + return properties; + } + + /** + * Special method to get the name of an extensible element as the TOSCA + * specification does not have a separate super type for elements with a + * name + * + * {@link + * org.eclipse.winery.common.Util.instanceSupportsNameAttribute(Class<? + * extends TOSCAComponentId>)} is related + * + * @param e the extensible element offering a name attribute (besides an id + * attribute) + * @return the name of the extensible element + * @throws IllegalStateException if e does not offer the method "getName" + */ + public static String getName(TExtensibleElements e) { + Method method; + Object res; + try { + method = e.getClass().getMethod("getName"); + res = method.invoke(e); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + return (String) res; + } + + /** + * Returns the name of the given element. If the name does not exist or is + * empty, the id is returned + * + * {@see getName} + * + * @return the name if there is a name field, if not, the id is returned. In + * case there is a Name field, + */ + public static String getNameWithIdFallBack(TExtensibleElements ci) { + Method method; + String res = null; + try { + method = ci.getClass().getMethod("getName"); + res = (String) method.invoke(ci); + } catch (Exception e) { + } + if (StringUtils.isEmpty(res)) { + try { + method = ci.getClass().getMethod("getId"); + res = (String) method.invoke(ci); + } catch (Exception e2) { + throw new IllegalStateException(e2); + } + } + return res; + } + + /** + * Special method to set the name of an extensible element as the TOSCA + * specification does not have a separate super type for elements with a + * name + * + * @param e the extensible element offering a name attribute (besides an id + * attribute) + * @param name the new name + * @throws IllegalStateException if e does not offer the method "getName" + */ + public static void setName(TExtensibleElements e, String name) { + Method method; + try { + method = e.getClass().getMethod("setName", String.class); + method.invoke(e, name); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + + public static boolean allRequiredFieldsNonNull(WinerysPropertiesDefinition wpd) { + boolean valid = wpd.getNamespace() != null; + valid = valid && (wpd.getElementName() != null); + if (valid) { + PropertyDefinitionKVList propertyDefinitionKVList = wpd.getPropertyDefinitionKVList(); + valid = (propertyDefinitionKVList != null); + if (valid) { + for (PropertyDefinitionKV def : propertyDefinitionKVList) { + valid = valid && (def.getKey() != null); + valid = valid && (def.getType() != null); + } + } + } + return valid; + } + + /** + * @return null if no explicit left is set + */ + public static String getLeft(TNodeTemplate nodeTemplate) { + Map<QName, String> otherAttributes = nodeTemplate.getOtherAttributes(); + String left = otherAttributes.get(new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "x")); + return left; + } + + /** + * @return null if no explicit left is set + */ + public static String getTop(TNodeTemplate nodeTemplate) { + Map<QName, String> otherAttributes = nodeTemplate.getOtherAttributes(); + String top = otherAttributes.get(new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "y")); + return top; + } + + /** + * locates targetObjectRef inside a topology template + * + * @param topologyTemplate the topology template to search in + * @param targetObjectRef the object ref as String + * + * @return null if not found, otherwise the entity template in the topology + */ + public static TEntityTemplate findNodeTemplateOrRequirementOfNodeTemplateOrCapabilityOfNodeTemplateOrRelationshipTemplate(TTopologyTemplate topologyTemplate, String targetObjectRef) { + // We cannot use XMLs id pointing capabilities as we work on the Java model + // Other option: modify the stored XML directly. This is more error prune than walking through the whole topology + for (TEntityTemplate t : topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (t instanceof TNodeTemplate) { + if (t.getId().equals(targetObjectRef)) { + return t; + } + TNodeTemplate nt = (TNodeTemplate) t; + + Requirements requirements = nt.getRequirements(); + if (requirements != null) { + for (TRequirement req : requirements.getRequirement()) { + if (req.getId().equals(targetObjectRef)) { + return req; + } + } + } + + Capabilities capabilities = nt.getCapabilities(); + if (capabilities != null) { + for (TCapability cap : capabilities.getCapability()) { + if (cap.getId().equals(targetObjectRef)) { + return cap; + } + } + } + + } else { + assert (t instanceof TRelationshipTemplate); + if (t.getId().equals(targetObjectRef)) { + return t; + } + } + } + + // no return hit inside the loop: nothing was found + return null; + } + + /** + * Returns the id of the given element + * + * The TOSCA specification does NOT always put an id field. In the case of + * EntityTypes and EntityTypeImplementations, there is no id, but a name + * field + * + * This method abstracts from that fact. + */ + public static String getId(TExtensibleElements ci) { + Method method; + Object res; + try { + method = ci.getClass().getMethod("getId"); + res = method.invoke(ci); + } catch (Exception e) { + // If no "getId" method is there, we try "getName" + try { + method = ci.getClass().getMethod("getName"); + res = method.invoke(ci); + } catch (Exception e2) { + throw new IllegalStateException(e2); + } + } + return (String) res; + } + + /** + * Resolves a given id as requirement in the given ServiceTemplate + * + * @return null if not found + */ + public static TRequirement resolveRequirement(TServiceTemplate serviceTemplate, String reference) { + TRequirement resolved = null; + for (TEntityTemplate tmpl : serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) { + if (tmpl instanceof TNodeTemplate) { + TNodeTemplate n = (TNodeTemplate) tmpl; + Requirements requirements = n.getRequirements(); + if (requirements != null) { + for (TRequirement req : n.getRequirements().getRequirement()) { + if (req.getId().equals(reference)) { + resolved = req; + } + } + } + } + } + return resolved; + } + + public static TCapability resolveCapability(TServiceTemplate serviceTemplate, String reference) { + TCapability resolved = null; + for (TEntityTemplate tmpl : serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) { + if (tmpl instanceof TNodeTemplate) { + TNodeTemplate n = (TNodeTemplate) tmpl; + Capabilities capabilities = n.getCapabilities(); + if (capabilities != null) { + for (TCapability cap : n.getCapabilities().getCapability()) { + if (cap.getId().equals(reference)) { + resolved = cap; + } + } + } + } + } + return resolved; + } + + public static TNodeTemplate resolveNodeTemplate(TServiceTemplate serviceTemplate, String reference) { + TNodeTemplate resolved = null; + for (TEntityTemplate tmpl : serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) { + if (tmpl instanceof TNodeTemplate) { + TNodeTemplate n = (TNodeTemplate) tmpl; + if (n.getId().equals(reference)) { + resolved = n; + } + } + } + return resolved; + } + + public static TRelationshipTemplate resolveRelationshipTemplate(TServiceTemplate serviceTemplate, String reference) { + TRelationshipTemplate resolved = null; + for (TEntityTemplate tmpl : serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) { + if (tmpl instanceof TRelationshipTemplate) { + TRelationshipTemplate n = (TRelationshipTemplate) tmpl; + if (n.getId().equals(reference)) { + resolved = n; + } + } + } + return resolved; + } + + public static TPlan resolvePlan(TServiceTemplate serviceTemplate, String reference) { + TPlan resolved = null; + TPlans plans = serviceTemplate.getPlans(); + if (plans == null) { + return null; + } + for (TPlan p : plans.getPlan()) { + if (p.getId().equals(reference)) { + resolved = p; + } + } + return resolved; + } + + /** + * Sets the x coordinate of a {@link TNodeTemplate}. + * + * @param nodeTemplate + * the nodeTemplate to be altered + * @param coordinate + * the value of the coordinate to be set + * @return + * the altered {@link TNodeTemplate} + */ + public static TNodeTemplate setLeft(TNodeTemplate nodeTemplate, String coordinate) { + + Map<QName, String> otherNodeTemplateAttributes = nodeTemplate.getOtherAttributes(); + otherNodeTemplateAttributes.put(new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "x"), coordinate); + + return nodeTemplate; + } + + /** + * Sets the y coordinate of a {@link TNodeTemplate}. + * + * @param nodeTemplate + * the nodeTemplate to be altered + * @param coordinate + * the value of the coordinate to be set + * @return + * the altered {@link TNodeTemplate} + */ + public static TNodeTemplate setTop(TNodeTemplate nodeTemplate, String coordinate) { + + Map<QName, String> otherNodeTemplateAttributes = nodeTemplate.getOtherAttributes(); + otherNodeTemplateAttributes.put(new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "y"), coordinate); + + return nodeTemplate; + + } + + /** + * This method instantiates a {@link TNodeTemplate} for a given {@link TNodeType}. + * + * @param nodeType + * the {@link TNodeType} used for the {@link TNodeTemplate} instantiation. + * + * @return the instantiated {@link TNodeTemplate} + */ + public static TNodeTemplate instantiateNodeTemplate(TNodeType nodeType) { + + TNodeTemplate nodeTemplate = new TNodeTemplate(); + + nodeTemplate.setId(UUID.randomUUID().toString()); + nodeTemplate.setName(nodeType.getName()); + nodeTemplate.setType(new QName(nodeType.getTargetNamespace(), nodeType.getName())); + + // add capabilities to the NodeTemplate + if (nodeType.getCapabilityDefinitions() != null) { + for (TCapabilityDefinition cd : nodeType.getCapabilityDefinitions().getCapabilityDefinition()) { + TCapability capa = new TCapability(); + capa.setId(UUID.randomUUID().toString()); + capa.setName(cd.getCapabilityType().getLocalPart()); + capa.setType(new QName(cd.getCapabilityType().getNamespaceURI(), cd.getCapabilityType().getLocalPart())); + nodeTemplate.setCapabilities(new Capabilities()); + nodeTemplate.getCapabilities().getCapability().add(capa); + } + } + + // add requirements + if (nodeType.getRequirementDefinitions() != null && nodeType.getRequirementDefinitions().getRequirementDefinition() != null) { + Requirements requirementsNode = new Requirements(); + nodeTemplate.setRequirements(requirementsNode); + for (TRequirementDefinition definition : nodeType.getRequirementDefinitions().getRequirementDefinition()) { + TRequirement newRequirement = new TRequirement(); + newRequirement.setName(definition.getName()); + newRequirement.setId(definition.getName()); + newRequirement.setType(definition.getRequirementType()); + nodeTemplate.getRequirements().getRequirement().add(newRequirement); + } + } + + return nodeTemplate; + } + + /** + * This method instantiates a {@link TRelationshipTemplate} for a given {@link TRelationshipType}. + * + * @param nodeType + * the {@link TRelationshipType} used for the {@link TRelationshipTemplate} instantiation. + * @param sourceNodeTemplate + * the source {@link TNodeTemplate} of the connection + * @param targetNodeTemplate + * the target {@link TNodeTemplate} of the connection + * + * @return the instantiated {@link TRelationshipTemplate} + */ + public static TRelationshipTemplate instantiateRelationshipTemplate(TRelationshipType relationshipType, TNodeTemplate sourceNodeTemplate, TNodeTemplate targetNodeTemplate) { + + TRelationshipTemplate relationshipTemplate = new TRelationshipTemplate(); + relationshipTemplate.setId(UUID.randomUUID().toString()); + relationshipTemplate.setName(relationshipType.getName()); + relationshipTemplate.setType(new QName(relationshipType.getTargetNamespace(), relationshipType.getName())); + + // connect the NodeTemplates + SourceElement source = new SourceElement(); + source.setRef(sourceNodeTemplate); + relationshipTemplate.setSourceElement(source); + TargetElement target = new TargetElement(); + target.setRef(targetNodeTemplate); + relationshipTemplate.setTargetElement(target); + + return relationshipTemplate; + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/RepositoryFileReference.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/RepositoryFileReference.java new file mode 100644 index 0000000..68fb22f --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/RepositoryFileReference.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common; + +import org.eclipse.winery.common.ids.GenericId; + +/** + * Holds a reference to a file "object" stored in the repository + * + * Directories are NOT supported as we would have to reflect parent + * relationships there, too. + * + * One has to create TOSCAelementId-objects for directories (e.g., scc-data) + */ +public class RepositoryFileReference implements Comparable<RepositoryFileReference> { + + protected final GenericId parent; + protected final String fileName; + + + /** + * @param parent the id of the toscaElement the file is nested in + * @param fileName the file name. <em>Must not</em> contain any illegal + * characters. java.nio.Path cannot be used as Path is tied to a + * FileSystem + */ + public RepositoryFileReference(GenericId parent, String fileName) { + if (parent == null) { + throw new IllegalArgumentException("Parent must not be null."); + } + if (fileName == null) { + throw new IllegalArgumentException("Filename must not be null."); + } + this.parent = parent; + this.fileName = fileName; + } + + public GenericId getParent() { + return this.parent; + } + + public String getFileName() { + return this.fileName; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RepositoryFileReference) { + RepositoryFileReference otherRef = (RepositoryFileReference) obj; + return (otherRef.fileName.equals(this.fileName)) && (otherRef.getParent().equals(this.getParent())); + } else { + return false; + } + } + + @Override + public int hashCode() { + return this.getParent().hashCode() ^ this.getFileName().hashCode(); + } + + @Override + public int compareTo(RepositoryFileReference o) { + int res; + res = this.parent.compareTo(o.parent); + if (res == 0) { + res = this.fileName.compareTo(o.fileName); + } + return res; + } + + @Override + public String toString() { + return this.getParent().toString() + "/" + this.getFileName(); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/StringEncodedAndDecoded.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/StringEncodedAndDecoded.java new file mode 100644 index 0000000..cac7a44 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/StringEncodedAndDecoded.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common; + + + +/** + * Meta class to handle things, where a String (URI, NCName, ...) may be + * URLencoded + */ +public class StringEncodedAndDecoded implements Comparable<StringEncodedAndDecoded> { + + private String decoded = null; + private String encoded = null; + + + /** + * @param uri the URI to store + * @param URLencoded true iff the given URI is URLencoded + */ + public StringEncodedAndDecoded(String uri, boolean URLencoded) { + if (URLencoded) { + this.encoded = uri; + } else { + this.decoded = uri; + } + } + + public String getDecoded() { + if (this.decoded == null) { + this.decoded = Util.URLdecode(this.encoded); + } + return this.decoded; + } + + public String getEncoded() { + if (this.encoded == null) { + this.encoded = Util.URLencode(this.decoded); + } + return this.encoded; + } + + @Override + public int hashCode() { + return this.getDecoded().hashCode(); + } + + /** + * @return the URL path fragment to be used in an URL + */ + public String getPathFragment() { + return this.getEncoded(); + } + + @Override + public String toString() { + return this.getDecoded(); + } + + @Override + public int compareTo(StringEncodedAndDecoded o) { + return this.getDecoded().compareTo(o.getDecoded()); + } + + /** + * Compares with the given object <br /> + * Equality checking is made based on the decoded String + */ + @Override + public boolean equals(Object o) { + if (o instanceof String) { + return this.getDecoded().equals(o); + } else if (o instanceof StringEncodedAndDecoded) { + return ((StringEncodedAndDecoded) o).getDecoded().equals(this.getDecoded()); + } else { + return false; + } + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/TOSCADocumentBuilderFactory.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/TOSCADocumentBuilderFactory.java new file mode 100644 index 0000000..74a0e26 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/TOSCADocumentBuilderFactory.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common; + +import java.net.URL; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +/** + * Class to produce DocumentBuilders with a pre-loaded TOSCA XSD. + * + * In a separate class as TOSCA XSD loading takes a few seconds + */ +public class TOSCADocumentBuilderFactory { + + private static final Logger logger = LoggerFactory.getLogger(TOSCADocumentBuilderFactory.class); + + public static final TOSCADocumentBuilderFactory INSTANCE = new TOSCADocumentBuilderFactory(); + private final DocumentBuilderFactory factory; + + + public TOSCADocumentBuilderFactory() { + this.factory = DocumentBuilderFactory.newInstance(); + + this.factory.setNamespaceAware(true); + + // we do not need DTD validation + this.factory.setValidating(false); + + // we do XSD validation + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema; + URL resource = this.getClass().getResource("/TOSCA-v1.0.xsd"); + try { + // takes a few seconds to load + schema = schemaFactory.newSchema(resource); + this.factory.setSchema(schema); + } catch (SAXException e) { + // TODO: load xml.xsd in offline mode + TOSCADocumentBuilderFactory.logger.error("Schema could not be initalized", e); + TOSCADocumentBuilderFactory.logger.debug("We continue nevertheless to enable offline usage"); + } + } + + public DocumentBuilder getTOSCADocumentBuilder() { + DocumentBuilder db; + try { + db = this.factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new IllegalStateException("document builder could not be initalized", e); + } + return db; + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/Util.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/Util.java new file mode 100644 index 0000000..702bf41 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/Util.java @@ -0,0 +1,603 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common; + +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.List; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchema; +import javax.xml.namespace.QName; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.lang3.StringUtils; +import org.apache.taglibs.standard.functions.Functions; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.EntityTemplateId; +import org.eclipse.winery.common.ids.definitions.EntityTypeId; +import org.eclipse.winery.common.ids.definitions.EntityTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +public class Util { + + private static final Logger logger = LoggerFactory.getLogger(Util.class); + + public static final String FORBIDDEN_CHARACTER_REPLACEMENT = "_"; + + + public static String URLdecode(String s) { + try { + return URLDecoder.decode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(); + } + } + + public static String URLencode(String s) { + try { + return URLEncoder.encode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(); + } + } + + public static String DoubleURLencode(String s) { + return Util.URLencode(Util.URLencode(s)); + } + + /** + * Encodes the namespace and the localname of the given qname, separated by + * "/" + * + * @return <double encoded namespace>"/"<double encoded localname> + */ + public static String DoubleURLencode(QName qname) { + String ns = Util.DoubleURLencode(qname.getNamespaceURI()); + String localName = Util.DoubleURLencode(qname.getLocalPart()); + return ns + "/" + localName; + } + + public static boolean isRelativeURI(String uri) { + URI u; + try { + u = new URI(uri); + } catch (URISyntaxException e) { + Util.logger.debug(e.getMessage(), e); + // fallback + return false; + } + return !u.isAbsolute(); + } + + /** + * @param c the element directly nested below a definitions element in XML + */ + public static String getURLpathFragmentForCollection(Class<? extends TExtensibleElements> c) { + String res = c.getName().toLowerCase(); + int lastDot = res.lastIndexOf('.'); + // classname is something like <package>.T<type>. We are only interested + // in "<type>". Therefore "+2" from the dot onwards + res = res.substring(lastDot + 2); + res = res + "s"; + return res; + } + + public static String getEverythingBetweenTheLastDotAndBeforeId(Class<? extends GenericId> cls) { + String res = cls.getName(); + // Everything between the last "." and before "Id" is the Type + int dotIndex = res.lastIndexOf('.'); + assert (dotIndex >= 0); + return res.substring(dotIndex + 1, res.length() - "Id".length()); + } + + public static String getTypeForElementId(Class<? extends TOSCAElementId> idClass) { + return Util.getEverythingBetweenTheLastDotAndBeforeId(idClass); + } + + /** + * @return Singular type name for the given id. E.g., "ServiceTemplateId" + * gets "ServiceTemplate" + */ + public static String getTypeForComponentId(Class<? extends TOSCAComponentId> idClass) { + return Util.getEverythingBetweenTheLastDotAndBeforeId(idClass); + } + + /** + * Returns the root path fragment for the given + * AbstractComponentIntanceResource + * + * With trailing slash + * + * @return [ComponentName]s/ + */ + public static String getRootPathFragment(Class<? extends TOSCAComponentId> idClass) { + // quick handling of imports special case + // in the package naming, all other component instances have a this intermediate location, but not in the URLs + // The package handling is in {@link org.eclipse.winery.repository.Utils.getIntermediateLocationStringForType(String, String)} + String res; + if (GenericImportId.class.isAssignableFrom(idClass)) { + // this fires if idClass is a sub class from ImportCollectionId + // special treatment for imports + res = "imports/"; + if (XSDImportId.class.isAssignableFrom(idClass)) { + res = res + "http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema/"; + } else { + throw new IllegalStateException("Not possible to determine local storage for generic imports class"); + } + // we have the complete root path fragment + return res; + } else { + res = ""; + } + res = res + Util.getTypeForComponentId(idClass); + res = res.toLowerCase(); + res = res + "s"; + res = res + "/"; + return res; + } + + /** + * Just calls @link{qname2href} + * + * Introduced because of JSP error + * "The method qname2href(String, Class<? extends TExtensibleElements>, QName) in the type Util is not applicable for the arguments (String, Class<TNodeType>, QName, String)" + */ + public static String qname2hrefWithName(String repositoryUrl, Class<? extends TExtensibleElements> element, QName qname, String name) { + return Util.qname2href(repositoryUrl, element, qname, name); + } + + /** + * + * @param repositoryUrl the URL to the repository + * @param element the element directly nested below a definitions element in + * XML + * @param qname the QName of the element + * @param name (optional) if not null, the name to display as text in the + * reference. Default: localName of the QName + * @return an <code>a</code> HTML element pointing to the given id + */ + public static String qname2href(String repositoryUrl, Class<? extends TExtensibleElements> element, QName qname, String name) { + if (StringUtils.isEmpty(repositoryUrl)) { + throw new IllegalArgumentException("Repository URL must not be empty."); + } + if (element == null) { + throw new IllegalArgumentException("Element class must not be null."); + } + if (qname == null) { + return "(none)"; + } + + String absoluteURL = repositoryUrl + "/" + Util.getURLpathFragmentForCollection(element) + "/" + Util.DoubleURLencode(qname.getNamespaceURI()) + "/" + Util.DoubleURLencode(qname.getLocalPart()); + + if (name == null) { + // fallback if no name is given + name = qname.getLocalPart(); + } + // sanitize name + name = Functions.escapeXml(name); + + String res = "<a target=\"_blank\" data-qname=\"" + qname + "\" href=\"" + absoluteURL + "\">" + name + "</a>"; + return res; + } + + /** + * + * @param repositoryUrl the URL to the repository + * @param element the element directly nested below a definitions element in + * XML + * @param qname the QName of the element + * @return an <code>a</code> HTML element pointing to the given id + */ + public static String qname2href(String repositoryUrl, Class<? extends TExtensibleElements> element, QName qname) { + return Util.qname2href(repositoryUrl, element, qname, null); + } + + /** + * Returns a visual rendering of minInstances + * + * @param minInstances the value to render + */ + public static String renderMinInstances(Integer minInstances) { + if ((minInstances == null) || (minInstances == 1)) { + // == null: default value: display nothing -- *never* happens: + // the function *always* returns 1 even, if no explicit value is set. Therefore, we also display "" if the default value 1 is set + return ""; + } else { + return Integer.toString(minInstances); + } + } + + /** + * Returns a visual rendering of maxInstances + * + * @param maxInstances the value to render + */ + public static String renderMaxInstances(String maxInstances) { + if ((maxInstances == null) || (maxInstances.equals("1"))) { + // default value display nothing + // "1" is returned even if no explicit value has been set. + return ""; + } else if (maxInstances.equals("unbounded")) { + return "∞"; + } else { + // maxInstance is a plain integer + // return as is + return maxInstances; + } + } + + /** + * @return the local name of a Class representing a TOSCA element + */ + private static String getLocalName(@SuppressWarnings("rawtypes") Class clazz) { + String localName = clazz.getName(); + // a class defined within another class is written as superclass$class. E.g., EntityTemplate$Properties + // We use the real class name + int pos = localName.lastIndexOf('$'); + if (pos == -1) { + pos = localName.lastIndexOf('.'); + } + localName = localName.substring(pos + 1); + if (localName.equals("TDocumentation")) { + // special case for documentation: the local name starts with a lower case letter + localName = "documentation"; + } else if (localName.startsWith("T")) { + localName = localName.substring(1); + } + return localName; + } + + public static <T extends Object> JAXBElement<T> getJAXBElement(Class<T> clazz, T obj) { + String namespace = null; + XmlRootElement xmlRootElement = clazz.getAnnotation(XmlRootElement.class); + if (xmlRootElement != null) { + namespace = xmlRootElement.namespace(); + if ("##default".equals(namespace)) { + XmlSchema xmlSchema = clazz.getPackage().getAnnotation(XmlSchema.class); + if (xmlSchema != null) { + namespace = xmlSchema.namespace(); + } else { + // trigger default handling + namespace = null; + } + } + } + if (namespace == null) { + // fallback non-specified namespaces + namespace = org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE; + } + String localName = Util.getLocalName(clazz); + QName qname = new QName(namespace, localName); + JAXBElement<T> rootElement = new JAXBElement<T>(qname, clazz, obj); + return rootElement; + } + + /** + * Method similar to {@link + * org.eclipse.winery.repository.Utils.getXMLAsString(Class, Object)}. + * + * Differences: + * <ul> + * <li>XML processing instruction is not included in the header</li> + * <li>JAXBcontext is created at each call</li> + * </ul> + */ + public static <T extends Object> String getXMLAsString(Class<T> clazz, T obj) throws Exception { + // copied from Utils java, but we create an own JAXBcontext here + // JAXBSupport cannot be used as this relies on a MockElement, which we do not want to factor out to winery.common + + JAXBContext context; + try { + // For winery classes, eventually the package+jaxb.index method could be better. See http://stackoverflow.com/a/3628525/873282 + // @formatter:off + context = JAXBContext.newInstance( + TEntityType.class); + // @formatter:on + } catch (JAXBException e) { + throw new IllegalStateException(e); + } + + JAXBElement<T> rootElement = Util.getJAXBElement(clazz, obj); + Marshaller m = context.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + m.setProperty(Marshaller.JAXB_FRAGMENT, true); + // m.setProperty("com.sun.xml.bind.namespacePrefixMapper", JAXBSupport.prefixMapper); + + StringWriter w = new StringWriter(); + try { + m.marshal(rootElement, w); + } catch (JAXBException e) { + throw new IllegalStateException(e); + } + String res = w.toString(); + return res; + } + + public static String getXMLAsString(Element el) { + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer t; + try { + t = tf.newTransformer(); + } catch (TransformerConfigurationException e) { + throw new IllegalStateException("Could not instantiate Transformer", e); + } + t.setOutputProperty(OutputKeys.INDENT, "yes"); + Source source = new DOMSource(el); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + Result target = new StreamResult(os); + try { + t.transform(source, target); + } catch (TransformerException e) { + Util.logger.debug(e.getMessage(), e); + throw new IllegalStateException("Could not transform dom node to string", e); + } + return os.toString(); + } + + /** + * Determines whether the instance belonging to the given id supports the + * "name" attribute. This cannot be done using the super class as the TOSCA + * specification treats that differently in the case of EntityTemplates + * + * NOTE: The respective subclasses of AbstractComponentInstanceResource have + * to implement {@link org.eclipse.winery.repository.resources.IHasName} + * + * @param id the id to test + * @return true if the TOSCA model class belonging to the given id supports + * the method "getName()" in addition to "getId()" + */ + public static boolean instanceSupportsNameAttribute(Class<? extends TOSCAComponentId> idClass) { + if (ServiceTemplateId.class.isAssignableFrom(idClass)) { + return true; + } else if ((EntityTypeId.class.isAssignableFrom(idClass)) || (EntityTypeImplementationId.class.isAssignableFrom(idClass))) { + // name is available, but no id attribute + return false; + } else if (GenericImportId.class.isAssignableFrom(idClass)) { + return false; + } else { + assert (EntityTemplateId.class.isAssignableFrom(idClass)); + if (ArtifactTemplateId.class.isAssignableFrom(idClass)) { + return true; + } else if (PolicyTemplateId.class.isAssignableFrom(idClass)) { + return true; + } else { + throw new IllegalStateException("Unimplemented branch to determine if getName() exists"); + } + } + } + + public static String getLastURIPart(String loc) { + int posSlash = loc.lastIndexOf('/'); + String fileName = loc.substring(posSlash + 1); + return fileName; + } + + /** + * Determines a color belonging to the given name + */ + public static String getColor(String name) { + int hash = name.hashCode(); + // trim to 3*8=24 bits + hash = hash & 0xFFFFFF; + // check if color is more than #F0F0F0, i.e., too light + if (((hash & 0xF00000) >= 0xF00000) && (((hash & 0x00F000) >= 0x00F000) && ((hash & 0x0000F0) >= 0x0000F0))) { + // set one high bit to zero for each channel. That makes the overall color darker + hash = hash & 0xEFEFEF; + } + String colorStr = String.format("#%06x", hash); + return colorStr; + } + + /** + * Determines the name of the CSS class used for relationshipTypes at + * nodeTemplateRenderer.tag + */ + public static String makeCSSName(String namespace, String localName) { + // according to http://stackoverflow.com/a/79022/873282 everything is allowed + // However, {namespace}id does NOT work + String res = namespace + "_" + localName; + res = res.replaceAll("[^\\w\\d_]", "_"); + return res; + } + + /** + * @see {@link org.eclipse.winery.common.Util.makeCSSName(String, String)} + */ + public static String makeCSSName(QName qname) { + return Util.makeCSSName(qname.getNamespaceURI(), qname.getLocalPart()); + } + + public static SortedMap<String, SortedSet<String>> convertQNameListToNamespaceToLocalNameList(List<QName> list) { + SortedMap<String, SortedSet<String>> res = new TreeMap<>(); + for (QName qname : list) { + SortedSet<String> localNameSet = res.get(qname.getNamespaceURI()); + if (localNameSet == null) { + localNameSet = new TreeSet<>(); + res.put(qname.getNamespaceURI(), localNameSet); + } + localNameSet.add(qname.getLocalPart()); + } + return res; + } + + public static String namespaceToJavaPackage(String namespace) { + URI uri; + try { + uri = new URI(namespace); + } catch (URISyntaxException e) { + Util.logger.debug(e.getMessage(), e); + return "uri.invalid"; + } + StringBuilder sb = new StringBuilder(); + + String host = uri.getHost(); + if (host != null) { + Util.addReversed(sb, host, "\\."); + } + + String path = uri.getPath(); + if (!path.equals("")) { + if (path.startsWith("/")) { + // remove first slash + path = path.substring(1); + } + + // and then handle the string + Util.addAsIs(sb, path, "/"); + } + + // remove the final dot + sb.replace(sb.length() - 1, sb.length(), ""); + + return Util.cleanName(sb.toString()); + } + + private static String cleanName(String s) { + // TODO: Integrate with other name cleaning functions. "." should not be replaced as it is used as separator in the java package name + // @formatter:off + return s.replace(":", Util.FORBIDDEN_CHARACTER_REPLACEMENT) + .replace("/", Util.FORBIDDEN_CHARACTER_REPLACEMENT) + .replace(" ", Util.FORBIDDEN_CHARACTER_REPLACEMENT) + .replace("-", Util.FORBIDDEN_CHARACTER_REPLACEMENT); + // @formatter:on + } + + + /* + * Valid chars: See + * <ul> + * <li>http://www.w3.org/TR/REC-xml-names/#NT-NCName</li> + * <li>http://www.w3.org/TR/REC-xml/#NT-Name</li> + * </ul> + */ + // NameCharRange \u10000-\ueffff is not supported by Java + private static final String NCNameStartChar_RegExp = "[A-Z_a-z\u00c0-\u00d6\u00d8\u00f6\u00f8\u02ff\u0370\u037d\u037f-\u1fff\u200c-\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]"; + private static final String NCNameChar_RegExp = Util.NCNameStartChar_RegExp + "|[-\\.0-9\u00B7\u0300-\u036F\u203F-\u2040]"; + private static final Pattern NCNameStartChar_Pattern = Pattern.compile(Util.NCNameStartChar_RegExp); + private static final Pattern NCNameChar_RegExp_Pattern = Pattern.compile(Util.NCNameChar_RegExp); + + + /** + * Removes all non-NCName characters from the given string and returns the + * result + * + * This function should be consistent with + * org.eclipse.winery.common.Util.cleanName(String) + * + * TODO: This method seems to be equal to {@link + * org.eclipse.winery.repository.Utils.createXMLidAsString(String)}. These + * methods should be merged. + * + */ + public static String makeNCName(String text) { + if (StringUtils.isEmpty(text)) { + return text; + } + + StringBuffer res = new StringBuffer(); + + // handle start + String start = text.substring(0, 1); + Matcher m = Util.NCNameStartChar_Pattern.matcher(start); + if (m.matches()) { + res.append(start); + } else { + // not a valid character + res.append("_"); + } + + // handle remaining characters; + for (int i = 1; i < text.length(); i++) { + String s = text.substring(i, i + 1); + m = Util.NCNameChar_RegExp_Pattern.matcher(s); + if (m.matches()) { + res.append(s); + } else { + // not a valid character + res.append("_"); + } + } + + return res.toString(); + } + + private static void addAsIs(StringBuilder sb, String s, String separator) { + if (s.isEmpty()) { + return; + } + String[] split = s.split(separator); + for (int i = 0; i < split.length; i++) { + sb.append(split[i]); + sb.append("."); + } + } + + private static void addReversed(StringBuilder sb, String s, String separator) { + String[] split = s.split(separator); + for (int i = split.length - 1; i >= 0; i--) { + sb.append(split[i]); + sb.append("."); + } + } + + /** + * Bridge to client.getType(). Just calls client getType(), used by + * functions.tld. + * + * We suppress compiler warnings as JSP 2.0 do not offer support for + * generics, but we're using JSP 2.0... + * + * @param client the repository client to use + * @param qname the QName to resolve + * @param clazz the class the QName is describing + * @return {@inheritDoc} + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static org.eclipse.winery.model.tosca.TEntityType getType(org.eclipse.winery.common.interfaces.IWineryRepository client, javax.xml.namespace.QName qname, java.lang.Class clazz) { + return client.getType(qname, clazz); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/beans/NamespaceIdOptionalName.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/beans/NamespaceIdOptionalName.java new file mode 100644 index 0000000..872cb04 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/beans/NamespaceIdOptionalName.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.beans; + +/** + * Bean containing + * <ul> + * <li>namespace</li> + * <li>id</li> + * <li>name</li> + * </ul> + * The name field is optional + */ +public class NamespaceIdOptionalName { + + private String namespace; + private String id; + private String name = null; + + + public NamespaceIdOptionalName() { + + } + + public String getNamespace() { + return this.namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/Defaults.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/Defaults.java new file mode 100644 index 0000000..a3e1368 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/Defaults.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.constants; + +public class Defaults { + + public static final String DEFAULT_RT_HOVER_COLOR = "black"; + + // files are in src/main/webapp/images/relationshiptype + // convention: below the prefix, then the filename is either ...Left.png or ...Right.png + public static final String DEFAULT_RT_ARROWHEAD_SOURCE = "none"; + public static final String DEFAULT_RT_ARROWHEAD_TARGET = "PlainArrow"; + + public static final String DEFAULT_RT_DASH = "plain"; + public static final String DEFAULT_RT_LINEWIDTH = "1"; +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/MimeTypes.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/MimeTypes.java new file mode 100644 index 0000000..f79593c --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/MimeTypes.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.constants; + +/** + * See also {@link org.eclipse.winery.repository.backend.constants.MediaTypes} + */ +public class MimeTypes { + + public static final String MIMETYPE_TOSCA_DEFINITIONS = "application/vnd.oasis.tosca.definitions"; + + // text/xsd is NOT used for XSD as text/xml is rendered correctly in browsers + public static final String MIMETYPE_XSD = "text/xml"; + + public static final String MIMETYPE_ZIP = "application/zip"; + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/Namespaces.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/Namespaces.java new file mode 100644 index 0000000..897aa69 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/Namespaces.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.constants; + +/** + * Defines namespace constants not available in Java7's XMLConstants + */ +public class Namespaces { + + public static final String TOSCA_NAMESPACE = "http://docs.oasis-open.org/tosca/ns/2011/12"; + public static final String TOSCA_WINERY_EXTENSIONS_NAMESPACE = "http://www.opentosca.org/winery/extensions/tosca/2013/02/12"; + + // XML Schema namespace is defined at Java7's XMLConstants.W3C_XML_SCHEMA_NS_URI + + public static final String URI_BPMN20_MODEL = "http://www.omg.org/spec/BPMN/20100524/MODEL"; + public static final String URI_BPMN4TOSCA_20 = "http://www.opentosca.org/bpmn4tosca"; + public static final String URI_BPEL20_ABSTRACT = "http://docs.oasis-open.org/wsbpel/2.0/process/abstract"; + public static final String URI_BPEL20_EXECUTABLE = "http://docs.oasis-open.org/wsbpel/2.0/process/executable"; +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/QNames.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/QNames.java new file mode 100644 index 0000000..dcc5de0 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/constants/QNames.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.constants; + +import javax.xml.namespace.QName; + +public class QNames { + + public static final QName QNAME_BORDER_COLOR = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "bordercolor"); + public static final QName QNAME_COLOR = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "color"); + + // Boolean flag to indicate that the import is generated via the Winery Properties Defintion + public static final QName QNAME_WINERYS_PROPERTIES_DEFINITION_ATTRIBUTE = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "wpd"); +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/GenericId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/GenericId.java new file mode 100644 index 0000000..756137e --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/GenericId.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids; + +/** + * Superclass for all IDs appearing in Winery. These are: + * <ul> + * <li>All IDs of elements directly nested in a Definitions element</li> + * <li>Subelements of those</li> + * </ul> + * + * We assume that TOSCAcomponentId is always the root node of nested IDs + * + */ +public abstract class GenericId implements Comparable<GenericId> { + + private final XMLId xmlId; + + + protected GenericId(XMLId xmlId) { + this.xmlId = xmlId; + } + + /** + * @return null if (this instanceof TOSCAcomponentId). In that case, the + * element is already the root element + */ + public abstract GenericId getParent(); + + /** + * @return the XML id of this thing + */ + public XMLId getXmlId() { + return this.xmlId; + } + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); + + @Override + public String toString() { + return this.getClass().toString() + " / " + this.getXmlId().toString(); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/IdNames.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/IdNames.java new file mode 100644 index 0000000..fb1af16 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/IdNames.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids; + +/** + * The names of ids, used to set XMLids for collections of things + */ +public class IdNames { + + public static final String DEPLOYMENTARTIFACTS = "deploymentartifacts"; + public static final String INSTANCESTATES = "instancestates"; + public static final String INTERFACES = "interfaces"; // used at node type + public static final String INPUTPARAMETERS = "inputParameters"; + public static final String IMPLEMENTATIONARTIFACTS = "implementationartifacts"; + public static final String NODETEMPLATES = "nodetemplates"; + public static final String OUTPUTPARAMETERS = "outputParameters"; + public static final String PROPERTIES = "properties"; + public static final String RELATIONSHIPTEMPLATES = "relationshiptemplates"; + public static final String SOURCEINTERFACES = "sourceinterfaces"; + public static final String TARGETINTERFACES = "targetinterfaces"; + public static final String TOPOLOGYTEMPATE = "topologytemplate"; +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/IdUtil.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/IdUtil.java new file mode 100644 index 0000000..90970f1 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/IdUtil.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; + +/** + * Helper methods for Winery's Id system + */ +public class IdUtil { + + /** + * Returns the namespace where the given Id is nested in. As the id is not a + * TOSCAComponentId, it cannot be directly asked for its parent. Merely, the + * parent has to be asked for its namespace. The parent, in turn, if it is + * no TOSCAComponentId has to ask his parent. + * + * @param id the id refering to an element, where the namespace has to be + * checked for + * @return the namespace of the element denoted by id + */ + public static Namespace getNamespace(GenericId id) { + if (id instanceof TOSCAComponentId) { + return ((TOSCAComponentId) id).getNamespace(); + } else { + return IdUtil.getNamespace(id.getParent()); + } + } + + /** + * Executes the real conversion to a path fragment + * + * @param id the id to transform to a path + * @param doubleEncode true if each sub fragment should be double encoded, + * false if it should be encoded only once + * @return + */ + private static String getPathFragment(final GenericId id, final boolean doubleEncode) { + String toInsert; + if (id instanceof TOSCAComponentId) { + // @return "[ComponentName]s/{namespace}/{id}/" + TOSCAComponentId tId = (TOSCAComponentId) id; + String res = Util.getRootPathFragment(tId.getClass()); + toInsert = tId.getNamespace().getEncoded(); + if (doubleEncode) { + toInsert = Util.URLencode(toInsert); + } + res = res + toInsert + "/"; + toInsert = tId.getXmlId().getEncoded(); + if (doubleEncode) { + toInsert = Util.URLencode(toInsert); + } + res = res + toInsert + "/"; + return res; + } else if (id instanceof TOSCAElementId) { + toInsert = id.getXmlId().getEncoded(); + if (doubleEncode) { + toInsert = Util.URLencode(toInsert); + } + return IdUtil.getPathFragment(id.getParent()) + toInsert + "/"; + } else { + throw new IllegalStateException("Unknown subclass of GenericId " + id.getClass()); + } + } + + /** + * Returns the fragment of the path belonging to the id + * + * For instance, an Id of type ServiceTemplateId has + * <code>servicetemplates/{encoded ns}/{encoded name}/</code> + * + * @param id the element to return the path fragment for + * @return the path fragment. This is <em>not</em> intended to be used + * inside a URL + */ + public static String getPathFragment(GenericId id) { + return IdUtil.getPathFragment(id, false); + } + + /** + * Returns the fragment of the URL path belonging to the id + * + * For instance, an Id of type ServiceTemplateId has + * <code>servicetemplates/{double encoded ns}/{double encoded name}/</encode> + * + * @param id the element to return the path fragment for + * @return the path fragment to be used inside an URL + */ + public static String getURLPathFragment(GenericId id) { + return IdUtil.getPathFragment(id, true); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/Namespace.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/Namespace.java new file mode 100644 index 0000000..a848c14 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/Namespace.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.StringEncodedAndDecoded; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Namespace extends StringEncodedAndDecoded { + + private static final Logger logger = LoggerFactory.getLogger(Namespace.class); + + + public Namespace(String uri, boolean URLencoded) { + super(uri, URLencoded); + if (StringUtils.isEmpty(uri)) { + Namespace.logger.error("Empty URI has been passed to Namespace constructor."); + // throw new IllegalArgumentException("uri must not be empty or null."); + } + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/XMLId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/XMLId.java new file mode 100644 index 0000000..67bfb9f --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/XMLId.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids; + +import org.eclipse.winery.common.StringEncodedAndDecoded; + +/** + * Handles an ID given in the XML + * + * We need to have this class as IDs are also passed at URIs at requests. To + * ease handling, we use StringEncodedAndDecoded + * + * There is no check for valid XMLids (AKA allowed NCname characters). This is + * OK as, for instance, properties make use of this fact and store the name as + * ID + */ +public class XMLId extends StringEncodedAndDecoded { + + public XMLId(String id, boolean URLencoded) { + super(id, URLencoded); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ArtifactTemplateId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ArtifactTemplateId.java new file mode 100644 index 0000000..d74c986 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ArtifactTemplateId.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public class ArtifactTemplateId extends EntityTemplateId { + + public ArtifactTemplateId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public ArtifactTemplateId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public ArtifactTemplateId(QName qname) { + super(qname); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ArtifactTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ArtifactTypeId.java new file mode 100644 index 0000000..80de6a9 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ArtifactTypeId.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public class ArtifactTypeId extends EntityTypeId { + + public ArtifactTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public ArtifactTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public ArtifactTypeId(QName qname) { + this(new Namespace(qname.getNamespaceURI(), false), new XMLId(qname.getLocalPart(), false)); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/CapabilityTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/CapabilityTypeId.java new file mode 100644 index 0000000..18268c9 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/CapabilityTypeId.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class CapabilityTypeId extends EntityTypeId { + + public CapabilityTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public CapabilityTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public CapabilityTypeId(QName qname) { + super(qname); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTemplateId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTemplateId.java new file mode 100644 index 0000000..16995b2 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTemplateId.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; + +/** + * ArtifactTemplates, PolicyTemplates, and ServiceTemplates are + * <em>directly nested</em> in a Definitions element. RelationshipTemplates and + * NodeTemplates are not. When approaching an EntityTemplateId, it is a thing + * directly nested in a Definitions element. + * + * The others have {@link TOSCAElementId} as parent + */ +public abstract class EntityTemplateId extends TOSCAComponentId { + + public EntityTemplateId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public EntityTemplateId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public EntityTemplateId(QName qname) { + super(qname); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTypeId.java new file mode 100644 index 0000000..6378baf --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTypeId.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public abstract class EntityTypeId extends TOSCAComponentId { + + public EntityTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public EntityTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public EntityTypeId(QName type) { + super(type); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTypeImplementationId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTypeImplementationId.java new file mode 100644 index 0000000..cc10800 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/EntityTypeImplementationId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public abstract class EntityTypeImplementationId extends TOSCAComponentId { + + public EntityTypeImplementationId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public EntityTypeImplementationId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/NodeTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/NodeTypeId.java new file mode 100644 index 0000000..d1410c0 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/NodeTypeId.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class NodeTypeId extends TopologyGraphElementEntityTypeId { + + public NodeTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public NodeTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public NodeTypeId(QName type) { + super(type); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/NodeTypeImplementationId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/NodeTypeImplementationId.java new file mode 100644 index 0000000..48ab36a --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/NodeTypeImplementationId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class NodeTypeImplementationId extends EntityTypeImplementationId { + + public NodeTypeImplementationId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public NodeTypeImplementationId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/PolicyTemplateId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/PolicyTemplateId.java new file mode 100644 index 0000000..ff9e4b8 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/PolicyTemplateId.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class PolicyTemplateId extends EntityTemplateId { + + public PolicyTemplateId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public PolicyTemplateId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public PolicyTemplateId(QName qname) { + super(qname); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/PolicyTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/PolicyTypeId.java new file mode 100644 index 0000000..48d4a4c --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/PolicyTypeId.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class PolicyTypeId extends EntityTypeId { + + public PolicyTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public PolicyTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public PolicyTypeId(QName qname) { + super(qname); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RelationshipTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RelationshipTypeId.java new file mode 100644 index 0000000..1648b09 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RelationshipTypeId.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class RelationshipTypeId extends TopologyGraphElementEntityTypeId { + + public RelationshipTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public RelationshipTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + public RelationshipTypeId(QName qname) { + super(qname); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RelationshipTypeImplementationId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RelationshipTypeImplementationId.java new file mode 100644 index 0000000..61c0238 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RelationshipTypeImplementationId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class RelationshipTypeImplementationId extends EntityTypeImplementationId { + + public RelationshipTypeImplementationId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public RelationshipTypeImplementationId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RequirementTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RequirementTypeId.java new file mode 100644 index 0000000..4b01833 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/RequirementTypeId.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class RequirementTypeId extends EntityTypeId { + + public RequirementTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public RequirementTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public RequirementTypeId(QName qname) { + super(qname); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ServiceTemplateId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ServiceTemplateId.java new file mode 100644 index 0000000..7001a49 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/ServiceTemplateId.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +public final class ServiceTemplateId extends EntityTemplateId { + + public ServiceTemplateId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public ServiceTemplateId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public ServiceTemplateId(QName qname) { + super(qname); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/TOSCAComponentId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/TOSCAComponentId.java new file mode 100644 index 0000000..e9ce856 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/TOSCAComponentId.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +/** + * Identifies a TOSCA component. Each component is required to be identified + * subclasses this class + * + * A TOSCAcomponentId has a namespace and an id within that namespace. In XML, + * the ID might be serialized as NCName (in the case of EntityTypes and + * EntityTemplates) and as xs:id (in the case of EntityTypeImplementations) + * + * Components are elements, which may appear directly nested in TDefinitions: + * <ul> + * <li>ServiceTemplates,</li> + * <li>EntityTypes,</li + * <li>EntityTypeImplementations,</li> + * <li>EntityTemplates</li> + * </ul> + */ +public abstract class TOSCAComponentId extends GenericId { + + private final Namespace namespace; + + + public TOSCAComponentId(Namespace namespace, XMLId xmlId) { + super(xmlId); + this.namespace = namespace; + } + + /** + * Creates a new id based on strings. This constructor is required for + * {@link AbstractComponentsResource} + * + * @param ns the namespace to be used + * @param id the id to be used + * @param URLencoded true: both Strings are URLencoded, false: both Strings + * are not URLencoded + */ + public TOSCAComponentId(String ns, String id, boolean URLencoded) { + this(new Namespace(ns, URLencoded), new XMLId(id, URLencoded)); + } + + public TOSCAComponentId(QName qname) { + this(qname.getNamespaceURI(), qname.getLocalPart(), false); + } + + public QName getQName() { + QName qname = new QName(this.getNamespace().getDecoded(), this.getXmlId().getDecoded()); + return qname; + } + + public Namespace getNamespace() { + return this.namespace; + } + + @Override + public int hashCode() { + return this.namespace.hashCode() ^ this.getXmlId().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TOSCAComponentId)) { + return false; + } else { + TOSCAComponentId other = (TOSCAComponentId) obj; + return this.getXmlId().equals(other.getXmlId()) && this.namespace.equals(other.namespace); + } + } + + @Override + public String toString() { + QName qn = this.getQName(); + return this.getClass().toString() + " / " + qn.toString(); + } + + @Override + public GenericId getParent() { + return null; + } + + @Override + public int compareTo(GenericId o1) { + if (o1 instanceof TOSCAComponentId) { + TOSCAComponentId o = (TOSCAComponentId) o1; + int res = this.getXmlId().compareTo(o.getXmlId()); + if (res == 0) { + res = this.getNamespace().compareTo(o.getNamespace()); + } + return res; + } else { + // comparing TOSCAcomponentIDs with non-TOSCAcomponentIDs is not + // possible + throw new IllegalStateException(); + } + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/TopologyGraphElementEntityTypeId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/TopologyGraphElementEntityTypeId.java new file mode 100644 index 0000000..9eceb42 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/TopologyGraphElementEntityTypeId.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +/** + * An instance of this class is either a NodeTypeId or a RelationShipTypeId + */ +public abstract class TopologyGraphElementEntityTypeId extends EntityTypeId { + + public TopologyGraphElementEntityTypeId(Namespace namespace, XMLId xmlId) { + super(namespace, xmlId); + } + + public TopologyGraphElementEntityTypeId(String ns, String id, boolean URLencoded) { + super(ns, id, URLencoded); + } + + public TopologyGraphElementEntityTypeId(QName type) { + super(type); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/imports/GenericImportId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/imports/GenericImportId.java new file mode 100644 index 0000000..3b81236 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/imports/GenericImportId.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions.imports; + +import org.apache.commons.io.FilenameUtils; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; + +/** + * class for import ids (not used for definitions) + * + * // Convention: id of import is filename without extension + */ +public class GenericImportId extends TOSCAComponentId { + + private final String type; + + + /** + * @param type the importType (e.g., MimeTypes.MIMETYPE_XSD) + */ + public GenericImportId(Namespace namespace, XMLId xmlId, String type) { + super(namespace, xmlId); + this.type = type; + } + + public GenericImportId(String ns, String id, boolean encoded, String type) { + super(ns, id, encoded); + this.type = type; + } + + /** + * Generates an ImportId based on an TImport object The import has to be an + * import created by winery. This method uses the convention that the id is + * derived from the location + * + * @param i the TImport element to derive an id from + */ + public GenericImportId(TImport i) { + this(i.getNamespace(), GenericImportId.getId(i), false, i.getImportType()); + } + + private static String getId(TImport i) { + String fileName = Util.getLastURIPart(i.getLocation()); + String id = FilenameUtils.removeExtension(fileName); + return id; + } + + public String getType() { + return this.type; + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/imports/XSDImportId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/imports/XSDImportId.java new file mode 100644 index 0000000..940e8d3 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/imports/XSDImportId.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.definitions.imports; + +import javax.xml.XMLConstants; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; + +/** + * Models an import of type XML Schema Definition + * + * Required for a special treatment in {@link + * org.eclipse.winery.repository.Utils. + * getAllXSDefinitionsForTypeAheadSelection(short)} + */ +public class XSDImportId extends GenericImportId { + + public XSDImportId(String ns, String id, boolean encoded) { + super(ns, id, encoded, XMLConstants.W3C_XML_SCHEMA_NS_URI); + } + + public XSDImportId(Namespace ns, XMLId id) { + super(ns, id, XMLConstants.W3C_XML_SCHEMA_NS_URI); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/package-info.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/package-info.java new file mode 100644 index 0000000..ac34b49 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/definitions/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * This package contains ids for all components, which are directly nested in a + * definitions element. See CSPRD01, Section 4.1 + */ +package org.eclipse.winery.common.ids.definitions; + diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/PlanId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/PlanId.java new file mode 100644 index 0000000..49c2c2a --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/PlanId.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.elements; + +import org.eclipse.winery.common.ids.XMLId; + +public class PlanId extends TOSCAElementId { + + public PlanId(PlansId parent, XMLId xmlId) { + super(parent, xmlId); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/PlansId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/PlansId.java new file mode 100644 index 0000000..bd703dd --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/PlansId.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.elements; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; + +/** + * Pseudo-Id for plans nested in one service template + * + * results in the path "plans/" + */ +public class PlansId extends TOSCAElementId { + + public PlansId(ServiceTemplateId parent) { + super(parent, new XMLId("plans", true)); + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/TOSCAElementId.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/TOSCAElementId.java new file mode 100644 index 0000000..139a567 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/TOSCAElementId.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.ids.elements; + +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.XMLId; + +/** + * Models an ID of a TOSCA element, which is NOT a TOSCAcomponentId + * + * It has a parent and an xmlId + */ +public abstract class TOSCAElementId extends GenericId { + + private final GenericId parent; + + + public TOSCAElementId(GenericId parent, XMLId xmlId) { + super(xmlId); + this.parent = parent; + } + + @Override + public GenericId getParent() { + return this.parent; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TOSCAElementId) { + TOSCAElementId otherId = (TOSCAElementId) obj; + // the XML id has to be equal and the parents have to be equal + return (otherId.getXmlId().equals(this.getXmlId())) && (otherId.getParent().equals(this.getParent())); + } else { + return false; + } + } + + @Override + public int compareTo(GenericId o1) { + if (o1 instanceof TOSCAElementId) { + TOSCAElementId o = (TOSCAElementId) o1; + if (this.getParent().equals(o.getParent())) { + return this.getXmlId().compareTo(o.getXmlId()); + } else { + return this.getParent().compareTo(o.getParent()); + } + } else { + // comparing TOSCAcomponentIDs with non-TOSCAcomponentIDs is not + // possible + throw new IllegalStateException(); + } + } + + @Override + public int hashCode() { + return this.getParent().hashCode() ^ this.getXmlId().hashCode(); + } + + @Override + public String toString() { + String res; + res = this.getClass().toString() + " / " + this.getXmlId().getDecoded(); + res += "\n"; + res += "parent: " + this.getParent().toString(); + return res; + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/package-info.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/package-info.java new file mode 100644 index 0000000..0fd2942 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/ids/elements/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * This package contains ids for all TOSCA element, which are <b>NOT</b> + * directly nested in a definitions element. + */ +package org.eclipse.winery.common.ids.elements; + diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/IWineryRepository.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/IWineryRepository.java new file mode 100644 index 0000000..5cfe754 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/IWineryRepository.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.interfaces; + +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.TDefinitions; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; + +/** + * This interface is used by the repository client to get access to the + * repository. + * + * This interface should be removed and the client should be able to use + * "IWineryRepositoryCommon" only. + */ +public interface IWineryRepository extends IWineryRepositoryCommon { + + /** + * Returns all namespaces used by all known TOSCA components and namespaces + * where a prefix is defined for + * + * String is used as return type as Java's QName also uses String as + * parameter to denote a namespace + */ + public SortedSet<String> getNamespaces(); + + /** + * Returns a list of the QNames of all available types. Types can be node + * types, service templates, artifact types, artifact templates. + * + * This method obsoletes methods like "getQNameListOfAllArtifactTypes": One + * just has to call getQNameListOfAllTypes(TArtifactType.class) + * + * @return List of QNames of all types + */ + <T extends TEntityType> List<QName> getQNameListOfAllTypes(Class<T> type); + + /** + * Get the TEntityType belonging to the given QName + * + * @return null if there is no data on the server + */ + <T extends TEntityType> T getType(QName qname, Class<T> type); + + /** + * Queries the repository for instances of the given type. Returns pairs of + * QNames and names. The names are added as some component instances do + * carry a name. + * + * If the component instance does not carry an explicit name, the localName + * of the QName is used as name. + * + * @param type the type to get all instances of + * @return a collection of QName/name pairs + */ + Collection<QNameWithName> getListOfAllInstances(Class<? extends TOSCAComponentId> type); + + /** + * Returns the associated name for the given id. + * + * Since not all TOSCA entities have names, this method may only be used for + * entities supporting names. If it is used for entities not having a name, + * null is returned. + * + * @param id references the entity to query for a name + * @return the name or null if no name is available + */ + String getName(GenericId id); + + /** + * Returns a list of all available types. Types can be node types, service + * templates, artifact types. Note that artifact templates are + * TEntityTemplates and thus cannot be retrieved by this method. + * + * This method obsoletes methods like "getAllArtifactTypes": One just has to + * call getallTypes(TArtifactType.class) + * + * @return List of all types + */ + <T extends TEntityType> Collection<T> getAllTypes(Class<T> type); + + /** + * @return List of all types with associated elements (such as deployment + * artifacts). Each type is nested in a separate Definitions Element + */ + <T extends TEntityType> Collection<TDefinitions> getAllTypesWithAssociatedElements(Class<T> type); + + /** + * Returns the topology template associated to the given service template + * + * @param serviceTemplate a QName of the sericeTemplate with full namespace + * @return null if nothing is found + */ + TTopologyTemplate getTopologyTemplate(QName serviceTemplate); + + /** + * Replaces (or creates) the provided topology template + * + * @param serviceTemplate the service template the given topolgoy template + * belongs to + * @param topologyTemplate the topology template to use + */ + void setTopologyTemplate(QName serviceTemplate, TTopologyTemplate topologyTemplate) throws Exception; + + /** + * Returns a reference to the artifact type registered for the given file + * extensions. Returns null if no such artifact type exists. + * + * @param extension the file extension to look up. + * @return Reference in the form of a QName to the artifact type matching + * the given file extension. + */ + QName getArtifactTypeQNameForExtension(String extension); + + /** + * Creates a component of the type idClass. + * + * @param qname + * @param type + * @throws QNameAlreadyExistsException + */ + void createComponent(QName qname, Class<? extends TOSCAComponentId> idClass) throws QNameAlreadyExistsException; + + /** + * Creates the specified artifact template + * + * @param qname the namespace and name of the artifact template + * @param artifactType the artifact type of the artifact template + * @throws QNameAlreadyExistsException if the given QName already exists + */ + void createArtifactTemplate(QName qname, QName artifactType) throws QNameAlreadyExistsException; +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/IWineryRepositoryCommon.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/IWineryRepositoryCommon.java new file mode 100644 index 0000000..7221489 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/IWineryRepositoryCommon.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.interfaces; + +import java.io.IOException; + +import org.eclipse.winery.common.ids.GenericId; + +/** + * Enables access to the winery repository via Ids defined in package + * {@link org.eclipse.winery.common.ids} + * + * Methods are moved from + * {@link org.eclipse.winery.repository.backend.IGenericRepository} to here as + * soon there is an implementation for them. The ultimate goal is to eliminate + * IGenericRepository + * + * These methods are shared between {@link IWineryRepository} and + * {@link org.eclipse.winery.repository.backend.IRepository} + */ +public interface IWineryRepositoryCommon { + + /** + * Deletes the TOSCA element <b>and all sub elements</b> referenced by the + * given id from the repository + * + * We assume that each id is a directory + * + * @param id + */ + public void forceDelete(GenericId id) throws IOException; + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/QNameAlreadyExistsException.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/QNameAlreadyExistsException.java new file mode 100644 index 0000000..d089935 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/QNameAlreadyExistsException.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.interfaces; + +public class QNameAlreadyExistsException extends Exception { + + private static final long serialVersionUID = 1L; + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/QNameWithName.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/QNameWithName.java new file mode 100644 index 0000000..96c2e43 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/interfaces/QNameWithName.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.interfaces; + +import javax.xml.namespace.QName; + +/** + * This class is used to pass around QNames with associated names in string + * format + */ +public class QNameWithName { + + public QName qname; + public String name; +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/PropertyDefinitionKV.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/PropertyDefinitionKV.java new file mode 100644 index 0000000..f8cc236 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/PropertyDefinitionKV.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.propertydefinitionkv; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "PropertyDefinition") +public class PropertyDefinitionKV { + + private String key; + private String type; + + + public PropertyDefinitionKV() { + super(); + } + + public PropertyDefinitionKV(String key, String type) { + super(); + this.setKey(key); + this.setType(type); + } + + public String getKey() { + return this.key; + } + + public void setKey(String key) { + if (key == null) { + throw new IllegalArgumentException(); + } + this.key = key; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + if (type == null) { + throw new IllegalArgumentException(); + } + this.type = type; + } + + @Override + public int hashCode() { + return this.key.hashCode(); + } +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/PropertyDefinitionKVList.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/PropertyDefinitionKVList.java new file mode 100644 index 0000000..445bda6 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/PropertyDefinitionKVList.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.propertydefinitionkv; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "PropertyDefinitions") +public class PropertyDefinitionKVList extends ArrayList<PropertyDefinitionKV> { + + private static final long serialVersionUID = -6442041855597987094L; + + + @XmlElement(name = "PropertyDefinition") + public List<PropertyDefinitionKV> getPropertyDefinitionKVs() { + return this; + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/WinerysPropertiesDefinition.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/WinerysPropertiesDefinition.java new file mode 100644 index 0000000..548e87b --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/WinerysPropertiesDefinition.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common.propertydefinitionkv; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.eclipse.winery.common.constants.Namespaces; + +/** + * This is Winery's main extension element for a key/value based properties + * definition + */ +@XmlRootElement(name = "PropertiesDefinition") +public class WinerysPropertiesDefinition { + + private String namespace; + private String elementName; + private PropertyDefinitionKVList propertyDefinitionKVList; + private Boolean isDerivedFromXSD = Boolean.FALSE; + + + @XmlAttribute(name = "namespace") + public String getNamespace() { + return this.namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + @XmlAttribute(name = "elementname") + public String getElementName() { + return this.elementName; + } + + public void setElementName(String localName) { + this.elementName = localName; + } + + @XmlElement(name = "properties") + public PropertyDefinitionKVList getPropertyDefinitionKVList() { + return this.propertyDefinitionKVList; + } + + public void setPropertyDefinitionKVList(PropertyDefinitionKVList propertyDefinitionKVList) { + this.propertyDefinitionKVList = propertyDefinitionKVList; + } + + /** + * @return null if not derived from XSD, "Boolean.TRUE" otherwise. This + * leads JAXB to write the attribute only if derivedFromXSD is true + */ + @XmlAttribute(name = "derivedFromXSD", namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE) + public Boolean getIsDerivedFromXSD() { + if ((this.isDerivedFromXSD != null) && (this.isDerivedFromXSD)) { + return Boolean.TRUE; + } else { + return null; + } + } + + public void setIsDerivedFromXSD(Boolean isDerivedFromXSD) { + this.isDerivedFromXSD = isDerivedFromXSD; + } + +} diff --git a/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/package-info.java b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/package-info.java new file mode 100644 index 0000000..169e755 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/java/org/eclipse/winery/common/propertydefinitionkv/package-info.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * This package defines the data structures for key/value property handling + * + * The XML Schema is generated based on the user configuration. The namespace + * for the schema is the namespace of the respective type with + * {@code /propertiesdefinition/<localname>} appended, where {@code <localname>} + * is the local name of the entity type, where the properties definition is + * defined. + * + */ +@XmlSchema(namespace = Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, elementFormDefault = XmlNsForm.QUALIFIED) +package org.eclipse.winery.common.propertydefinitionkv; + +import javax.xml.bind.annotation.XmlNsForm; +import javax.xml.bind.annotation.XmlSchema; + +import org.eclipse.winery.common.constants.Namespaces; + diff --git a/winery/org.eclipse.winery.common/src/main/resources/TOSCA-v1.0.xsd b/winery/org.eclipse.winery.common/src/main/resources/TOSCA-v1.0.xsd new file mode 100644 index 0000000..8bed0e0 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/main/resources/TOSCA-v1.0.xsd @@ -0,0 +1,791 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Topology and Orchestration Specification for Cloud Applications Version 1.0 + Committee Specification Draft 08 + 09 May 2013 + Copyright (c) OASIS Open 2013. All rights reserved. + Source: http://docs.oasis-open.org/tosca/TOSCA/v1.0/csd08/schemas/ +--> +<xs:schema targetNamespace="http://docs.oasis-open.org/tosca/ns/2011/12" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns="http://docs.oasis-open.org/tosca/ns/2011/12" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> + <xs:element name="documentation" type="tDocumentation"/> + <xs:complexType name="tDocumentation" mixed="true"> + <xs:sequence> + <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="source" type="xs:anyURI"/> + <xs:attribute ref="xml:lang"/> + </xs:complexType> + <xs:complexType name="tExtensibleElements"> + <xs:sequence> + <xs:element ref="documentation" minOccurs="0" maxOccurs="unbounded"/> + <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:anyAttribute namespace="##other" processContents="lax"/> + </xs:complexType> + <xs:complexType name="tImport"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="namespace" type="xs:anyURI"/> + <xs:attribute name="location" type="xs:anyURI"/> + <xs:attribute name="importType" type="importedURI" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:element name="Definitions"> + <xs:complexType> + <xs:complexContent> + <xs:extension base="tDefinitions"/> + </xs:complexContent> + </xs:complexType> + </xs:element> + <xs:complexType name="tDefinitions"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Extensions" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Extension" type="tExtension" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Import" type="tImport" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="Types" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:choice maxOccurs="unbounded"> + <xs:element name="ServiceTemplate" type="tServiceTemplate"/> + <xs:element name="NodeType" type="tNodeType"/> + <xs:element name="NodeTypeImplementation" type="tNodeTypeImplementation"/> + <xs:element name="RelationshipType" type="tRelationshipType"/> + <xs:element name="RelationshipTypeImplementation" type="tRelationshipTypeImplementation"/> + <xs:element name="RequirementType" type="tRequirementType"/> + <xs:element name="CapabilityType" type="tCapabilityType"/> + <xs:element name="ArtifactType" type="tArtifactType"/> + <xs:element name="ArtifactTemplate" type="tArtifactTemplate"/> + <xs:element name="PolicyType" type="tPolicyType"/> + <xs:element name="PolicyTemplate" type="tPolicyTemplate"/> + </xs:choice> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tServiceTemplate"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="BoundaryDefinitions" type="tBoundaryDefinitions" minOccurs="0"/> + <xs:element name="TopologyTemplate" type="tTopologyTemplate"/> + <xs:element name="Plans" type="tPlans" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="targetNamespace" type="xs:anyURI"/> + <xs:attribute name="substitutableNodeType" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tTags"> + <xs:sequence> + <xs:element name="Tag" type="tTag" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tTag"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="value" type="xs:string" use="required"/> + </xs:complexType> + <xs:complexType name="tBoundaryDefinitions"> + <xs:sequence> + <xs:element name="Properties" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other"/> + <xs:element name="PropertyMappings" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="PropertyMapping" type="tPropertyMapping" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="PropertyConstraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="PropertyConstraint" type="tPropertyConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Requirements" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Requirement" type="tRequirementRef" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Capabilities" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Capability" type="tCapabilityRef" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Policies" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Policy" type="tPolicy" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Interfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tExportedInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tPropertyMapping"> + <xs:attribute name="serviceTemplatePropertyRef" type="xs:string" use="required"/> + <xs:attribute name="targetObjectRef" type="xs:IDREF" use="required"/> + <xs:attribute name="targetPropertyRef" type="xs:string" use="required"/> + </xs:complexType> + <xs:complexType name="tRequirementRef"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + <xs:complexType name="tCapabilityRef"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + <xs:complexType name="tEntityType" abstract="true"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="DerivedFrom" minOccurs="0"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="PropertiesDefinition" minOccurs="0"> + <xs:complexType> + <xs:attribute name="element" type="xs:QName"/> + <xs:attribute name="type" type="xs:QName"/> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + <xs:attribute name="abstract" type="tBoolean" default="no"/> + <xs:attribute name="final" type="tBoolean" default="no"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tEntityTemplate" abstract="true"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Properties" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="PropertyConstraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="PropertyConstraint" type="tPropertyConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="type" type="xs:QName" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tNodeTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:sequence> + <xs:element name="Requirements" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Requirement" type="tRequirement" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Capabilities" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Capability" type="tCapability" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Policies" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Policy" type="tPolicy" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="DeploymentArtifacts" type="tDeploymentArtifacts" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="minInstances" type="xs:int" use="optional" default="1"/> + <xs:attribute name="maxInstances" use="optional" default="1"> + <xs:simpleType> + <xs:union> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:pattern value="([1-9]+[0-9]*)"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="unbounded"/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tTopologyTemplate"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:choice maxOccurs="unbounded"> + <xs:element name="NodeTemplate" type="tNodeTemplate"/> + <xs:element name="RelationshipTemplate" type="tRelationshipTemplate"/> + </xs:choice> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRelationshipType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:sequence> + <xs:element name="InstanceStates" type="tTopologyElementInstanceStates" minOccurs="0"/> + <xs:element name="SourceInterfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="TargetInterfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="ValidSource" minOccurs="0"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="ValidTarget" minOccurs="0"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRelationshipTypeImplementation"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="DerivedFrom" minOccurs="0"> + <xs:complexType> + <xs:attribute name="relationshipTypeImplementationRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RequiredContainerFeatures" type="tRequiredContainerFeatures" minOccurs="0"/> + <xs:element name="ImplementationArtifacts" type="tImplementationArtifacts" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + <xs:attribute name="relationshipType" type="xs:QName" use="required"/> + <xs:attribute name="abstract" type="tBoolean" use="optional" default="no"/> + <xs:attribute name="final" type="tBoolean" use="optional" default="no"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRelationshipTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:sequence> + <xs:element name="SourceElement"> + <xs:complexType> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="TargetElement"> + <xs:complexType> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RelationshipConstraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="RelationshipConstraint" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="constraintType" type="xs:anyURI" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tNodeType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:sequence> + <xs:element name="RequirementDefinitions" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="RequirementDefinition" type="tRequirementDefinition" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="CapabilityDefinitions" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="CapabilityDefinition" type="tCapabilityDefinition" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="InstanceStates" type="tTopologyElementInstanceStates" minOccurs="0"/> + <xs:element name="Interfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tNodeTypeImplementation"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="DerivedFrom" minOccurs="0"> + <xs:complexType> + <xs:attribute name="nodeTypeImplementationRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RequiredContainerFeatures" type="tRequiredContainerFeatures" minOccurs="0"/> + <xs:element name="ImplementationArtifacts" type="tImplementationArtifacts" minOccurs="0"/> + <xs:element name="DeploymentArtifacts" type="tDeploymentArtifacts" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + <xs:attribute name="nodeType" type="xs:QName" use="required"/> + <xs:attribute name="abstract" type="tBoolean" use="optional" default="no"/> + <xs:attribute name="final" type="tBoolean" use="optional" default="no"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRequirementType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:attribute name="requiredCapabilityType" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRequirementDefinition"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Constraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Constraint" type="tConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="requirementType" type="xs:QName" use="required"/> + <xs:attribute name="lowerBound" type="xs:int" use="optional" default="1"/> + <xs:attribute name="upperBound" use="optional" default="1"> + <xs:simpleType> + <xs:union> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:pattern value="([1-9]+[0-9]*)"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="unbounded"/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRequirement"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:attribute name="name" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tCapabilityType"> + <xs:complexContent> + <xs:extension base="tEntityType"/> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tCapabilityDefinition"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Constraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Constraint" type="tConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="capabilityType" type="xs:QName" use="required"/> + <xs:attribute name="lowerBound" type="xs:int" use="optional" default="1"/> + <xs:attribute name="upperBound" use="optional" default="1"> + <xs:simpleType> + <xs:union> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:pattern value="([1-9]+[0-9]*)"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="unbounded"/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tCapability"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:attribute name="name" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tArtifactType"> + <xs:complexContent> + <xs:extension base="tEntityType"/> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tArtifactTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:sequence> + <xs:element name="ArtifactReferences" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="ArtifactReference" type="tArtifactReference" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tDeploymentArtifacts"> + <xs:sequence> + <xs:element name="DeploymentArtifact" type="tDeploymentArtifact" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tDeploymentArtifact"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="artifactType" type="xs:QName" use="required"/> + <xs:attribute name="artifactRef" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tImplementationArtifacts"> + <xs:sequence> + <xs:element name="ImplementationArtifact" maxOccurs="unbounded"> + <xs:complexType> + <xs:complexContent> + <xs:extension base="tImplementationArtifact"/> + </xs:complexContent> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tImplementationArtifact"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="interfaceName" type="xs:anyURI" use="optional"/> + <xs:attribute name="operationName" type="xs:NCName" use="optional"/> + <xs:attribute name="artifactType" type="xs:QName" use="required"/> + <xs:attribute name="artifactRef" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tPlans"> + <xs:sequence> + <xs:element name="Plan" type="tPlan" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + </xs:complexType> + <xs:complexType name="tPlan"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Precondition" type="tCondition" minOccurs="0"/> + <xs:element name="InputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="InputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="OutputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="OutputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:choice> + <xs:element name="PlanModel"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="PlanModelReference"> + <xs:complexType> + <xs:attribute name="reference" type="xs:anyURI" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="planType" type="xs:anyURI" use="required"/> + <xs:attribute name="planLanguage" type="xs:anyURI" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tPolicyType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:sequence> + <xs:element name="AppliesTo" type="tAppliesTo" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="policyLanguage" type="xs:anyURI" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tPolicyTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:attribute name="name" type="xs:string" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tAppliesTo"> + <xs:sequence> + <xs:element name="NodeTypeReference" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tPolicy"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="policyType" type="xs:QName" use="required"/> + <xs:attribute name="policyRef" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tConstraint"> + <xs:sequence> + <xs:any namespace="##other" processContents="lax"/> + </xs:sequence> + <xs:attribute name="constraintType" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tPropertyConstraint"> + <xs:complexContent> + <xs:extension base="tConstraint"> + <xs:attribute name="property" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tExtensions"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Extension" type="tExtension" maxOccurs="unbounded"/> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tExtension"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="namespace" type="xs:anyURI" use="required"/> + <xs:attribute name="mustUnderstand" type="tBoolean" use="optional" default="yes"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tParameter"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="type" type="xs:string" use="required"/> + <xs:attribute name="required" type="tBoolean" use="optional" default="yes"/> + </xs:complexType> + <xs:complexType name="tInterface"> + <xs:sequence> + <xs:element name="Operation" type="tOperation" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="name" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tExportedInterface"> + <xs:sequence> + <xs:element name="Operation" type="tExportedOperation" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="name" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tOperation"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="InputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="InputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="OutputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="OutputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tExportedOperation"> + <xs:choice> + <xs:element name="NodeOperation"> + <xs:complexType> + <xs:attribute name="nodeRef" type="xs:IDREF" use="required"/> + <xs:attribute name="interfaceName" type="xs:anyURI" use="required"/> + <xs:attribute name="operationName" type="xs:NCName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RelationshipOperation"> + <xs:complexType> + <xs:attribute name="relationshipRef" type="xs:IDREF" use="required"/> + <xs:attribute name="interfaceName" type="xs:anyURI" use="required"/> + <xs:attribute name="operationName" type="xs:NCName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="Plan"> + <xs:complexType> + <xs:attribute name="planRef" type="xs:IDREF" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="name" type="xs:NCName" use="required"/> + </xs:complexType> + <xs:complexType name="tCondition"> + <xs:sequence> + <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="expressionLanguage" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tTopologyElementInstanceStates"> + <xs:sequence> + <xs:element name="InstanceState" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="state" type="xs:anyURI" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tArtifactReference"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="Include"> + <xs:complexType> + <xs:attribute name="pattern" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="Exclude"> + <xs:complexType> + <xs:attribute name="pattern" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="reference" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tRequiredContainerFeatures"> + <xs:sequence> + <xs:element name="RequiredContainerFeature" type="tRequiredContainerFeature" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tRequiredContainerFeature"> + <xs:attribute name="feature" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:simpleType name="tBoolean"> + <xs:restriction base="xs:string"> + <xs:enumeration value="yes"/> + <xs:enumeration value="no"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="importedURI"> + <xs:restriction base="xs:anyURI"/> + </xs:simpleType> +</xs:schema> diff --git a/winery/org.eclipse.winery.common/src/test/java/.gitkeep b/winery/org.eclipse.winery.common/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/test/java/.gitkeep diff --git a/winery/org.eclipse.winery.common/src/test/java/META-INF/MANIFEST.MF b/winery/org.eclipse.winery.common/src/test/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..254272e --- /dev/null +++ b/winery/org.eclipse.winery.common/src/test/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/winery/org.eclipse.winery.common/src/test/java/org/eclipse/winery/common/ModelUtilitiesTest.java b/winery/org.eclipse.winery.common/src/test/java/org/eclipse/winery/common/ModelUtilitiesTest.java new file mode 100644 index 0000000..650241d --- /dev/null +++ b/winery/org.eclipse.winery.common/src/test/java/org/eclipse/winery/common/ModelUtilitiesTest.java @@ -0,0 +1,13 @@ +package org.eclipse.winery.common; + +import org.junit.Test; + +public class ModelUtilitiesTest { + + @Test + public void setPropertiesKV() { + // TODO: add some test here + // The test is difficult as a node type has to be generated with a wineryspropertiesdefinition, ... + } + +} diff --git a/winery/org.eclipse.winery.common/src/test/java/org/eclipse/winery/common/TestUtil.java b/winery/org.eclipse.winery.common/src/test/java/org/eclipse/winery/common/TestUtil.java new file mode 100644 index 0000000..8c0c924 --- /dev/null +++ b/winery/org.eclipse.winery.common/src/test/java/org/eclipse/winery/common/TestUtil.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.common; + +import org.junit.Assert; +import org.junit.Test; + +public class TestUtil { + + @Test + public void testNamespaceToJavaPackageFullURL() { + Assert.assertEquals("org.example.www.tosca.nodetypes", Util.namespaceToJavaPackage("http://www.example.org/tosca/nodetypes")); + } + + @Test + public void testNamespaceToJavaPackageURLWithHostOnly() { + Assert.assertEquals("org.example.www", Util.namespaceToJavaPackage("http://www.example.org/")); + } + + @Test + public void testNamespaceToJavaPackageURLWithHostOnlyAndNoFinalSlash() { + Assert.assertEquals("org.example.www", Util.namespaceToJavaPackage("http://www.example.org")); + } + + @Test + public void testNamespaceToJavaPackageURLWithNoHost() { + Assert.assertEquals("plainNCname", Util.namespaceToJavaPackage("plainNCname")); + } + + @Test + public void testNCNameFromURL() { + Assert.assertEquals("http___www.example.org", Util.makeNCName("http://www.example.org")); + } + + @Test + public void testNCNameFromNCName() { + Assert.assertEquals("NCName", Util.makeNCName("NCName")); + } +} diff --git a/winery/org.eclipse.winery.generators.ia/.gitignore b/winery/org.eclipse.winery.generators.ia/.gitignore new file mode 100644 index 0000000..bfe7d2a --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/.gitignore @@ -0,0 +1,9 @@ +.classpath +/.gradle +.settings +.project +/.sonar +/bin +/build +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.generators.ia/about.html b/winery/org.eclipse.winery.generators.ia/about.html new file mode 100644 index 0000000..b02b906 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/about.html @@ -0,0 +1,155 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<h4>Java Libraries</h4> + +<h5>Apache Commons IO – Version 2.4</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-io/">http://commons.apache.org/proper/commons-io/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang3 – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>JSP Standard Tag Library – Version 1.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://jstl.java.net/">https://jstl.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Logback Classic – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: jcl-over-slf4j – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.tosca – Version 0.1.20</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>xz for Java – Version 1.3</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://tukaani.org/xz/java.html">http://tukaani.org/xz/java.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Public domain. A copy of the license is available at <a href="http://tukaani.org/xz/java.html" target="_blank">http://tukaani.org/xz/java.html</a></td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.generators.ia/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.generators.ia/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.generators.ia/about_files/CDDL-v1.1.txt b/winery/org.eclipse.winery.generators.ia/about_files/CDDL-v1.1.txt new file mode 100644 index 0000000..7cc8719 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/about_files/CDDL-v1.1.txt @@ -0,0 +1,129 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL - Version 1.1) +1. Definitions. + + 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + + 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + + 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + + 1.4. “Executable” means the Covered Software in any form other than Source Code. + + 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + + 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + + 1.7. “License” means this document. + + 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + + 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + + 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + + 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.generators.ia/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.generators.ia/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.generators.ia/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.generators.ia/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.generators.ia/pom.xml b/winery/org.eclipse.winery.generators.ia/pom.xml new file mode 100644 index 0000000..ccdf43b --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/pom.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Binz - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.winery</groupId> + <artifactId>winery</artifactId> + <version>0.1.37-SNAPSHOT</version> + </parent> + <artifactId>org.eclipse.winery.generators.ia</artifactId> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.common</artifactId> + <version>0.1.37-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.7.6</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.tosca</artifactId> + <version>0.1.21-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.6</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <!-- Version 1.3 is approved by Eclipse, Version 1.4 is not --> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.16</version> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/winery/org.eclipse.winery.generators.ia/src/main/java/org/eclipse/winery/generators/ia/Generator.java b/winery/org.eclipse.winery.generators.ia/src/main/java/org/eclipse/winery/generators/ia/Generator.java new file mode 100644 index 0000000..571d42c --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/java/org/eclipse/winery/generators/ia/Generator.java @@ -0,0 +1,393 @@ +/******************************************************************************* + * Copyright (c) 2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Binz - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.generators.ia; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.ArchiveStreamFactory; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.commons.io.FileUtils; +import org.eclipse.winery.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.model.tosca.TParameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Generator { + + private static final Logger logger = LoggerFactory.getLogger(Generator.class); + + // Placeholder applicable for all files + public static final String PLACEHOLDER_JAVA_PACKAGE = "IA_PACKAGE"; + public static final String PLACEHOLDER_NAMESPACE = "IA_NAMESPACE"; + public static final String PLACEHOLDER_CLASS_NAME = "IA_CLASS_NAME"; + public static final String PLACEHOLDER_IA_ARTIFACT_TEMPLATE_UPLOAD_URL = "IA_ARTIFACT_TEMPLATE_UPLOAD_URL"; + + // Placeholders in Java Service Files + public static final String PLACEHOLDER_GENERATED_WEBSERVICE_METHODS = "GENERATED_WEBSERVICE_METHODS"; + + // Template folder relative to resources folder in this project + public static final String TEMPLATE_PROJECT_FOLDER = "template/project"; + public static final String TEMPLATE_JAVA_FOLDER = "template/java"; + + private static final String TEMPLATE_JAVA_ABSTRACT_IA_SERVICE = "AbstractIAService.java.template"; + private static final String TEMPLATE_JAVA_TEMPLATE_SERVICE = "TemplateService.java.template"; + + private final TInterface tinterface; + private final File workingDir; + private final File outDir; + private final String name; + private final String javaPackage; + private final String namespace; + private final URL iaArtifactTemplateUploadUrl; + + + /** + * Creates a new IA Generator instance for the given {@link TInterface}. + * + * @param tinterface TOSCA interface to generate the IA for + * @param packageAndNamespace Package to be used for the generated Java + * code, e.g. 'org.opentosca.ia'. To generate the respective + * Namespace for the Web Service the components of the package + * are reverted, prepended with 'http://' and appended with '/'. + * This is provided by the user in a textfield in the Winery UI. + * @param iaArtifactTemplateUploadUrl The URL to which the generated IA + * should be posted. + * @param name unique and valid name to be used for the generated maven + * project name, java project name, class name, port type name. + * @param workingDir working directory to generate the files. This directory + * also will contain the ZIP file with the Eclipse project after + * generating it. + */ + public Generator(TInterface tinterface, String packageAndNamespace, URL iaArtifactTemplateUploadUrl, String name, File workingDir) { + super(); + this.tinterface = tinterface; + this.javaPackage = packageAndNamespace; + this.iaArtifactTemplateUploadUrl = iaArtifactTemplateUploadUrl; + this.name = name; + this.workingDir = new File(workingDir.getAbsolutePath() + File.separator + this.name); + this.outDir = new File(workingDir.getAbsolutePath()); + + if (this.workingDir.exists()) { + Generator.logger.error("Workdir " + this.workingDir + " already exits. This might lead to corrupted results if it is not empty!"); + } + + // Generate Namespace + String[] splitPkg = this.javaPackage.split("\\."); + String tmpNamespace = "http://"; + for (int i = splitPkg.length - 1; i >= 0; i--) { + tmpNamespace += splitPkg[i]; + // Add '.' if it is not the last iterations + if (i != 0) { + tmpNamespace += "."; + } + } + this.namespace = tmpNamespace += "/"; + } + + /** + * Generates the IA project. + * + * @return The ZIP file containing the maven/eclipse project to be + * downloaded by the user. + */ + public File generateProject() { + + try { + Path workingDirPath = this.workingDir.toPath(); + Files.createDirectories(workingDirPath); + + // directory to store the template files to generate the java files from + Path javaTemplateDir = workingDirPath.resolve("../java"); + Files.createDirectories(javaTemplateDir); + + // Copy template project and template java files + String s = this.getClass().getResource("").getPath(); + if (s.contains("jar!")) { + Generator.logger.trace("we work on a jar file"); + Generator.logger.trace("Location of the current class: {}", s); + + // we have a jar file + // format: file:/location...jar!...path-in-the-jar + // we only want to have location :) + int excl = s.lastIndexOf("!"); + s = s.substring(0, excl); + s = s.substring("file:".length()); + + try (JarFile jf = new JarFile(s);) { + Enumeration<JarEntry> entries = jf.entries(); + while (entries.hasMoreElements()) { + JarEntry je = entries.nextElement(); + String name = je.getName(); + if (name.startsWith(Generator.TEMPLATE_PROJECT_FOLDER + "/") && (name.length() > (Generator.TEMPLATE_PROJECT_FOLDER.length() + 1))) { + // strip "template/" from the beginning to have paths without "template" starting relatively from the working dir + name = name.substring(Generator.TEMPLATE_PROJECT_FOLDER.length() + 1); + if (je.isDirectory()) { + // directory found + Path dir = workingDirPath.resolve(name); + Files.createDirectory(dir); + } else { + Path file = workingDirPath.resolve(name); + try (InputStream is = jf.getInputStream(je);) { + Files.copy(is, file, StandardCopyOption.REPLACE_EXISTING); + } + } + } else if (name.startsWith(Generator.TEMPLATE_JAVA_FOLDER + "/") && (name.length() > (Generator.TEMPLATE_JAVA_FOLDER.length() + 1))) { + if (!je.isDirectory()) { + // we copy the file directly into javaTemplateDir + File f = new File(name); + Path file = javaTemplateDir.resolve(f.getName()); + try (InputStream is = jf.getInputStream(je);) { + Files.copy(is, file, StandardCopyOption.REPLACE_EXISTING); + } + } + } + } + } + } else { + // we're running in debug mode, we can work on the plain file system + File templateProjectDir = new File(this.getClass().getResource("/" + Generator.TEMPLATE_PROJECT_FOLDER).getFile()); + FileUtils.copyDirectory(templateProjectDir, this.workingDir); + + File javaTemplatesDir = new File(this.getClass().getResource("/" + Generator.TEMPLATE_JAVA_FOLDER).getFile()); + FileUtils.copyDirectory(javaTemplatesDir, javaTemplateDir.toFile()); + } + + // Create Java Code Folder + String[] splitPkg = this.javaPackage.split("\\."); + String javaFolderString = this.workingDir.getAbsolutePath() + File.separator + "src" + File.separator + "main" + File.separator + "java"; + for (int i = 0; i < splitPkg.length; i++) { + javaFolderString += File.separator + splitPkg[i]; + } + + // Copy TEMPLATE_JAVA_ABSTRACT_IA_SERVICE + Path templateAbstractIAService = javaTemplateDir.resolve(Generator.TEMPLATE_JAVA_ABSTRACT_IA_SERVICE); + File javaAbstractIAService = new File(javaFolderString + File.separator + "AbstractIAService.java"); + Files.createDirectories(javaAbstractIAService.toPath().getParent()); + Files.copy(templateAbstractIAService, javaAbstractIAService.toPath(), StandardCopyOption.REPLACE_EXISTING); + + // Copy and rename TEMPLATE_JAVA_TEMPLATE_SERVICE + Path templateJavaService = javaTemplateDir.resolve(Generator.TEMPLATE_JAVA_TEMPLATE_SERVICE); + File javaService = new File(javaFolderString + File.separator + this.name + ".java"); + Files.createDirectories(javaService.toPath().getParent()); + Files.copy(templateJavaService, javaService.toPath(), StandardCopyOption.REPLACE_EXISTING); + + this.generateJavaFile(javaService); + this.updateFilesRecursively(this.workingDir); + return this.packageProject(); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private void generateJavaFile(File javaService) throws IOException { + + // Generate methods + StringBuilder sb = new StringBuilder(); + + for (TOperation op : this.tinterface.getOperation()) { + // Annotations + sb.append("\t@WebMethod\n"); + sb.append("\t@SOAPBinding\n"); + sb.append("\t@Oneway\n"); + + // Signatur + String operationReturn = "void"; + sb.append("\tpublic " + operationReturn + " " + op.getName() + "(\n"); + + // Parameter + boolean first = true; + if (op.getInputParameters() != null) { + for (TParameter parameter : op.getInputParameters().getInputParameter()) { + String parameterName = parameter.getName(); + + if (first) { + first = false; + sb.append("\t\t"); + } else { + sb.append(",\n\t\t"); + } + + // Generate @WebParam + sb.append("@WebParam(name=\"" + parameterName + "\", targetNamespace=\"" + this.namespace + "\") "); + + // Handle required and optional parameters using @XmlElement + if (parameter.getRequired().equals(TBoolean.YES)) { + sb.append("@XmlElement(required=true)"); + } else { + sb.append("@XmlElement(required=false)"); + } + + sb.append(" String " + parameterName); + } + } + sb.append("\n\t) {\n"); + + // If there are output parameters we generate the respective HashMap + boolean outputParamsExist = (op.getOutputParameters() != null) && (!op.getOutputParameters().getOutputParameter().isEmpty()); + if (outputParamsExist) { + sb.append("\t\t// This HashMap holds the return parameters of this operation.\n"); + sb.append("\t\tfinal HashMap<String,String> returnParameters = new HashMap<String, String>();\n\n"); + } + + sb.append("\t\t// TODO: Implement your operation here.\n"); + + // Generate code to set output parameters + if (outputParamsExist) { + for (TParameter outputParam : op.getOutputParameters().getOutputParameter()) { + sb.append("\n\n\t\t// Output Parameter '" + outputParam.getName() + "' "); + if (outputParam.getRequired().equals(TBoolean.YES)) { + sb.append("(required)"); + } else { + sb.append("(optional)"); + } + sb.append("\n\t\t// TODO: Set " + outputParam.getName() + " parameter here."); + sb.append("\n\t\t// Do NOT delete the next line of code. Set \"\" as value if you want to return nothing or an empty result!"); + sb.append("\n\t\treturnParameters.put(\"" + outputParam.getName() + "\", \"TODO\");"); + } + sb.append("\n\n\t\tsendResponse(returnParameters);\n"); + } + + sb.append("\t}\n\n"); + } + + // Read file and replace placeholders + Charset cs = Charset.defaultCharset(); + List<String> lines = new ArrayList<>(); + for (String line : Files.readAllLines(javaService.toPath(), cs)) { + // Replace web service method + line = line.replaceAll(Generator.PLACEHOLDER_GENERATED_WEBSERVICE_METHODS, sb.toString()); + lines.add(line); + } + + // Write file + OpenOption[] options = new OpenOption[] {StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING}; + Files.write(javaService.toPath(), lines, cs, options); + } + + /** + * Iterates recursively through all the files in the project working + * directory and tries to replace the global placeholders. + * + * @param folderOrFile to start with + */ + private void updateFilesRecursively(File folderOrFile) { + if (folderOrFile.isFile()) { + + if (folderOrFile.getAbsolutePath().endsWith(".jar")) { + return; + } + + Generator.logger.trace("Updating file " + folderOrFile); + + try { + // Read file and replace placeholders + Charset cs = Charset.defaultCharset(); + List<String> lines = new ArrayList<>(); + for (String line : Files.readAllLines(folderOrFile.toPath(), cs)) { + line = line.replaceAll(Generator.PLACEHOLDER_CLASS_NAME, this.name); + line = line.replaceAll(Generator.PLACEHOLDER_JAVA_PACKAGE, this.javaPackage); + line = line.replaceAll(Generator.PLACEHOLDER_NAMESPACE, this.namespace); + line = line.replaceAll(Generator.PLACEHOLDER_IA_ARTIFACT_TEMPLATE_UPLOAD_URL, this.iaArtifactTemplateUploadUrl.toString()); + lines.add(line); + } + + // Write file + OpenOption[] options = new OpenOption[] {StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING}; + Files.write(folderOrFile.toPath(), lines, cs, options); + + } catch (IOException e) { + e.printStackTrace(); + } + + } else { + Generator.logger.trace("Updating folder " + folderOrFile); + for (File childFile : folderOrFile.listFiles()) { + this.updateFilesRecursively(childFile); + } + } + } + + /** + * Packages the generated project into a ZIP file which is stored in outDir + * and has the name of the Project. + * + * @return ZIP file + */ + private File packageProject() { + try { + File packagedProject = new File(this.outDir.getAbsoluteFile() + File.separator + this.name + ".zip"); + FileOutputStream fileOutputStream = new FileOutputStream(packagedProject); + final ArchiveOutputStream zos = new ArchiveStreamFactory().createArchiveOutputStream("zip", fileOutputStream); + + this.addFilesRecursively(this.workingDir.getAbsoluteFile(), this.workingDir.getAbsoluteFile().getAbsolutePath() + File.separator, zos); + + zos.finish(); + zos.close(); + + return packagedProject; + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Recursive Helper function for packageProject() + * + * @param folderOrFile to add into the archive + * @param baseDir + * @param zos ArchiveOutputStream to add the files to + */ + private void addFilesRecursively(File folderOrFile, String baseDir, ArchiveOutputStream zos) { + if (folderOrFile.isFile()) { + String nameOfFileInZip = folderOrFile.getAbsolutePath().replace(baseDir, ""); + Generator.logger.trace("Adding " + folderOrFile + " as " + nameOfFileInZip); + ArchiveEntry archiveEntry = new ZipArchiveEntry(nameOfFileInZip); + try (InputStream is = new FileInputStream(folderOrFile)) { + zos.putArchiveEntry(archiveEntry); + IOUtils.copy(is, zos); + zos.closeArchiveEntry(); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + Generator.logger.trace("Adding folder " + folderOrFile); + for (File childFile : folderOrFile.listFiles()) { + this.addFilesRecursively(childFile, baseDir, zos); + } + } + } +} diff --git a/winery/org.eclipse.winery.generators.ia/src/main/resources/template/java/AbstractIAService.java.template b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/java/AbstractIAService.java.template new file mode 100644 index 0000000..4d4d2a4 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/java/AbstractIAService.java.template @@ -0,0 +1,86 @@ +package IA_PACKAGE; + +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +import javax.annotation.Resource; +import javax.xml.ws.WebServiceContext; + +import org.apache.cxf.headers.Header; +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.jaxws.context.WrappedMessageContext; +import org.apache.cxf.message.Message; +import org.w3c.dom.Node; + +import org.eclipse.winery.highlevelrestapi.HighLevelRestApi; + +public abstract class AbstractIAService { + + @Resource + private WebServiceContext context; + + protected void sendResponse (HashMap<String,String> returnParameters) { + + // Extract message + WrappedMessageContext wrappedContext = (WrappedMessageContext) context.getMessageContext(); + Message message = wrappedContext.getWrappedMessage(); + + // Extract headers from message + List<Header> headers = CastUtils.cast((List<?>) message.get(Header.HEADER_LIST)); + + // Find ReplyTo and MessageID SOAP Header + String replyTo = null; + String messageID = null; + for (Header iter : headers) { + + Object headerObject = iter.getObject(); + + // Unmarshall to org.w3c.dom.Node + if (headerObject instanceof Node) { + Node node = (Node) headerObject; + String localPart = iter.getName().getLocalPart(); + String content = node.getTextContent(); + + // Extract ReplyTo Header value + if ("ReplyTo".equals(localPart)) { + replyTo = content; + } + + // Extract MessageID Header value + if ("MessageID".equals(localPart)) { + messageID = content; + } + } + } + + // Create asynchronous SOAP Response Message + StringBuilder builder = new StringBuilder(); + + builder.append("<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:sch='http://siserver.org/schema'>"); + builder.append(" <soapenv:Header/>"); + builder.append(" <soapenv:Body>"); + builder.append(" <sch:invokeResponse>"); + builder.append(" <sch:MessageID>" + messageID + "</sch:MessageID>"); + + // Insert return parameters into asynchronous SOAP Response Message + for (Entry<String, String> paramIter : returnParameters.entrySet()) { + + String key = paramIter.getKey(); + String value = paramIter.getValue(); + + builder.append(" <" + key + ">" + value + "</" + key +">"); + } + + builder.append(" </sch:invokeResponse>"); + builder.append(" </soapenv:Body>"); + builder.append("</soapenv:Envelope>"); + + // Send SOAP Response Message back to requester + if(replyTo == null) { + System.err.println("No 'ReplyTo' header found!\nTherefore, reply message is printed here:\n" + builder.toString()); + } else { + HighLevelRestApi.Post(replyTo, builder.toString(), ""); + } + } +} diff --git a/winery/org.eclipse.winery.generators.ia/src/main/resources/template/java/TemplateService.java.template b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/java/TemplateService.java.template new file mode 100644 index 0000000..692905e --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/java/TemplateService.java.template @@ -0,0 +1,17 @@ +package IA_PACKAGE; + +import java.util.HashMap; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.xml.bind.annotation.XmlElement; + +@WebService +public class IA_CLASS_NAME extends AbstractIAService { + +GENERATED_WEBSERVICE_METHODS + +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/README.txt b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/README.txt new file mode 100644 index 0000000..bce220d --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/README.txt @@ -0,0 +1,61 @@ +########################################################################### +GENERATED IMPLEMENTATION ARTIFACT SKELETON FOR IA_CLASS_NAME + +Interface Name: IA_CLASS_NAME +Namespace: IA_NAMESPACE +Java Package: IA_PACKAGE +URL: IA_ARTIFACT_TEMPLATE_UPLOAD_URL../ +########################################################################### + +##### Preconditions +To develop and build this Implementation Artifact you need Maven and Eclipse. ++ How to install maven is described at the end of this file ++ If you use an Eclipse workspace for the first time with a maven project you've to run this command before starting eclipse: + mvn -Declipse.workspace="<your_workspace_location>" eclipse:configure-workspace + - When using Windows: Make sure you replace '\' (backslashes) with '/' ('slashes') + - It doesn't hurt to run it multiple times + - This command must not be executed in a particular folder + +##### Preparations ++ Unzip the archive generated by Winery into a location of your choice. ++ Note: All following maven commands are executed on a shell in the root folder of the Implementation Artifact. + +##### Create eclipse project +- Run: mvn eclipse:eclipse +- Open Eclipse +- 'File' -> 'Import' -> 'Existing Project into Workspace' -> click 'Next' +- Click 'Browse' and select folder where you unzipped the generated Implementation Artifact +- Select the project from the list and click 'Finish' + +##### Test your Implementation Artifact +- Run: mvn clean package tomcat7:run-war + (more information: http://tomcat.apache.org/maven-plugin-trunk/tomcat7-maven-plugin/plugin-info.html) +- Open this page to see the list of available services: http://localhost:9090/services/ +- This page also links the WSDL +- With the WSDL your're able to test your IA using SOAPui or other tools. + +##### Upload your Implementation Artifact +You have to options to do this: + +### 1) Automatically (to the Winery instance this IA project was generated with) +- Run: mvn deploy +- The WAR is directly uploaded into the correct ArtifactTemplate. Previous versions are overwritten. + +### 2) Manually +- Run: mvn clean package +- Locate the WAR file in the /target folder +- Open Winery in your browser, locate the NodeType and then click through to the Implementation of the respective Interface, its Implementation Artifacts and lastly to the ArtifactTemplate representing this IA. +- Upload the WAR file by clicking on the "Attach file..." button + + +##### Install Maven +- Download latest release of Maven: http://maven.apache.org/download.cgi (Binary zip) +- Unzip into directory of your choice +- Set environment variables (in system environment variables, not the ones for the user account): + + Check that the variables JAVA_HOME and JRE_HOME are set. If not create them and enter the path to your JDK, e.g., C:\Program Files (x86)\Java\jdk1.6.0_21 + + Create the following environment variables + M2_HOME = C:\Path\where\your\maven\was\unzipped\to (no backslash at the end) + M2 = %M2_HOME%\bin + MAVEN_OPTS = -Xms256m -Xmx512m + + Append ;%M2% to the 'Path' environment variable. Make sure to separate the new entry with a semicolon (;) from the last one. +- After that you have to open a new command line windows (if you already opened one) to let the changes take effect.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/pom.xml b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/pom.xml new file mode 100644 index 0000000..1a0b715 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/pom.xml @@ -0,0 +1,251 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>IA_PACKAGE</groupId> + <artifactId>IA_CLASS_NAME</artifactId> + <packaging>war</packaging> + <version>1.0-SNAPSHOT</version> + <name>Implementation Artifact IA_CLASS_NAME</name> + + <repositories> + <repository> + <id>2471.de</id> + <url>http://2471.de/maven2</url> + </repository> + </repositories> + + <properties> + <run.HttpPort>9090</run.HttpPort> + <winery.upload.url>IA_ARTIFACT_TEMPLATE_UPLOAD_URL</winery.upload.url> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <cxf.version>2.7.6</cxf.version> + <highlevelrestapi.version>0.1.6</highlevelrestapi.version> + </properties> + + <dependencies> + <!-- LIBRARIES ADDED FOR IMPLEMENTATION ARTIFACT IMPLEMENTATION --> + + + <!-- END - LIBRARIES ADDED FOR IMPLEMENTATION ARTIFACT IMPLEMENTATION --> + + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.highlevelrestapi</artifactId> + <version>${highlevelrestapi.version}</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.5</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxws</artifactId> + <version>${cxf.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-simple</artifactId> + <version>${cxf.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-transports-http</artifactId> + <version>${cxf.version}</version> + </dependency> + </dependencies> + <build> + <finalName>IA_CLASS_NAME</finalName> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.0</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-eclipse-plugin</artifactId> + <version>2.9</version> + <configuration> + <downloadSources>false</downloadSources> + <downloadJavadocs>true</downloadJavadocs> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-java2ws-plugin</artifactId> + <version>${cxf.version}</version> + <dependencies> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxws</artifactId> + <version>${cxf.version}</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-simple</artifactId> + <version>${cxf.version}</version> + </dependency> + </dependencies> + <executions> + <execution> + <id>process-classes</id> + <phase>process-classes</phase> + <configuration> + <className>IA_PACKAGE.IA_CLASS_NAME</className> + <outputFile>${basedir}/src/main/webapp/wsdl/IA_CLASS_NAME.wsdl</outputFile> + <genWsdl>true</genWsdl> + <verbose>true</verbose> + </configuration> + <goals> + <goal>java2ws</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>2.3</version> + <configuration> + <webXml>src/main/webapp/WEB-INF/web.xml</webXml> + </configuration> + </plugin> + + <!-- Inspired by: http://giallone.blogspot.de/2013/02/post-file-to-web-page-as-part-of-maven.html --> + <plugin> + <groupId>org.codehaus.gmaven</groupId> + <artifactId>gmaven-plugin</artifactId> + <version>1.4</version> + <dependencies> + <dependency> + <groupId>org.codehaus.gmaven.runtime</groupId> + <artifactId>gmaven-runtime-1.7</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpmime</artifactId> + <version>4.2.1</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>4.2.1</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.2.1</version> + </dependency> + </dependencies> + <executions> + <execution> + <id>upload2winery</id> + <!-- In this mvn phase... --> + <phase>deploy</phase> + <!-- ...run the execute goal of this plugin --> + <goals> + <goal>execute</goal> + </goals> + <configuration> + <providerSelection>1.7</providerSelection> + <source> + import org.apache.http.impl.client.DefaultHttpClient + import org.apache.http.client.methods.HttpPost + import org.apache.http.entity.mime.MultipartEntity + import org.apache.http.entity.mime.content.FileBody + + // Get WAR file + def name = "target/${project.build.finalName}.war" + println "Archive file: $name" + def f = new File(name) + + // POST file + DefaultHttpClient httpclient = new DefaultHttpClient() + println "Upload URL: ${winery.upload.url}" + def post = new HttpPost("${winery.upload.url}") + def entity = new MultipartEntity() + def fileBody = new FileBody(f) + entity.addPart("files[]", fileBody) + post.setEntity(entity) + + // Process response + def response = httpclient.execute(post) + def status = response.getStatusLine() + if( !(status ==~ /.*Created.*/) ) + fail("IA upload to Winery FAILED, please upload manually. (HTTP status code: $status)" ) + else + println "IA upload finished sucessfully (HTTP status code $status)" + </source> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.tomcat.maven</groupId> + <artifactId>tomcat7-maven-plugin</artifactId> + <version>2.1</version> + <configuration> + <!-- http port --> + <port>${run.HttpPort}</port> + <!-- application path always starts with / --> + <path>/</path> + <!-- if you want to use test dependencies rather than only runtime --> + <useTestClasspath>false</useTestClasspath> + </configuration> + </plugin> + + <!-- Disable default install phase, because we don't install into maven + repo but into Winery (during deploy phase). --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <executions> + <execution> + <id>default-install</id> + <phase>none</phase> + </execution> + </executions> + </plugin> + + <!-- Disable default deploy phase, because we don't deploy into remote + maven repo but into remote Winery. --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <executions> + <execution> + <id>default-deploy</id> + <phase>none</phase> + </execution> + </executions> + </plugin> + </plugins> + </pluginManagement> + + </build> +</project>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/src/main/webapp/WEB-INF/beans.xml b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..2a926f2 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> + <import resource="classpath:META-INF/cxf/cxf.xml" /> + <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> + <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> + <jaxws:endpoint xmlns:tns="IA_NAMESPACE" + id="IA_CLASS_NAME" implementor="IA_PACKAGE.IA_CLASS_NAME" + wsdlLocation="wsdl/IA_CLASS_NAME.wsdl" endpointName="tns:IA_CLASS_NAMEPort" + serviceName="tns:IA_CLASS_NAMEService" address="/IA_CLASS_NAMEPort"> + <jaxws:features> + <bean class="org.apache.cxf.feature.LoggingFeature" /> + </jaxws:features> + </jaxws:endpoint> +</beans> diff --git a/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/src/main/webapp/WEB-INF/web.xml b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..f7bd1bf --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/main/resources/template/project/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> + <display-name>IA_CLASS_NAME</display-name> + <welcome-file-list> + <welcome-file>index.html</welcome-file> + <welcome-file>index.htm</welcome-file> + <welcome-file>index.jsp</welcome-file> + <welcome-file>default.html</welcome-file> + <welcome-file>default.htm</welcome-file> + <welcome-file>default.jsp</welcome-file> + </welcome-file-list> + <servlet> + <description>Apache CXF Endpoint</description> + <display-name>cxf</display-name> + <servlet-name>cxf</servlet-name> + <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> + <load-on-startup>1</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>cxf</servlet-name> + <url-pattern>/services/*</url-pattern> + </servlet-mapping> + <session-config> + <session-timeout>60</session-timeout> + </session-config> + <context-param> + <param-name>contextConfigLocation</param-name> + <param-value>WEB-INF/beans.xml</param-value> + </context-param> + <listener> + <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> + </listener> +</web-app> diff --git a/winery/org.eclipse.winery.generators.ia/src/test/java/META-INF/MANIFEST.MF b/winery/org.eclipse.winery.generators.ia/src/test/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..254272e --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/test/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/winery/org.eclipse.winery.generators.ia/src/test/java/org/eclipse/winery/generators/ia/Test.java b/winery/org.eclipse.winery.generators.ia/src/test/java/org/eclipse/winery/generators/ia/Test.java new file mode 100644 index 0000000..73d4127 --- /dev/null +++ b/winery/org.eclipse.winery.generators.ia/src/test/java/org/eclipse/winery/generators/ia/Test.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Binz - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.generators.ia; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.winery.model.tosca.ObjectFactory; +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.model.tosca.TOperation.InputParameters; +import org.eclipse.winery.model.tosca.TOperation.OutputParameters; +import org.eclipse.winery.model.tosca.TParameter; +import org.junit.BeforeClass; + +public class Test { + + private static Path WORKING_DIR; + + + @BeforeClass + public static void initializeWorkingDir() throws IOException { + Test.WORKING_DIR = Files.createTempDirectory("IAGenerator"); + } + + @org.junit.Test + public void testInOut() throws MalformedURLException { + ObjectFactory f = new ObjectFactory(); + + TInterface tinterface = f.createTInterface(); + tinterface.setName("http://www.example.org/interfaces/lifecycle"); + + TOperation op1 = f.createTOperation(); + op1.setName("Op1InOut"); + tinterface.getOperation().add(op1); + InputParameters op1InputParameters = f.createTOperationInputParameters(); + + TParameter op1ip1 = f.createTParameter(); + op1ip1.setName("op1ip1"); + op1ip1.setType("xs:string"); + op1InputParameters.getInputParameter().add(op1ip1); + TParameter op1ip2 = f.createTParameter(); + op1ip2.setName("op1ip2"); + op1ip2.setType("xs:string"); + op1InputParameters.getInputParameter().add(op1ip2); + op1.setInputParameters(op1InputParameters); + + OutputParameters op1OutputParameters = f.createTOperationOutputParameters(); + TParameter op1op1 = f.createTParameter(); + op1op1.setName("op1op1"); + op1op1.setType("xs:string"); + op1OutputParameters.getOutputParameter().add(op1op1); + TParameter op1op2 = f.createTParameter(); + op1op2.setName("op1op2"); + op1op1.setType("xs:string"); + op1OutputParameters.getOutputParameter().add(op1op2); + op1.setOutputParameters(op1OutputParameters); + + TNodeType nodeType = f.createTNodeType(); + nodeType.setName("test"); + nodeType.setTargetNamespace("http://asd.com"); + + Generator gen = new Generator(tinterface, "org.opentosca.ia", new URL("http://asd.com"), "testname", Test.WORKING_DIR.toFile()); + File generateProject = gen.generateProject(); + System.out.println(generateProject); + } + + @org.junit.Test + public void testMultipleOperationsInOrOut() throws MalformedURLException { + ObjectFactory f = new ObjectFactory(); + + TInterface tinterface = f.createTInterface(); + tinterface.setName("TestInOrOut"); + + TOperation opIn = f.createTOperation(); + opIn.setName("OpIn"); + tinterface.getOperation().add(opIn); + + InputParameters op1InputParameters = f.createTOperationInputParameters(); + TParameter op1ip1 = f.createTParameter(); + op1ip1.setName("op1ip1"); + op1ip1.setType("xs:string"); + op1InputParameters.getInputParameter().add(op1ip1); + TParameter op1ip2 = f.createTParameter(); + op1ip2.setName("op1ip2"); + op1ip2.setType("xs:string"); + op1InputParameters.getInputParameter().add(op1ip2); + opIn.setInputParameters(op1InputParameters); + + TOperation opOut = f.createTOperation(); + opOut.setName("OpOut"); + tinterface.getOperation().add(opOut); + + OutputParameters op1OutputParameters = f.createTOperationOutputParameters(); + TParameter op1op1 = f.createTParameter(); + op1op1.setName("op1op1"); + op1op1.setType("xs:string"); + op1OutputParameters.getOutputParameter().add(op1op1); + TParameter op1op2 = f.createTParameter(); + op1op2.setName("op1op2"); + op1op1.setType("xs:string"); + op1OutputParameters.getOutputParameter().add(op1op2); + opOut.setOutputParameters(op1OutputParameters); + + TNodeType nodeType = f.createTNodeType(); + nodeType.setName("test"); + nodeType.setTargetNamespace("http://asd.com"); + + Generator gen = new Generator(tinterface, "org.opentosca.ia", new URL("http://asd.com"), "testname", Test.WORKING_DIR.toFile()); + File generateProject = gen.generateProject(); + System.out.println(generateProject); + } + + @org.junit.Test + public void testNoParams() throws MalformedURLException { + ObjectFactory f = new ObjectFactory(); + + TInterface tinterface = f.createTInterface(); + tinterface.setName("TestNoParams"); + + TOperation opIn = f.createTOperation(); + opIn.setName("OpNoParams"); + tinterface.getOperation().add(opIn); + + TNodeType nodeType = f.createTNodeType(); + nodeType.setName("test"); + nodeType.setTargetNamespace("http://asd.com"); + + Generator gen = new Generator(tinterface, "org.opentosca.ia", new URL("http://asd.com"), "testname", Test.WORKING_DIR.toFile()); + File generateProject = gen.generateProject(); + System.out.println(generateProject); + } + +} diff --git a/winery/org.eclipse.winery.highlevelrestapi/.gitignore b/winery/org.eclipse.winery.highlevelrestapi/.gitignore new file mode 100644 index 0000000..948b942 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/.gitignore @@ -0,0 +1,10 @@ +.classpath +/.gradle +.settings +.project +/.sonar +/bin +/build +sonar-project.properties +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.highlevelrestapi/LICENSE-ASL.txt b/winery/org.eclipse.winery.highlevelrestapi/LICENSE-ASL.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/LICENSE-ASL.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.highlevelrestapi/LICENSE-EPL.txt b/winery/org.eclipse.winery.highlevelrestapi/LICENSE-EPL.txt new file mode 100644 index 0000000..5d80026 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/LICENSE-EPL.txt @@ -0,0 +1,227 @@ +Eclipse Public License - v 1.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF + THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and + are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by such + Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include additions to the Program which: (i) are + separate modules of software distributed in conjunction with the + Program under their own license agreement, and (ii) are not derivative + works of the Program. + + "Contributor" means any person or entity that distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement, + including all Contributors. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. This patent license shall + apply to the combination of the Contribution and the Program if, at the + time the Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other combinations + which include the Contribution. No hardware per se is licensed + hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility to + secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow Recipient + to distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + + 3. REQUIREMENTS + + A Contributor may choose to distribute the Program in object code form + under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or conditions + of title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software exchange. + + When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + + Contributors may not remove or alter any copyright notices contained + within the Program. + + Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the + Indemnified Contributor to the extent caused by the acts or omissions + of such Commercial Contributor in connection with its distribution of + the Program in a commercial product offering. The obligations in this + section do not apply to any claims or Losses relating to any actual or + alleged intellectual property infringement. In order to qualify, an + Indemnified Contributor must: a) promptly notify the Commercial + Contributor in writing of such claim, and b) allow the Commercial + Contributor to control, and cooperate with the Commercial Contributor + in, the defense and any related settlement negotiations. The + Indemnified Contributor may participate in any such claim at its own + expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible + for determining the appropriateness of using and distributing the + Program and assumes all risks associated with its exercise of rights + under this Agreement , including but not limited to the risks and costs + of program errors, compliance with applicable laws, damage to or loss + of data, programs or equipment, and unavailability or interruption of + operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity (including + a cross-claim or counterclaim in a lawsuit) alleging that the Program + itself (excluding combinations of the Program with other software or + hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it fails + to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of time + after becoming aware of such noncompliance. If all Recipient's rights + under this Agreement terminate, Recipient agrees to cease use and + distribution of the Program as soon as reasonably practicable. However, + Recipient's obligations under this Agreement and any licenses granted + by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a + distinguishing version number. The Program (including Contributions) + may always be distributed subject to the version of the Agreement under + which it was received. In addition, after a new version of the + Agreement is published, Contributor may elect to distribute the Program + (including its Contributions) under the new version. Except as + expressly stated in Sections 2(a) and 2(b) above, Recipient receives no + rights or licenses to the intellectual property of any Contributor + under this Agreement, whether expressly, by implication, estoppel or + otherwise. All rights in the Program not expressly granted under this + Agreement are reserved. + + This Agreement is governed by the laws of the State of New York and the + intellectual property laws of the United States of America. No party to + this Agreement will bring a legal action under this Agreement more than + one year after the cause of action arose. Each party waives its rights + to a jury trial in any resulting litigation. diff --git a/winery/org.eclipse.winery.highlevelrestapi/README.md b/winery/org.eclipse.winery.highlevelrestapi/README.md new file mode 100644 index 0000000..fa1820b --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/README.md @@ -0,0 +1,8 @@ +This project provides a wrapper around org.apache.commons.httpclient. + +It is independent of Winery itself as Winery uses JAX-RS. +The generated implementation artifacts, however, rely on this package. + +## Build fat JARs +To build a fatJar of the HighLevelRestAPI which also contains all the dependencies use the maven profile fatJar (i.e., run `mvn clean package -P fatJar`). +Maven will create a JAR called `org.eclipse.winery.highlevelrestapi-*-jar-with-dependencies.jar` in `/target`.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.highlevelrestapi/about.html b/winery/org.eclipse.winery.highlevelrestapi/about.html new file mode 100644 index 0000000..070c2de --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/about.html @@ -0,0 +1,117 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<h4>Java Libraries</h4> + +<h5>Apache Commons Codec – Version 1.3</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-codec/">http://commons.apache.org/proper/commons-codec/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons HTTP Client – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://hc.apache.org/httpclient-3.x/">http://hc.apache.org/httpclient-3.x/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Logback Classic – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: jcl-over-slf4j – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.highlevelrestapi/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.highlevelrestapi/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.highlevelrestapi/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.highlevelrestapi/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.highlevelrestapi/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.highlevelrestapi/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.highlevelrestapi/notice.html b/winery/org.eclipse.winery.highlevelrestapi/notice.html new file mode 100644 index 0000000..122ebbc --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/notice.html @@ -0,0 +1,7 @@ +<html> +<body> +<p>All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 and Apache License v2.0 which accompanies this distribution. +The Eclipse Public License is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and the Apache License v2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses.</p> +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.highlevelrestapi/pom.xml b/winery/org.eclipse.winery.highlevelrestapi/pom.xml new file mode 100644 index 0000000..7474246 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/pom.xml @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Tobias Binz - Adds support for building fatJars (including all dependencies) and profile for fatJars + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.winery</groupId> + <version>0.1.7-SNAPSHOT</version> + <artifactId>org.eclipse.winery.highlevelrestapi</artifactId> + <packaging>jar</packaging> + <url>http://www.eclipse.org/winery</url> + <organization> + <name>Eclipse.org - Winery Project</name> + <url>http://www.eclipse.org/winery</url> + </organization> + <issueManagement> + <system>bugzilla</system> + <url>https://bugs.eclipse.org/bugs</url> + </issueManagement> + <inceptionYear>2012</inceptionYear> + <mailingLists> + <mailingList> + <name>Winery Developer List</name> + <post>winery-dev@eclipse.org</post> + <archive>http://dev.eclipse.org/mhonarc/lists/winery-dev</archive> + </mailingList> + </mailingLists> + <licenses> + <license> + <name>Eclipse Public License v1.0</name> + <url>http://www.eclipse.org/legal/epl-v10.html</url> + <distribution>repo</distribution> + <comments>Standard Eclipse Licence</comments> + </license> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + <distribution>repo</distribution> + </license> + </licenses> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <profiles> + <profile> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <id>default</id> + <properties> + <package.fatJar>none</package.fatJar> + </properties> + </profile> + <profile> + <id>fatJar</id> + <properties> + <package.fatJar>package</package.fatJar> + </properties> + </profile> + </profiles> + <dependencies> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <!-- NOTE: "The Commons HttpClient project is now end of life, and is no longer being developed." + See http://hc.apache.org/httpclient-3.x/. New project: http://hc.apache.org/httpcomponents-client-ga/ --> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + <version>3.1</version> + <exclusions> + <!-- provided by jcl-over-slf4j to enable logging via logback --> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.7.6</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + <!-- Generates an additional *-jar-with-dependencies.jar --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.4</version> + <configuration> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + </configuration> + <executions> + <execution> + <id>assemble-all</id> + <phase>${package.fatJar}</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HighLevelRestApi.java b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HighLevelRestApi.java new file mode 100644 index 0000000..376d0da --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HighLevelRestApi.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation + * Kálmán Képes - improvements + *******************************************************************************/ +package org.eclipse.winery.highlevelrestapi; + +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.DeleteMethod; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; + +/** + * This class wraps HTTP-Method functionality and thereby abstracts from low + * level code to simplify the usage. + */ +public class HighLevelRestApi { + + /** + * This method implements the HTTP Put Method + * + * @param uri Resource URI + * @param requestPayload Content which has to be put into the Resource + * @return ResponseCode of HTTP Interaction + */ + @SuppressWarnings("deprecation") + public static HttpResponseMessage Put(String uri, String requestPayload, String acceptHeaderValue) { + + PutMethod method = new PutMethod(uri); + // requestPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + // requestPayload; + + HighLevelRestApi.setAcceptHeader(method, acceptHeaderValue); + method.setRequestBody(requestPayload); + + HttpResponseMessage responseMessage = LowLevelRestApi.executeHttpMethod(method); + + // kill <?xml... in front of response + HighLevelRestApi.cleanResponseBody(responseMessage); + + return responseMessage; + } + + /** + * This method implements the HTTP Post Method + * + * @param uri Resource URI + * @param requestPayload Content which has to be posted into the Resource + * @return ResponseCode of HTTP Interaction + */ + @SuppressWarnings("deprecation") + public static HttpResponseMessage Post(String uri, String requestPayload, String acceptHeaderValue) { + + PostMethod method = null; + if (uri.contains("?")) { + System.out.println("Found query trying to split"); + String[] split = uri.split("\\?"); + System.out.println("Raw URI part: " + split[0]); + System.out.println("Raw Query part: " + split[1]); + method = new PostMethod(split[0]); + method.setQueryString(HighLevelRestApi.createNameValuePairArrayFromQuery(split[1])); + } else { + method = new PostMethod(uri); + ; + } + method.setRequestBody(requestPayload); + HighLevelRestApi.setAcceptHeader(method, acceptHeaderValue); + HttpResponseMessage responseMessage = LowLevelRestApi.executeHttpMethod(method); + HighLevelRestApi.cleanResponseBody(responseMessage); + return responseMessage; + } + + /** + * This method implements the HTTP Get Method + * + * @param uri Resource URI + * @return Content represented by the Resource URI + */ + public static HttpResponseMessage Get(String uri, String acceptHeaderValue) { + System.out.println("Setting URI to: \n"); + System.out.println(uri); + GetMethod method = null; + if (uri.contains("?")) { + System.out.println("Found query trying to split"); + String[] split = uri.split("\\?"); + System.out.println("Raw URI part: " + split[0]); + System.out.println("Raw Query part: " + split[1]); + method = new GetMethod(split[0]); + method.setQueryString(HighLevelRestApi.createNameValuePairArrayFromQuery(split[1])); + } else { + method = new GetMethod(uri); + } + HighLevelRestApi.setAcceptHeader(method, acceptHeaderValue); + HttpResponseMessage responseMessage = LowLevelRestApi.executeHttpMethod(method); + HighLevelRestApi.cleanResponseBody(responseMessage); + return responseMessage; + } + + private static NameValuePair[] createNameValuePairArrayFromQuery(String query) { + // example: + // csarID=Moodle.csar&serviceTemplateID={http://www.example.com/tosca/ServiceTemplates/Moodle}Moodle&nodeTemplateID={http://www.example.com/tosca/ServiceTemplates/Moodle}VmApache + System.out.println("Splitting query: " + query); + String[] pairs = query.trim().split("&"); + NameValuePair[] nameValuePairArray = new NameValuePair[pairs.length]; + int count = 0; + for (String pair : pairs) { + System.out.println("Splitting query pair: " + pair); + String[] keyValue = pair.split("="); + NameValuePair nameValuePair = new NameValuePair(); + System.out.println("Key: " + keyValue[0] + " Value: " + keyValue[1]); + nameValuePair.setName(keyValue[0]); + nameValuePair.setValue(keyValue[1]); + nameValuePairArray[count] = nameValuePair; + count++; + } + return nameValuePairArray; + } + + /** + * This method implements the HTTP Delete Method + * + * @param uri Resource URI + * @return ResponseCode of HTTP Interaction + */ + public static HttpResponseMessage Delete(String uri, String acceptHeaderValue) { + + DeleteMethod method = new DeleteMethod(uri); + HighLevelRestApi.setAcceptHeader(method, acceptHeaderValue); + HttpResponseMessage responseMessage = LowLevelRestApi.executeHttpMethod(method); + HighLevelRestApi.cleanResponseBody(responseMessage); + return responseMessage; + } + + private static void setAcceptHeader(HttpMethodBase method, String value) { + if (!value.equals("")) { + method.setRequestHeader("Accept", value); + } else { + method.setRequestHeader("Accept", "application/xml"); + } + } + + private static void cleanResponseBody(HttpResponseMessage responseMessage) { + System.out.println("ResponseBody: \n"); + System.out.println(responseMessage.getResponseBody()); + // @formatter:off + String temp = responseMessage + .getResponseBody() + .replace( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>", + ""); + // @formatter:on + responseMessage.setResponseBody(temp); + } +} diff --git a/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HttpMethod.java b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HttpMethod.java new file mode 100644 index 0000000..fedd3f0 --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HttpMethod.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.highlevelrestapi; + +/** + * This enum is intended to simplify identifying different HTTP-methods + */ +public enum HttpMethod { + PUT, POST, GET, DELETE +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HttpResponseMessage.java b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HttpResponseMessage.java new file mode 100644 index 0000000..14888af --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/HttpResponseMessage.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.highlevelrestapi; + +/** + */ +public class HttpResponseMessage { + + private int statusCode; + private String responseBody; + + + /** + * @return the statusCode + */ + public int getStatusCode() { + return this.statusCode; + } + + /** + * @param statusCode the statusCode to set + */ + protected void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + /** + * @return the responseBody + */ + public String getResponseBody() { + return this.responseBody; + } + + /** + * @param responseBody the responseBody to set + */ + protected void setResponseBody(String responseBody) { + this.responseBody = responseBody; + } + +} diff --git a/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/LowLevelRestApi.java b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/LowLevelRestApi.java new file mode 100644 index 0000000..a99bb8f --- /dev/null +++ b/winery/org.eclipse.winery.highlevelrestapi/src/main/java/org/eclipse/winery/highlevelrestapi/LowLevelRestApi.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation + * Kálmán Képes - improvements + *******************************************************************************/ +package org.eclipse.winery.highlevelrestapi; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethod; + +/** + * This static-class eases HTTP-method execution by self-managed fault-handling + * and automated Response-information processing + */ +public class LowLevelRestApi { + + // Local HttpClient used for every communication (Singleton implementation) + private static HttpClient httpClient = new HttpClient(); + + + /** + * Executes a passed HttpMethod (Method type is either PUT, POST, GET or + * DELETE) and returns a HttpResponseMessage + * + * @param method Method to execute + * @return HttpResponseMessage which contains all information about the + * execution + */ + public static HttpResponseMessage executeHttpMethod(HttpMethod method) { + + HttpResponseMessage responseMessage = null; + + try { + System.out.println("Method invocation on URI: \n"); + System.out.println(method.getURI().toString()); + // Execute Request + LowLevelRestApi.httpClient.executeMethod(method); + responseMessage = LowLevelRestApi.extractResponseInformation(method); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + + // Release Connection anyway + method.releaseConnection(); + } + + // Extract response information and return + return responseMessage; + } + + /** + * Extracts the response information from an executed HttpMethod + * + * @param method Executed Method + * @return Packaged response information + */ + private static HttpResponseMessage extractResponseInformation(HttpMethod method) { + // Create and return HttpResponseMethod + HttpResponseMessage responseMessage = new HttpResponseMessage(); + responseMessage.setStatusCode(method.getStatusCode()); + try { + responseMessage.setResponseBody(method.getResponseBodyAsString()); + } catch (Exception e) { + e.printStackTrace(); + } + return responseMessage; + + } + +} diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/.gitignore b/winery/org.eclipse.winery.model.csar.toscametafile/.gitignore new file mode 100644 index 0000000..bf3a77d --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/.gitignore @@ -0,0 +1,8 @@ +.classpath +.project +/.settings +build.properties +/bin +/build +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/LICENSE-ASL.txt b/winery/org.eclipse.winery.model.csar.toscametafile/LICENSE-ASL.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/LICENSE-ASL.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/LICENSE-EPL.txt b/winery/org.eclipse.winery.model.csar.toscametafile/LICENSE-EPL.txt new file mode 100644 index 0000000..5d80026 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/LICENSE-EPL.txt @@ -0,0 +1,227 @@ +Eclipse Public License - v 1.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF + THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and + are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by such + Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include additions to the Program which: (i) are + separate modules of software distributed in conjunction with the + Program under their own license agreement, and (ii) are not derivative + works of the Program. + + "Contributor" means any person or entity that distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement, + including all Contributors. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. This patent license shall + apply to the combination of the Contribution and the Program if, at the + time the Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other combinations + which include the Contribution. No hardware per se is licensed + hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility to + secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow Recipient + to distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + + 3. REQUIREMENTS + + A Contributor may choose to distribute the Program in object code form + under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or conditions + of title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software exchange. + + When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + + Contributors may not remove or alter any copyright notices contained + within the Program. + + Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the + Indemnified Contributor to the extent caused by the acts or omissions + of such Commercial Contributor in connection with its distribution of + the Program in a commercial product offering. The obligations in this + section do not apply to any claims or Losses relating to any actual or + alleged intellectual property infringement. In order to qualify, an + Indemnified Contributor must: a) promptly notify the Commercial + Contributor in writing of such claim, and b) allow the Commercial + Contributor to control, and cooperate with the Commercial Contributor + in, the defense and any related settlement negotiations. The + Indemnified Contributor may participate in any such claim at its own + expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible + for determining the appropriateness of using and distributing the + Program and assumes all risks associated with its exercise of rights + under this Agreement , including but not limited to the risks and costs + of program errors, compliance with applicable laws, damage to or loss + of data, programs or equipment, and unavailability or interruption of + operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity (including + a cross-claim or counterclaim in a lawsuit) alleging that the Program + itself (excluding combinations of the Program with other software or + hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it fails + to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of time + after becoming aware of such noncompliance. If all Recipient's rights + under this Agreement terminate, Recipient agrees to cease use and + distribution of the Program as soon as reasonably practicable. However, + Recipient's obligations under this Agreement and any licenses granted + by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a + distinguishing version number. The Program (including Contributions) + may always be distributed subject to the version of the Agreement under + which it was received. In addition, after a new version of the + Agreement is published, Contributor may elect to distribute the Program + (including its Contributions) under the new version. Except as + expressly stated in Sections 2(a) and 2(b) above, Recipient receives no + rights or licenses to the intellectual property of any Contributor + under this Agreement, whether expressly, by implication, estoppel or + otherwise. All rights in the Program not expressly granted under this + Agreement are reserved. + + This Agreement is governed by the laws of the State of New York and the + intellectual property laws of the United States of America. No party to + this Agreement will bring a legal action under this Agreement more than + one year after the cause of action arose. Each party waives its rights + to a jury trial in any resulting litigation. diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/about.html b/winery/org.eclipse.winery.model.csar.toscametafile/about.html new file mode 100644 index 0000000..ba38f45 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/about.html @@ -0,0 +1,92 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<p>The Content includes items that have been sourced from third parties as set out below. If you +did not receive this Content directly from the Eclipse Foundation, the following is provided +for informational purposes only, and you should look to the Redistributor's license for +terms and conditions of use.</p> + +<h4>Java Manifest Parser – Version 2.0.5</h4> +<table> + <tr> + <td>URL</td> + <td><a href="http://ebr.springsource.com/repository/app/bundle/version/detail?name=com.springsource.util.parser.manifest&version=2.0.5.RELEASE">http://ebr.springsource.com/repository/app/bundle/version/detail?name=com.springsource.util.parser.manifest&version=2.0.5.RELEASE</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. The sources do not contain a license file, but each .java file contains an Apache 2.0 license header. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h4>Logback Classic – Version 1.1.1</h4> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual-license. A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a></td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.model.csar.toscametafile/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.model.csar.toscametafile/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.model.csar.toscametafile/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/notice.html b/winery/org.eclipse.winery.model.csar.toscametafile/notice.html new file mode 100644 index 0000000..122ebbc --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/notice.html @@ -0,0 +1,7 @@ +<html> +<body> +<p>All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 and Apache License v2.0 which accompanies this distribution. +The Eclipse Public License is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and the Apache License v2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses.</p> +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/pom.xml b/winery/org.eclipse.winery.model.csar.toscametafile/pom.xml new file mode 100644 index 0000000..d3f4922 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/pom.xml @@ -0,0 +1,82 @@ +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.csar.toscametafile</artifactId> + <version>0.0.4-SNAPSHOT</version> + <packaging>jar</packaging> + <name>Model for TOSCA metafile</name> + <description>This project offers a data model and parsing facility for TOSCA meta files.</description> + <url>http://www.eclipse.org/winery</url> + <organization> + <name>Eclipse.org - Winery Project</name> + <url>http://www.eclipse.org/winery</url> + </organization> + <issueManagement> + <system>bugzilla</system> + <url>https://bugs.eclipse.org/bugs</url> + </issueManagement> + <inceptionYear>2012</inceptionYear> + <mailingLists> + <mailingList> + <name>Winery Developer List</name> + <post>winery-dev@eclipse.org</post> + <archive>http://dev.eclipse.org/mhonarc/lists/winery-dev</archive> + </mailingList> + </mailingLists> + <licenses> + <license> + <name>Eclipse Public License v1.0</name> + <url>http://www.eclipse.org/legal/epl-v10.html</url> + <distribution>repo</distribution> + <comments>Standard Eclipse Licence</comments> + </license> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + <distribution>repo</distribution> + </license> + </licenses> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.3.1</version> + </plugin> + </plugins> + </build> + <repositories> + <repository> + <id>springsource</id> + <url>http://repository.springsource.com/maven/bundles/release/</url> + </repository> + </repositories> + <dependencies> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>com.springsource.util</groupId> + <artifactId>com.springsource.util.parser.manifest</artifactId> + <version>2.0.5.RELEASE</version> + </dependency> + </dependencies> +</project> diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFile.java b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFile.java new file mode 100644 index 0000000..e795631 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFile.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2013 Rene Trefft, Oliver Kopp. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Rene Trefft - initial API and implementation and/or initial documentation + * Oliver Kopp - support for getMimeType(name) + *******************************************************************************/ +package org.eclipse.winery.model.csar.toscametafile; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.springsource.util.parser.manifest.ManifestContents; + +/** + * Provides structured access to the content of a TOSCA meta file.<br /> + * <br /> + * Copyright 2013 IAAS University of Stuttgart <br /> + * <br /> + * + * @author Rene Trefft - rene.trefft@developers.opentosca.org + * + */ +public class TOSCAMetaFile implements Serializable { + + private static final long serialVersionUID = 5636441655503533546L; + + Map<String, String> block0 = new HashMap<String, String>(); + List<Map<String, String>> fileBlocks = new ArrayList<Map<String, String>>(); + + + /** + * Creates a new TOSCA meta file. + * + * @param manifestContent to create from + */ + public TOSCAMetaFile(ManifestContents manifestContent) { + this.block0 = manifestContent.getMainAttributes(); + for (String name : manifestContent.getSectionNames()) { + Map<String, String> fileBlock = new HashMap<String, String>(); + fileBlock.put(TOSCAMetaFileAttributes.NAME, name); + fileBlock.putAll(manifestContent.getAttributesForSection(name)); + this.fileBlocks.add(fileBlock); + } + } + + /** + * + * @return Value of attribute <code>CSAR-Version</code> in block 0. + */ + public String getCSARVersion() { + return this.block0.get(TOSCAMetaFileAttributes.CSAR_VERSION); + } + + /** + * + * @return Value of attribute <code>TOSCA-Meta-Version</code> in block 0. + */ + public String getTOSCAMetaVersion() { + return this.block0.get(TOSCAMetaFileAttributes.TOSCA_META_VERSION); + } + + /** + * + * @return Value of attribute <code>Created-By</code> in block 0. + */ + public String getCreatedBy() { + return this.block0.get(TOSCAMetaFileAttributes.CREATED_BY); + } + + /** + * + * @return Value of attribute <code>Entry-Definitions</code> in block 0 + * (contains relative path to the root TOSCA file in the CSAR). If + * attribute is not specified <code>null</code>. + */ + public String getEntryDefinitions() { + return this.block0.get(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS); + } + + /** + * + * @return Value of attribute <code>Description</code> in block 0 (contains + * description of CSAR). If attribute is not specified + * <code>null</code>. + */ + public String getDescription() { + return this.block0.get(TOSCAMetaFileAttributes.DESCRIPTION); + } + + /** + * + * @return Value of attribute <code>Topology</code> in block 0 (contains + * relative path to topology picture in the CSAR). If attribute is + * not specified <code>null</code>. + */ + public String getTopology() { + return this.block0.get(TOSCAMetaFileAttributes.TOPOLOGY); + } + + /** + * + * @return Block 0 (contains meta data about the CSAR itself). + */ + public Map<String, String> getBlock0() { + return this.block0; + } + + /** + * + * @return File blocks (block 1 to last block; contains meta data of files + * in the CSAR). Every block is a element + * <code>Map<String, String></code> in the returned + * <code>List</code>. + */ + public List<Map<String, String>> getFileBlocks() { + return this.fileBlocks; + } + + /** + * Returns the mime type for the given name + * + * @param name a reference to a file + * @return the mime type associated with the given name, null if no mime + * type was found + */ + public String getMimeType(String name) { + if (name == null) { + throw new IllegalArgumentException("name must not be null"); + } + for (Map<String, String> map : this.getFileBlocks()) { + String storedName = map.get("Name"); + if (name.equals(storedName)) { + // first hit, check whether content-type is stored + String contentType = map.get("Content-Type"); + if (contentType != null) { + // hit - return the found content type + return contentType; + } + } + } + // nothing found + return null; + } + +} diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFileAttributes.java b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFileAttributes.java new file mode 100644 index 0000000..e470416 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFileAttributes.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2013 Rene Trefft. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Rene Trefft - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.winery.model.csar.toscametafile; + +/** + * Predefined attribute names and values of a TOSCA meta file. <br /> + * <br /> + * Copyright 2013 IAAS University of Stuttgart <br /> + * <br /> + * + * @author Rene Trefft - rene.trefft@developers.opentosca.org + * + */ +public class TOSCAMetaFileAttributes { + + // of block 0 + final public static String TOSCA_META_VERSION = "TOSCA-Meta-Version"; + final public static String TOSCA_META_VERSION_VALUE = "1.0"; + final public static String CSAR_VERSION = "CSAR-Version"; + final public static String CSAR_VERSION_VALUE = "1.0"; + final public static String CREATED_BY = "Created-By"; + final public static String ENTRY_DEFINITIONS = "Entry-Definitions"; + final public static String TOPOLOGY = "Topology"; + final public static String DESCRIPTION = "Description"; + + // of blocks > 0 (file blocks) + final public static String NAME = "Name"; + final public static String CONTENT_TYPE = "Content-Type"; + +} diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFileParser.java b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFileParser.java new file mode 100644 index 0000000..c5b7c9d --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/TOSCAMetaFileParser.java @@ -0,0 +1,298 @@ +/******************************************************************************* + * Copyright (c) 2013 Rene Trefft. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Rene Trefft - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.winery.model.csar.toscametafile; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.springsource.util.parser.manifest.ManifestContents; +import com.springsource.util.parser.manifest.ManifestParser; +import com.springsource.util.parser.manifest.ManifestProblem; +import com.springsource.util.parser.manifest.RecoveringManifestParser; + +/** + * Parses and validates a TOSCA meta file.<br /> + * <br /> + * Copyright 2013 IAAS University of Stuttgart <br /> + * <br /> + * + * @author Rene Trefft - rene.trefft@developers.opentosca.org + * + */ +public class TOSCAMetaFileParser { + + final private static Logger LOG = LoggerFactory.getLogger(TOSCAMetaFileParser.class); + + + /** + * Parses and validates the <code>toscaMetaFile</code>.<br /> + * <br /> + * + * @param toscaMetaFile to process + * @return <code>TOSCAMetaFile</code> that gives access to the content of + * the TOSCA meta file. If the given file doesn't exist or is + * invalid <code>null</code>. + */ + public TOSCAMetaFile parse(Path toscaMetaFile) { + + // counts the errors during parsing + int numErrors = 0; + + FileReader reader = null; + ManifestParser parser = null; + ManifestContents manifestContent = null; + TOSCAMetaFile toscaMetaFileContent = null; + + try { + + parser = new RecoveringManifestParser(); + reader = new FileReader(toscaMetaFile.toFile()); + TOSCAMetaFileParser.LOG.debug("Parsing TOSCA meta file \"{}\"...", toscaMetaFile.getFileName().toString()); + manifestContent = parser.parse(reader); + reader.close(); + + for (ManifestProblem problem : parser.getProblems()) { + this.logManifestProblem(problem); + numErrors++; + } + + numErrors += this.validateBlock0(manifestContent); + numErrors += this.validateFileBlocks(manifestContent); + + if (numErrors == 0) { + TOSCAMetaFileParser.LOG.debug("Parsing TOSCA meta file \"{}\" completed without errors. TOSCA meta file is valid.", toscaMetaFile.getFileName().toString()); + toscaMetaFileContent = new TOSCAMetaFile(manifestContent); + } else { + TOSCAMetaFileParser.LOG.error("Parsing TOSCA meta file \"{}\" failed - {} error(s) occured. TOSCA meta file is invalid.", toscaMetaFile.getFileName().toString(), numErrors); + } + + } catch (FileNotFoundException exc) { + TOSCAMetaFileParser.LOG.error("\"{}\" doesn't exist or is not a file.", toscaMetaFile, exc); + } catch (IOException exc) { + TOSCAMetaFileParser.LOG.error("An IO Exception occured.", exc); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException exc) { + TOSCAMetaFileParser.LOG.warn("An IOException occured.", exc); + } + } + } + + return toscaMetaFileContent; + + } + + /** + * Validates block 0 of the TOSCA meta file.<br /> + * <br /> + * Required attributes in block 0: + * <ul> + * <li><code>TOSCA-Meta-Version</code> (value must be <code>1.0</code>)</li> + * <li><code>CSAR-Version</code> (value must be <code>1.0</code>)</li> + * <li><code>Created-By</code></li> + * </ul> + * Optional attributes in block 0: + * <ul> + * <li><code>Entry-Definitions</code></li> + * <li><code>Description</code></li> + * <li><code>Topology</code></li> + * </ul> + * + * Further, arbitrary attributes are also allowed.<br /> + * <br /> + * + * @param mf to validate + * @return Number of errors occurred during validation. + */ + private int validateBlock0(ManifestContents mf) { + + int numErrors = 0; + + String metaFileVersion = null; + String csarVersion = null; + String createdBy = null; + String entryDefinitions = null; + String description = null; + String topology = null; + + Map<String, String> mainAttr = mf.getMainAttributes(); + + metaFileVersion = mainAttr.get(TOSCAMetaFileAttributes.TOSCA_META_VERSION); + + if (metaFileVersion == null) { + this.logAttrMissing(TOSCAMetaFileAttributes.TOSCA_META_VERSION, 0); + numErrors++; + } else if (!(metaFileVersion = metaFileVersion.trim()).equals(TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE)) { + this.logAttrWrongVal(TOSCAMetaFileAttributes.TOSCA_META_VERSION, 0, TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE); + numErrors++; + } + + csarVersion = mainAttr.get(TOSCAMetaFileAttributes.CSAR_VERSION); + + if (csarVersion == null) { + this.logAttrMissing(TOSCAMetaFileAttributes.CSAR_VERSION, 0); + numErrors++; + } else if (!(csarVersion = csarVersion.trim()).equals(TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE)) { + this.logAttrWrongVal(TOSCAMetaFileAttributes.CSAR_VERSION, 0, TOSCAMetaFileAttributes.CSAR_VERSION_VALUE); + numErrors++; + } + + createdBy = mainAttr.get(TOSCAMetaFileAttributes.CREATED_BY); + + if (createdBy == null) { + this.logAttrMissing(TOSCAMetaFileAttributes.CREATED_BY, 0); + numErrors++; + } else if ((createdBy = createdBy.trim()).isEmpty()) { + this.logAttrValEmpty(TOSCAMetaFileAttributes.CREATED_BY, 0); + numErrors++; + } + + entryDefinitions = mainAttr.get(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS); + + if ((entryDefinitions != null) && entryDefinitions.trim().isEmpty()) { + this.logAttrValEmpty(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS, 0); + numErrors++; + } + + description = mainAttr.get(TOSCAMetaFileAttributes.DESCRIPTION); + + if ((description != null) && description.trim().isEmpty()) { + this.logAttrValEmpty(TOSCAMetaFileAttributes.DESCRIPTION, 0); + numErrors++; + } + + topology = mainAttr.get(TOSCAMetaFileAttributes.TOPOLOGY); + + if ((topology != null) && topology.trim().isEmpty()) { + this.logAttrValEmpty(TOSCAMetaFileAttributes.TOPOLOGY, 0); + numErrors++; + } + + return numErrors; + + } + + /** + * Validates the file blocks (block 1 to last block) of the TOSCA meta file.<br /> + * <br /> + * Each file block has the following required attributes: + * <ul> + * <li><code>Name</code></li> + * <li><code>Content-Type</code> (will be checked for correct syntax)</li> + * </ul> + * + * Further, arbitrary attributes are also allowed in a file block.<br /> + * <br /> + * + * @param mf to validate. + * @return Number of errors occurred during validation. + */ + private int validateFileBlocks(ManifestContents mf) { + + int blockNr = 0; + int numErrors = 0; + + String contentType; + + List<String> names = mf.getSectionNames(); + + for (String name : names) { + + blockNr++; + + if ((name != null) && name.trim().isEmpty()) { + this.logAttrValEmpty(name, blockNr); + numErrors++; + } + + Map<String, String> attr = mf.getAttributesForSection(name); + contentType = attr.get(TOSCAMetaFileAttributes.CONTENT_TYPE); + + if (contentType == null) { + this.logAttrMissing(TOSCAMetaFileAttributes.CONTENT_TYPE, blockNr); + numErrors++; + } else if (!contentType.trim().matches("^[-\\w\\+\\.]+/[-\\w\\+\\.]+$")) { + this.logAttrWrongVal(TOSCAMetaFileAttributes.CONTENT_TYPE, blockNr); + numErrors++; + } + + } + + return numErrors; + + } + + /** + * Logs that attribute <code>attributeName</code> in block + * <code>blockNr</code> is missing. + * + * @param attributeName + * @param blockNr + */ + private void logAttrMissing(String attributeName, int blockNr) { + TOSCAMetaFileParser.LOG.warn("Required attribute {} in block {} is missing.", attributeName, blockNr); + } + + /** + * Logs that attribute <code>attributeName</code> in block + * <code>blockNr</code> has an invalid value. Correct is + * <code>correctValue</code>. + * + * @param attributeName + * @param blockNr + * @param correctValue + */ + private void logAttrWrongVal(String attributeName, int blockNr, String correctValue) { + TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has an invalid value. Must be {}.", attributeName, blockNr, correctValue); + } + + /** + * Logs that attribute <code>attributeName</code> in block + * <code>blockNr</code> has an invalid value. + * + * @param attributeName + * @param blockNr + */ + private void logAttrWrongVal(String attributeName, int blockNr) { + TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has an invalid value.", attributeName, blockNr); + } + + /** + * Logs that attribute <code>attributeName</code> in block + * <code>blockNr</code> has an empty value. + * + * @param attributeName + * @param blockNr + */ + private void logAttrValEmpty(String attributeName, int blockNr) { + TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has a empty value.", attributeName, blockNr); + } + + /** + * Logs the ManifestProblem <code>problem</code>. + * + * @param problem + */ + private void logManifestProblem(ManifestProblem problem) { + TOSCAMetaFileParser.LOG.warn(problem.toString()); + } + +} diff --git a/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/package-info.java b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/package-info.java new file mode 100644 index 0000000..c932233 --- /dev/null +++ b/winery/org.eclipse.winery.model.csar.toscametafile/src/main/java/org/eclipse/winery/model/csar/toscametafile/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2013 Rene Trefft. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Rene Trefft - initial API and implementation and/or initial documentation + *******************************************************************************/ + +/** + * This package provides a data model and parsing facility for TOSCA meta files. + */ +package org.eclipse.winery.model.csar.toscametafile;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.selfservice/.gitignore b/winery/org.eclipse.winery.model.selfservice/.gitignore new file mode 100644 index 0000000..bf3a77d --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/.gitignore @@ -0,0 +1,8 @@ +.classpath +.project +/.settings +build.properties +/bin +/build +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.model.selfservice/LICENSE-ASL.txt b/winery/org.eclipse.winery.model.selfservice/LICENSE-ASL.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/LICENSE-ASL.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.model.selfservice/LICENSE-EPL.txt b/winery/org.eclipse.winery.model.selfservice/LICENSE-EPL.txt new file mode 100644 index 0000000..5d80026 --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/LICENSE-EPL.txt @@ -0,0 +1,227 @@ +Eclipse Public License - v 1.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF + THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and + are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by such + Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include additions to the Program which: (i) are + separate modules of software distributed in conjunction with the + Program under their own license agreement, and (ii) are not derivative + works of the Program. + + "Contributor" means any person or entity that distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement, + including all Contributors. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. This patent license shall + apply to the combination of the Contribution and the Program if, at the + time the Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other combinations + which include the Contribution. No hardware per se is licensed + hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility to + secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow Recipient + to distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + + 3. REQUIREMENTS + + A Contributor may choose to distribute the Program in object code form + under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or conditions + of title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software exchange. + + When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + + Contributors may not remove or alter any copyright notices contained + within the Program. + + Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the + Indemnified Contributor to the extent caused by the acts or omissions + of such Commercial Contributor in connection with its distribution of + the Program in a commercial product offering. The obligations in this + section do not apply to any claims or Losses relating to any actual or + alleged intellectual property infringement. In order to qualify, an + Indemnified Contributor must: a) promptly notify the Commercial + Contributor in writing of such claim, and b) allow the Commercial + Contributor to control, and cooperate with the Commercial Contributor + in, the defense and any related settlement negotiations. The + Indemnified Contributor may participate in any such claim at its own + expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible + for determining the appropriateness of using and distributing the + Program and assumes all risks associated with its exercise of rights + under this Agreement , including but not limited to the risks and costs + of program errors, compliance with applicable laws, damage to or loss + of data, programs or equipment, and unavailability or interruption of + operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity (including + a cross-claim or counterclaim in a lawsuit) alleging that the Program + itself (excluding combinations of the Program with other software or + hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it fails + to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of time + after becoming aware of such noncompliance. If all Recipient's rights + under this Agreement terminate, Recipient agrees to cease use and + distribution of the Program as soon as reasonably practicable. However, + Recipient's obligations under this Agreement and any licenses granted + by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a + distinguishing version number. The Program (including Contributions) + may always be distributed subject to the version of the Agreement under + which it was received. In addition, after a new version of the + Agreement is published, Contributor may elect to distribute the Program + (including its Contributions) under the new version. Except as + expressly stated in Sections 2(a) and 2(b) above, Recipient receives no + rights or licenses to the intellectual property of any Contributor + under this Agreement, whether expressly, by implication, estoppel or + otherwise. All rights in the Program not expressly granted under this + Agreement are reserved. + + This Agreement is governed by the laws of the State of New York and the + intellectual property laws of the United States of America. No party to + this Agreement will bring a legal action under this Agreement more than + one year after the cause of action arose. Each party waives its rights + to a jury trial in any resulting litigation. diff --git a/winery/org.eclipse.winery.model.selfservice/about.html b/winery/org.eclipse.winery.model.selfservice/about.html new file mode 100644 index 0000000..37c9eed --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/about.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.selfservice/notice.html b/winery/org.eclipse.winery.model.selfservice/notice.html new file mode 100644 index 0000000..122ebbc --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/notice.html @@ -0,0 +1,7 @@ +<html> +<body> +<p>All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 and Apache License v2.0 which accompanies this distribution. +The Eclipse Public License is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and the Apache License v2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses.</p> +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.selfservice/pom.xml b/winery/org.eclipse.winery.model.selfservice/pom.xml new file mode 100644 index 0000000..844cba9 --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/pom.xml @@ -0,0 +1,90 @@ +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Binz - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.selfservice</artifactId> + <version>0.1.20-SNAPSHOT</version> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <url>http://www.eclipse.org/winery</url> + <organization> + <name>Eclipse.org - Winery Project</name> + <url>http://www.eclipse.org/winery</url> + </organization> + <issueManagement> + <system>bugzilla</system> + <url>https://bugs.eclipse.org/bugs</url> + </issueManagement> + <inceptionYear>2012</inceptionYear> + <mailingLists> + <mailingList> + <name>Winery Developer List</name> + <post>winery-dev@eclipse.org</post> + <archive>http://dev.eclipse.org/mhonarc/lists/winery-dev</archive> + </mailingList> + </mailingLists> + <licenses> + <license> + <name>Eclipse Public License v1.0</name> + <url>http://www.eclipse.org/legal/epl-v10.html</url> + <distribution>repo</distribution> + <comments>Standard Eclipse Licence</comments> + </license> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + <distribution>repo</distribution> + </license> + </licenses> + <build> + <extensions> + <!-- Enabling the use of SFTP --> + <extension> + <groupId>org.apache.maven.wagon</groupId> + <artifactId>wagon-ssh-external</artifactId> + <version>2.5</version> + </extension> + </extensions> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jaxb2-maven-plugin</artifactId> + <version>1.5</version> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>xjc</goal> + </goals> + <configuration> + <schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory> + <packageName>org.eclipse.winery.model.selfservice</packageName> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.selfservice/src/main/resources/SelfServiceModel.xsd b/winery/org.eclipse.winery.model.selfservice/src/main/resources/SelfServiceModel.xsd new file mode 100644 index 0000000..b95e3e1 --- /dev/null +++ b/winery/org.eclipse.winery.model.selfservice/src/main/resources/SelfServiceModel.xsd @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Binz and Uwe Breitenbücher - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<xs:schema xmlns="http://www.eclipse.org/winery/model/selfservice" targetNamespace="http://www.eclipse.org/winery/model/selfservice" + xmlns:tns="http://www.eclipse.org/winery/model/selfservice" xmlns:xs="http://www.w3.org/2001/XMLSchema" + elementFormDefault="qualified" attributeFormDefault="unqualified"> + + <xs:element name="Application"> + <xs:complexType> + <xs:sequence> + <xs:element name="displayName" type="xs:string" /> + + <xs:element name="description" type="xs:string" /> + + <xs:element name="iconUrl" type="xs:string"> + <xs:annotation> + <xs:documentation>Absolute or relative (with respect to the SELFSERVICE-Metadata folder root in the CSAR) URL to load the application icon.</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="imageUrl" type="xs:string"> + <xs:annotation> + <xs:documentation>Absolute or relative (with respect to the SELFSERVICE-Metadata folder root in the CSAR) URL to load the application image for the application's offering details.</xs:documentation> + </xs:annotation> + </xs:element> + + <xs:element name="options"> + <xs:complexType> + <xs:sequence> + <xs:element name="option" type="ApplicationOption" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + </xs:element> + + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:complexType name="ApplicationOption"> + <xs:sequence> + <xs:element name="description" type="xs:string" /> + + <xs:element name="iconUrl" type="xs:anyURI"> + <xs:annotation> + <xs:documentation>Absolute or relative (with respect to the SELFSERVICE-Metadata folder root in the CSAR) URL to load the application icon.</xs:documentation> + </xs:annotation> + </xs:element> + + <xs:element name="planServiceName" type="xs:string" /> + + <xs:element name="planInputMessageUrl" type="xs:string"> + <xs:annotation> + <xs:documentation>Absolute or relative (with respect to the SELFSERVICE-Metadata folder root in the CSAR) URL to load the plan input message to start the build plan.</xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + + <xs:attribute name="id" type="xs:string" use="required" /> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> +</xs:schema>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.tosca/.gitignore b/winery/org.eclipse.winery.model.tosca/.gitignore new file mode 100644 index 0000000..bf3a77d --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/.gitignore @@ -0,0 +1,8 @@ +.classpath +.project +/.settings +build.properties +/bin +/build +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.model.tosca/LICENSE-ASL.txt b/winery/org.eclipse.winery.model.tosca/LICENSE-ASL.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/LICENSE-ASL.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.model.tosca/LICENSE-EPL.txt b/winery/org.eclipse.winery.model.tosca/LICENSE-EPL.txt new file mode 100644 index 0000000..5d80026 --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/LICENSE-EPL.txt @@ -0,0 +1,227 @@ +Eclipse Public License - v 1.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF + THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and + are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by such + Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include additions to the Program which: (i) are + separate modules of software distributed in conjunction with the + Program under their own license agreement, and (ii) are not derivative + works of the Program. + + "Contributor" means any person or entity that distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement, + including all Contributors. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. This patent license shall + apply to the combination of the Contribution and the Program if, at the + time the Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license shall not apply to any other combinations + which include the Contribution. No hardware per se is licensed + hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility to + secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow Recipient + to distribute the Program, it is Recipient's responsibility to acquire + that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + + 3. REQUIREMENTS + + A Contributor may choose to distribute the Program in object code form + under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or conditions + of title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software exchange. + + When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + + Contributors may not remove or alter any copyright notices contained + within the Program. + + Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the + Indemnified Contributor to the extent caused by the acts or omissions + of such Commercial Contributor in connection with its distribution of + the Program in a commercial product offering. The obligations in this + section do not apply to any claims or Losses relating to any actual or + alleged intellectual property infringement. In order to qualify, an + Indemnified Contributor must: a) promptly notify the Commercial + Contributor in writing of such claim, and b) allow the Commercial + Contributor to control, and cooperate with the Commercial Contributor + in, the defense and any related settlement negotiations. The + Indemnified Contributor may participate in any such claim at its own + expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible + for determining the appropriateness of using and distributing the + Program and assumes all risks associated with its exercise of rights + under this Agreement , including but not limited to the risks and costs + of program errors, compliance with applicable laws, damage to or loss + of data, programs or equipment, and unavailability or interruption of + operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity (including + a cross-claim or counterclaim in a lawsuit) alleging that the Program + itself (excluding combinations of the Program with other software or + hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it fails + to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of time + after becoming aware of such noncompliance. If all Recipient's rights + under this Agreement terminate, Recipient agrees to cease use and + distribution of the Program as soon as reasonably practicable. However, + Recipient's obligations under this Agreement and any licenses granted + by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a + distinguishing version number. The Program (including Contributions) + may always be distributed subject to the version of the Agreement under + which it was received. In addition, after a new version of the + Agreement is published, Contributor may elect to distribute the Program + (including its Contributions) under the new version. Except as + expressly stated in Sections 2(a) and 2(b) above, Recipient receives no + rights or licenses to the intellectual property of any Contributor + under this Agreement, whether expressly, by implication, estoppel or + otherwise. All rights in the Program not expressly granted under this + Agreement are reserved. + + This Agreement is governed by the laws of the State of New York and the + intellectual property laws of the United States of America. No party to + this Agreement will bring a legal action under this Agreement more than + one year after the cause of action arose. Each party waives its rights + to a jury trial in any resulting litigation. diff --git a/winery/org.eclipse.winery.model.tosca/about.html b/winery/org.eclipse.winery.model.tosca/about.html new file mode 100644 index 0000000..33325e9 --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/about.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<h4>XSD Files</h4> + +<h5>TOSCA-v1.0.xsd</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://docs.oasis-open.org/tosca/TOSCA/v1.0/os/schemas/">http://docs.oasis-open.org/tosca/TOSCA/v1.0/os/schemas/</a></td> + </tr> + <tr> + <td>License</td> + <td>Copyright (c) OASIS Open 2013. All rights reserved.</td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.tosca/notice.html b/winery/org.eclipse.winery.model.tosca/notice.html new file mode 100644 index 0000000..122ebbc --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/notice.html @@ -0,0 +1,7 @@ +<html> +<body> +<p>All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 and Apache License v2.0 which accompanies this distribution. +The Eclipse Public License is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and the Apache License v2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses.</p> +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.tosca/pom.xml b/winery/org.eclipse.winery.model.tosca/pom.xml new file mode 100644 index 0000000..fedd3b8 --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/pom.xml @@ -0,0 +1,83 @@ +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Binz - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.tosca</artifactId> + <version>0.1.21-SNAPSHOT</version> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <url>http://www.eclipse.org/winery</url> + <organization> + <name>Eclipse.org - Winery Project</name> + <url>http://www.eclipse.org/winery</url> + </organization> + <issueManagement> + <system>bugzilla</system> + <url>https://bugs.eclipse.org/bugs</url> + </issueManagement> + <inceptionYear>2012</inceptionYear> + <mailingLists> + <mailingList> + <name>Winery Developer List</name> + <post>winery-dev@eclipse.org</post> + <archive>http://dev.eclipse.org/mhonarc/lists/winery-dev</archive> + </mailingList> + </mailingLists> + <licenses> + <license> + <name>Eclipse Public License v1.0</name> + <url>http://www.eclipse.org/legal/epl-v10.html</url> + <distribution>repo</distribution> + <comments>Standard Eclipse Licence</comments> + </license> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + <distribution>repo</distribution> + </license> + </licenses> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jaxb2-maven-plugin</artifactId> + <version>1.5</version> + <executions> + <execution> + <phase>generate-sources</phase> + <goals> + <goal>xjc</goal> + </goals> + <configuration> + <schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory> + <!--<schemaFiles>TOSCA-v1.0-cos01.xsd</schemaFiles>--> + <packageName>org.eclipse.winery.model.tosca</packageName> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.model.tosca/src/main/resources/TOSCA-v1.0.xsd b/winery/org.eclipse.winery.model.tosca/src/main/resources/TOSCA-v1.0.xsd new file mode 100644 index 0000000..d467d2f --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/src/main/resources/TOSCA-v1.0.xsd @@ -0,0 +1,792 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Topology and Orchestration Specification for Cloud Applications Version 1.0
+ Committee Specification Draft 08
+ 09 May 2013
+ Copyright (c) OASIS Open 2013. All rights reserved.
+ Source: http://docs.oasis-open.org/tosca/TOSCA/v1.0/csd08/schemas/
+-->
+<xs:schema targetNamespace="http://docs.oasis-open.org/tosca/ns/2011/12" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns="http://docs.oasis-open.org/tosca/ns/2011/12" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http_www.w3.org_2001_xml.xsd"/>
+ <xs:element name="documentation" type="tDocumentation"/>
+ <xs:complexType name="tDocumentation" mixed="true">
+ <xs:sequence>
+ <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="source" type="xs:anyURI"/>
+ <xs:attribute ref="xml:lang"/>
+ </xs:complexType>
+ <xs:complexType name="tExtensibleElements">
+ <xs:sequence>
+ <xs:element ref="documentation" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:complexType name="tImport">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:attribute name="namespace" type="xs:anyURI"/>
+ <xs:attribute name="location" type="xs:anyURI"/>
+ <xs:attribute name="importType" type="importedURI" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:element name="Definitions">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:extension base="tDefinitions"/>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="tDefinitions">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Extensions" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Extension" type="tExtension" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Import" type="tImport" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Types" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="ServiceTemplate" type="tServiceTemplate"/>
+ <xs:element name="NodeType" type="tNodeType"/>
+ <xs:element name="NodeTypeImplementation" type="tNodeTypeImplementation"/>
+ <xs:element name="RelationshipType" type="tRelationshipType"/>
+ <xs:element name="RelationshipTypeImplementation" type="tRelationshipTypeImplementation"/>
+ <xs:element name="RequirementType" type="tRequirementType"/>
+ <xs:element name="CapabilityType" type="tCapabilityType"/>
+ <xs:element name="ArtifactType" type="tArtifactType"/>
+ <xs:element name="ArtifactTemplate" type="tArtifactTemplate"/>
+ <xs:element name="PolicyType" type="tPolicyType"/>
+ <xs:element name="PolicyTemplate" type="tPolicyTemplate"/>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:ID" use="required"/>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="targetNamespace" type="xs:anyURI" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tServiceTemplate">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Tags" type="tTags" minOccurs="0"/>
+ <xs:element name="BoundaryDefinitions" type="tBoundaryDefinitions" minOccurs="0"/>
+ <xs:element name="TopologyTemplate" type="tTopologyTemplate"/>
+ <xs:element name="Plans" type="tPlans" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:ID" use="required"/>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="targetNamespace" type="xs:anyURI"/>
+ <xs:attribute name="substitutableNodeType" type="xs:QName" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tTags">
+ <xs:sequence>
+ <xs:element name="Tag" type="tTag" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tTag">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="value" type="xs:string" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tBoundaryDefinitions">
+ <xs:sequence>
+ <xs:element name="Properties" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##other"/>
+ <xs:element name="PropertyMappings" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="PropertyMapping" type="tPropertyMapping" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PropertyConstraints" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="PropertyConstraint" type="tPropertyConstraint" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Requirements" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Requirement" type="tRequirementRef" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Capabilities" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Capability" type="tCapabilityRef" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Policies" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Policy" type="tPolicy" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Interfaces" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Interface" type="tExportedInterface" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tPropertyMapping">
+ <xs:attribute name="serviceTemplatePropertyRef" type="xs:string" use="required"/>
+ <xs:attribute name="targetObjectRef" type="xs:IDREF" use="required"/>
+ <xs:attribute name="targetPropertyRef" type="xs:string" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tRequirementRef">
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="ref" type="xs:IDREF" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tCapabilityRef">
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="ref" type="xs:IDREF" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tEntityType" abstract="true">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Tags" type="tTags" minOccurs="0"/>
+ <xs:element name="DerivedFrom" minOccurs="0">
+ <xs:complexType>
+ <xs:attribute name="typeRef" type="xs:QName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PropertiesDefinition" minOccurs="0">
+ <xs:complexType>
+ <xs:attribute name="element" type="xs:QName"/>
+ <xs:attribute name="type" type="xs:QName"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:NCName" use="required"/>
+ <xs:attribute name="abstract" type="tBoolean" default="no"/>
+ <xs:attribute name="final" type="tBoolean" default="no"/>
+ <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tEntityTemplate" abstract="true">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Properties" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PropertyConstraints" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="PropertyConstraint" type="tPropertyConstraint" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:ID" use="required"/>
+ <xs:attribute name="type" type="xs:QName" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tNodeTemplate">
+ <xs:complexContent>
+ <xs:extension base="tEntityTemplate">
+ <xs:sequence>
+ <xs:element name="Requirements" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Requirement" type="tRequirement" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Capabilities" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Capability" type="tCapability" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Policies" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Policy" type="tPolicy" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DeploymentArtifacts" type="tDeploymentArtifacts" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="minInstances" type="xs:int" use="optional" default="1"/>
+ <xs:attribute name="maxInstances" use="optional" default="1">
+ <xs:simpleType>
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="xs:nonNegativeInteger">
+ <xs:pattern value="([1-9]+[0-9]*)"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="unbounded"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tTopologyTemplate">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="NodeTemplate" type="tNodeTemplate"/>
+ <xs:element name="RelationshipTemplate" type="tRelationshipTemplate"/>
+ </xs:choice>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tRelationshipType">
+ <xs:complexContent>
+ <xs:extension base="tEntityType">
+ <xs:sequence>
+ <xs:element name="InstanceStates" type="tTopologyElementInstanceStates" minOccurs="0"/>
+ <xs:element name="SourceInterfaces" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="TargetInterfaces" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="ValidSource" minOccurs="0">
+ <xs:complexType>
+ <xs:attribute name="typeRef" type="xs:QName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="ValidTarget" minOccurs="0">
+ <xs:complexType>
+ <xs:attribute name="typeRef" type="xs:QName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tRelationshipTypeImplementation">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Tags" type="tTags" minOccurs="0"/>
+ <xs:element name="DerivedFrom" minOccurs="0">
+ <xs:complexType>
+ <xs:attribute name="relationshipTypeImplementationRef" type="xs:QName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RequiredContainerFeatures" type="tRequiredContainerFeatures" minOccurs="0"/>
+ <xs:element name="ImplementationArtifacts" type="tImplementationArtifacts" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:NCName" use="required"/>
+ <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/>
+ <xs:attribute name="relationshipType" type="xs:QName" use="required"/>
+ <xs:attribute name="abstract" type="tBoolean" use="optional" default="no"/>
+ <xs:attribute name="final" type="tBoolean" use="optional" default="no"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tRelationshipTemplate">
+ <xs:complexContent>
+ <xs:extension base="tEntityTemplate">
+ <xs:sequence>
+ <xs:element name="SourceElement">
+ <xs:complexType>
+ <xs:attribute name="ref" type="xs:IDREF" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="TargetElement">
+ <xs:complexType>
+ <xs:attribute name="ref" type="xs:IDREF" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RelationshipConstraints" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="RelationshipConstraint" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="constraintType" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="own" type="xs:string" use="optional" default="0"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tNodeType">
+ <xs:complexContent>
+ <xs:extension base="tEntityType">
+ <xs:sequence>
+ <xs:element name="RequirementDefinitions" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="RequirementDefinition" type="tRequirementDefinition" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="CapabilityDefinitions" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="CapabilityDefinition" type="tCapabilityDefinition" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="InstanceStates" type="tTopologyElementInstanceStates" minOccurs="0"/>
+ <xs:element name="Interfaces" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tNodeTypeImplementation">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Tags" type="tTags" minOccurs="0"/>
+ <xs:element name="DerivedFrom" minOccurs="0">
+ <xs:complexType>
+ <xs:attribute name="nodeTypeImplementationRef" type="xs:QName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RequiredContainerFeatures" type="tRequiredContainerFeatures" minOccurs="0"/>
+ <xs:element name="ImplementationArtifacts" type="tImplementationArtifacts" minOccurs="0"/>
+ <xs:element name="DeploymentArtifacts" type="tDeploymentArtifacts" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:NCName" use="required"/>
+ <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/>
+ <xs:attribute name="nodeType" type="xs:QName" use="required"/>
+ <xs:attribute name="abstract" type="tBoolean" use="optional" default="no"/>
+ <xs:attribute name="final" type="tBoolean" use="optional" default="no"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tRequirementType">
+ <xs:complexContent>
+ <xs:extension base="tEntityType">
+ <xs:attribute name="requiredCapabilityType" type="xs:QName" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tRequirementDefinition">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Constraints" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Constraint" type="tConstraint" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="requirementType" type="xs:QName" use="required"/>
+ <xs:attribute name="lowerBound" type="xs:int" use="optional" default="1"/>
+ <xs:attribute name="upperBound" use="optional" default="1">
+ <xs:simpleType>
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="xs:nonNegativeInteger">
+ <xs:pattern value="([1-9]+[0-9]*)"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="unbounded"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tRequirement">
+ <xs:complexContent>
+ <xs:extension base="tEntityTemplate">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tCapabilityType">
+ <xs:complexContent>
+ <xs:extension base="tEntityType"/>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tCapabilityDefinition">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Constraints" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Constraint" type="tConstraint" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="capabilityType" type="xs:QName" use="required"/>
+ <xs:attribute name="lowerBound" type="xs:int" use="optional" default="1"/>
+ <xs:attribute name="upperBound" use="optional" default="1">
+ <xs:simpleType>
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="xs:nonNegativeInteger">
+ <xs:pattern value="([1-9]+[0-9]*)"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="unbounded"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tCapability">
+ <xs:complexContent>
+ <xs:extension base="tEntityTemplate">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tArtifactType">
+ <xs:complexContent>
+ <xs:extension base="tEntityType"/>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tArtifactTemplate">
+ <xs:complexContent>
+ <xs:extension base="tEntityTemplate">
+ <xs:sequence>
+ <xs:element name="ArtifactReferences" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="ArtifactReference" type="tArtifactReference" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tDeploymentArtifacts">
+ <xs:sequence>
+ <xs:element name="DeploymentArtifact" type="tDeploymentArtifact" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tDeploymentArtifact">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="artifactType" type="xs:QName" use="required"/>
+ <xs:attribute name="artifactRef" type="xs:QName" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tImplementationArtifacts">
+ <xs:sequence>
+ <xs:element name="ImplementationArtifact" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:extension base="tImplementationArtifact"/>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tImplementationArtifact">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="interfaceName" type="xs:anyURI" use="optional"/>
+ <xs:attribute name="operationName" type="xs:NCName" use="optional"/>
+ <xs:attribute name="artifactType" type="xs:QName" use="required"/>
+ <xs:attribute name="artifactRef" type="xs:QName" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tPlans">
+ <xs:sequence>
+ <xs:element name="Plan" type="tPlan" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="tPlan">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Precondition" type="tCondition" minOccurs="0"/>
+ <xs:element name="InputParameters" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="InputParameter" type="tParameter" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="OutputParameters" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="OutputParameter" type="tParameter" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:choice>
+ <xs:element name="PlanModel">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PlanModelReference">
+ <xs:complexType>
+ <xs:attribute name="reference" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:ID" use="required"/>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="planType" type="xs:anyURI" use="required"/>
+ <xs:attribute name="planLanguage" type="xs:anyURI" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tPolicyType">
+ <xs:complexContent>
+ <xs:extension base="tEntityType">
+ <xs:sequence>
+ <xs:element name="AppliesTo" type="tAppliesTo" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="policyLanguage" type="xs:anyURI" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tPolicyTemplate">
+ <xs:complexContent>
+ <xs:extension base="tEntityTemplate">
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tAppliesTo">
+ <xs:sequence>
+ <xs:element name="NodeTypeReference" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="typeRef" type="xs:QName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tPolicy">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:attribute name="policyType" type="xs:QName" use="required"/>
+ <xs:attribute name="policyRef" type="xs:QName" use="optional"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tConstraint">
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:sequence>
+ <xs:attribute name="constraintType" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tPropertyConstraint">
+ <xs:complexContent>
+ <xs:extension base="tConstraint">
+ <xs:attribute name="property" type="xs:string" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tExtensions">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="Extension" type="tExtension" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tExtension">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:attribute name="namespace" type="xs:anyURI" use="required"/>
+ <xs:attribute name="mustUnderstand" type="tBoolean" use="optional" default="yes"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tParameter">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="type" type="xs:string" use="required"/>
+ <xs:attribute name="required" type="tBoolean" use="optional" default="yes"/>
+ </xs:complexType>
+ <xs:complexType name="tInterface">
+ <xs:sequence>
+ <xs:element name="Operation" type="tOperation" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tExportedInterface">
+ <xs:sequence>
+ <xs:element name="Operation" type="tExportedOperation" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tOperation">
+ <xs:complexContent>
+ <xs:extension base="tExtensibleElements">
+ <xs:sequence>
+ <xs:element name="InputParameters" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="InputParameter" type="tParameter" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="OutputParameters" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="OutputParameter" type="tParameter" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:NCName" use="required"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="tExportedOperation">
+ <xs:choice>
+ <xs:element name="NodeOperation">
+ <xs:complexType>
+ <xs:attribute name="nodeRef" type="xs:IDREF" use="required"/>
+ <xs:attribute name="interfaceName" type="xs:anyURI" use="required"/>
+ <xs:attribute name="operationName" type="xs:NCName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="RelationshipOperation">
+ <xs:complexType>
+ <xs:attribute name="relationshipRef" type="xs:IDREF" use="required"/>
+ <xs:attribute name="interfaceName" type="xs:anyURI" use="required"/>
+ <xs:attribute name="operationName" type="xs:NCName" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Plan">
+ <xs:complexType>
+ <xs:attribute name="planRef" type="xs:IDREF" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:NCName" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tCondition">
+ <xs:sequence>
+ <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="expressionLanguage" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tTopologyElementInstanceStates">
+ <xs:sequence>
+ <xs:element name="InstanceState" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="state" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tArtifactReference">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="Include">
+ <xs:complexType>
+ <xs:attribute name="pattern" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Exclude">
+ <xs:complexType>
+ <xs:attribute name="pattern" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ <xs:attribute name="reference" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="tRequiredContainerFeatures">
+ <xs:sequence>
+ <xs:element name="RequiredContainerFeature" type="tRequiredContainerFeature" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="tRequiredContainerFeature">
+ <xs:attribute name="feature" type="xs:anyURI" use="required"/>
+ </xs:complexType>
+ <xs:simpleType name="tBoolean">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="yes"/>
+ <xs:enumeration value="no"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="importedURI">
+ <xs:restriction base="xs:anyURI"/>
+ </xs:simpleType>
+</xs:schema>
diff --git a/winery/org.eclipse.winery.model.tosca/src/main/resources/http_www.w3.org_2001_xml.xsd b/winery/org.eclipse.winery.model.tosca/src/main/resources/http_www.w3.org_2001_xml.xsd new file mode 100644 index 0000000..8807a89 --- /dev/null +++ b/winery/org.eclipse.winery.model.tosca/src/main/resources/http_www.w3.org_2001_xml.xsd @@ -0,0 +1,286 @@ +<?xml version='1.0'?>
+<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns ="http://www.w3.org/1999/xhtml"
+ xml:lang="en">
+
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+ <h1>About the XML namespace</h1>
+
+ <div class="bodytext">
+ <p>
+ This schema document describes the XML namespace, in a form
+ suitable for import by other schema documents.
+ </p>
+ <p>
+ See <a href="http://www.w3.org/XML/1998/namespace.html">
+ http://www.w3.org/XML/1998/namespace.html</a> and
+ <a href="http://www.w3.org/TR/REC-xml">
+ http://www.w3.org/TR/REC-xml</a> for information
+ about this namespace.
+ </p>
+ <p>
+ Note that local names in this namespace are intended to be
+ defined only by the World Wide Web Consortium or its subgroups.
+ The names currently defined in this namespace are listed below.
+ They should not be used with conflicting semantics by any Working
+ Group, specification, or document instance.
+ </p>
+ <p>
+ See further below in this document for more information about <a
+ href="#usage">how to refer to this schema document from your own
+ XSD schema documents</a> and about <a href="#nsversioning">the
+ namespace-versioning policy governing this schema document</a>.
+ </p>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang">
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>lang (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose value
+ is a language code for the natural language of the content of
+ any element; its value is inherited. This name is reserved
+ by virtue of its definition in the XML specification.</p>
+
+ </div>
+ <div>
+ <h4>Notes</h4>
+ <p>
+ Attempting to install the relevant ISO 2- and 3-letter
+ codes as the enumerated possible values is probably never
+ going to be a realistic possibility.
+ </p>
+ <p>
+ See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
+ http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
+ and the IANA language subtag registry at
+ <a href="http://www.iana.org/assignments/language-subtag-registry">
+ http://www.iana.org/assignments/language-subtag-registry</a>
+ for further information.
+ </p>
+ <p>
+ The union allows for the 'un-declaration' of xml:lang with
+ the empty string.
+ </p>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:union memberTypes="xs:language">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value=""/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="space">
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>space (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose
+ value is a keyword indicating what whitespace processing
+ discipline is intended for the content of the element; its
+ value is inherited. This name is reserved by virtue of its
+ definition in the XML specification.</p>
+
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>base (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose value
+ provides a URI to be used as the base for interpreting any
+ relative URIs in the scope of the element on which it
+ appears; its value is inherited. This name is reserved
+ by virtue of its definition in the XML Base specification.</p>
+
+ <p>
+ See <a
+ href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
+ for information about this attribute.
+ </p>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="id" type="xs:ID">
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>id (as an attribute name)</h3>
+ <p>
+ denotes an attribute whose value
+ should be interpreted as if declared to be of type ID.
+ This name is reserved by virtue of its definition in the
+ xml:id specification.</p>
+
+ <p>
+ See <a
+ href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
+ for information about this attribute.
+ </p>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ <xs:attribute ref="xml:id"/>
+ </xs:attributeGroup>
+
+ <xs:annotation>
+ <xs:documentation>
+ <div>
+
+ <h3>Father (in any context at all)</h3>
+
+ <div class="bodytext">
+ <p>
+ denotes Jon Bosak, the chair of
+ the original XML Working Group. This name is reserved by
+ the following decision of the W3C XML Plenary and
+ XML Coordination groups:
+ </p>
+ <blockquote>
+ <p>
+ In appreciation for his vision, leadership and
+ dedication the W3C XML Plenary on this 10th day of
+ February, 2000, reserves for Jon Bosak in perpetuity
+ the XML name "xml:Father".
+ </p>
+ </blockquote>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>
+ <div xml:id="usage" id="usage">
+ <h2><a name="usage">About this schema document</a></h2>
+
+ <div class="bodytext">
+ <p>
+ This schema defines attributes and an attribute group suitable
+ for use by schemas wishing to allow <code>xml:base</code>,
+ <code>xml:lang</code>, <code>xml:space</code> or
+ <code>xml:id</code> attributes on elements they define.
+ </p>
+ <p>
+ To enable this, such a schema must import this schema for
+ the XML namespace, e.g. as follows:
+ </p>
+ <pre>
+ <schema . . .>
+ . . .
+ <import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+ </pre>
+ <p>
+ or
+ </p>
+ <pre>
+ <import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+ </pre>
+ <p>
+ Subsequently, qualified reference to any of the attributes or the
+ group defined below will have the desired effect, e.g.
+ </p>
+ <pre>
+ <type . . .>
+ . . .
+ <attributeGroup ref="xml:specialAttrs"/>
+ </pre>
+ <p>
+ will define a type which will schema-validate an instance element
+ with any of those attributes.
+ </p>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>
+ <div id="nsversioning" xml:id="nsversioning">
+ <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
+ <div class="bodytext">
+ <p>
+ In keeping with the XML Schema WG's standard versioning
+ policy, this schema document will persist at
+ <a href="http://www.w3.org/2009/01/xml.xsd">
+ http://www.w3.org/2009/01/xml.xsd</a>.
+ </p>
+ <p>
+ At the date of issue it can also be found at
+ <a href="http://www.w3.org/2001/xml.xsd">
+ http://www.w3.org/2001/xml.xsd</a>.
+ </p>
+ <p>
+ The schema document at that URI may however change in the future,
+ in order to remain compatible with the latest version of XML
+ Schema itself, or with the XML namespace itself. In other words,
+ if the XML Schema or XML namespaces change, the version of this
+ document at <a href="http://www.w3.org/2001/xml.xsd">
+ http://www.w3.org/2001/xml.xsd
+ </a>
+ will change accordingly; the version at
+ <a href="http://www.w3.org/2009/01/xml.xsd">
+ http://www.w3.org/2009/01/xml.xsd
+ </a>
+ will not change.
+ </p>
+ <p>
+ Previous dated (and unchanging) versions of this schema
+ document are at:
+ </p>
+ <ul>
+ <li><a href="http://www.w3.org/2009/01/xml.xsd">
+ http://www.w3.org/2009/01/xml.xsd</a></li>
+ <li><a href="http://www.w3.org/2007/08/xml.xsd">
+ http://www.w3.org/2007/08/xml.xsd</a></li>
+ <li><a href="http://www.w3.org/2004/10/xml.xsd">
+ http://www.w3.org/2004/10/xml.xsd</a></li>
+ <li><a href="http://www.w3.org/2001/03/xml.xsd">
+ http://www.w3.org/2001/03/xml.xsd</a></li>
+ </ul>
+ </div>
+ </div>
+ </xs:documentation>
+ </xs:annotation>
+
+</xs:schema>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository.client/.gitignore b/winery/org.eclipse.winery.repository.client/.gitignore new file mode 100644 index 0000000..3576cf9 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/.gitignore @@ -0,0 +1,14 @@ +.classpath +/.gradle +.project +.settings/org.eclipse.core.resources.prefs +.settings/org.eclipse.jdt.core.prefs +.settings/org.eclipse.m2e.core.prefs +.settings/org.eclipse.wst.common.component +.settings/org.eclipse.wst.common.project.facet.core.xml +.settings/org.eclipse.wst.validation.prefs +/.sonar +/bin +/build +/src/main/resources/rebel.xml +/target diff --git a/winery/org.eclipse.winery.repository.client/README.md b/winery/org.eclipse.winery.repository.client/README.md new file mode 100644 index 0000000..b530bfa --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/README.md @@ -0,0 +1,5 @@ +This project provides a Java client to a Winery repository. + +## Build fat JARs +To build a fatJar of the repository client which also contains all the dependencies use the maven profile fatJar (i.e., run `mvn clean package -P fatJar`). +Maven will create a JAR called `org.eclipse.winery.repository.client-*-jar-with-dependencies.jar` in `/target`.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository.client/about.html b/winery/org.eclipse.winery.repository.client/about.html new file mode 100644 index 0000000..9fe8131 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/about.html @@ -0,0 +1,286 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<h4>Java Libraries</h4> + +<h5>Apache Commons Configuration – Version 1.9</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-configuration/">http://commons.apache.org/proper/commons-configuration/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons IO – Version 2.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-io/">http://commons.apache.org/proper/commons-io/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang – Version 2.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang3 – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-annotations – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-annotations">https://github.com/FasterXML/jackson-annotations</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> + <tr> + <td>Note</td> + <td>The license was explicitly added in version 2.2.3 and 2.3.0. See <a href="https://github.com/FasterXML/jackson-annotations/issues/14">Issue #14</a> and <a href="https://github.com/FasterXML/jackson-annotations/blob/master/src/main/resources/META-INF/LICENSE">LICENSE in the source repository</a>.</td> + </tr> +</table> + +<h5>jackson-core – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-core">https://github.com/FasterXML/jackson-core</a> and <a href="http://wiki.fasterxml.com/JacksonHome">http://wiki.fasterxml.com/JacksonHome</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-databind – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-databind">https://github.com/FasterXML/jackson-databind</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-jaxrs-base – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base">https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-jaxrs-json-provider – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/json">https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/json</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-module-jaxb-annotations – Version 2.3.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-module-jaxb-annotations">https://github.com/FasterXML/jackson-module-jaxb-annotations</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a>. + The license is added via the <a href="https://github.com/FasterXML/oss-parent">oss-parent</a> project.</td> + </tr> +</table> + +<h5>Jersey Client – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Jersey Core – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception. A copy of the license is available at <a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a></td> + </tr> +</table> + +<h5>JSP Standard Tag Library – Version 1.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://jstl.java.net/">https://jstl.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception. A copy of the license is available at <a href="https://jstl.java.net/license.html" target="_blank">https://jstl.java.net/license.html</a></td> + </tr> +</table> + +<h5>Logback Classic – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual-license. A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a></td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual-license. A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: jcl-over-slf4j – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.common – ${project.version}</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.tosca – Version 0.1.20</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h4>XSD Files</h4> + +<h5>TOSCA-v1.0.xsd</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://docs.oasis-open.org/tosca/TOSCA/v1.0/os/schemas/">http://docs.oasis-open.org/tosca/TOSCA/v1.0/os/schemas/</a></td> + </tr> + <tr> + <td>License</td> + <td>Copyright (c) OASIS Open 2013. All rights reserved.</td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository.client/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.repository.client/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.repository.client/about_files/CDDL-v1.1.txt b/winery/org.eclipse.winery.repository.client/about_files/CDDL-v1.1.txt new file mode 100644 index 0000000..7cc8719 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/about_files/CDDL-v1.1.txt @@ -0,0 +1,129 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL - Version 1.1) +1. Definitions. + + 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + + 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + + 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + + 1.4. “Executable” means the Covered Software in any form other than Source Code. + + 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + + 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + + 1.7. “License” means this document. + + 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + + 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + + 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + + 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository.client/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.repository.client/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.repository.client/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.repository.client/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository.client/pom.xml b/winery/org.eclipse.winery.repository.client/pom.xml new file mode 100644 index 0000000..b6a6c91 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/pom.xml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Unger - initial API and implementation and/or initial documentation + * Tobias Binz - Adds support for building fatJars (including all dependencies) and profile for fatJars + * Oliver Kopp - cleanup + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.winery</groupId> + <artifactId>winery</artifactId> + <version>0.1.37-SNAPSHOT</version> + </parent> + <artifactId>org.eclipse.winery.repository.client</artifactId> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <profiles> + <profile> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <id>default</id> + <properties> + <package.fatJar>none</package.fatJar> + </properties> + </profile> + <profile> + <id>fatJar</id> + <properties> + <package.fatJar>package</package.fatJar> + </properties> + </profile> + </profiles> + <dependencies> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.2.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.7.6</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.tosca</artifactId> + <version>0.1.21-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-core</artifactId> + <version>1.17</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.common</artifactId> + <version>0.1.37-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.2.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + <version>1.17</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>commons-configuration</groupId> + <artifactId>commons-configuration</artifactId> + <version>1.9</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <!-- use jackson-jaxrs-json-provider instead of jersey-json as suggested by http://stackoverflow.com/a/17006866/873282 --> + <dependency> + <groupId>com.fasterxml.jackson.jaxrs</groupId> + <artifactId>jackson-jaxrs-json-provider</artifactId> + <version>2.2.2</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.16</version> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + <!-- Generates an additional *-jar-with-dependencies.jar --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.4</version> + <configuration> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + </configuration> + <executions> + <execution> + <id>assemble-all</id> + <phase>${package.fatJar}</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/winery/org.eclipse.winery.repository.client/src/main/java/META-INF/MANIFEST.MF b/winery/org.eclipse.winery.repository.client/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..254272e --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/IWineryRepositoryClient.java b/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/IWineryRepositoryClient.java new file mode 100644 index 0000000..f53aca9 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/IWineryRepositoryClient.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.client; + +import org.eclipse.winery.common.interfaces.IWineryRepository; + +public interface IWineryRepositoryClient extends IWineryRepository { + + /** + * Adds an URI to the list of known repositories + * + * SIDE EFFECT: If currently no primary repository is defined, the given + * repository is used as primary repository + * + * @param uri the URI of the repository + */ + void addRepository(String uri); + + /** + * Get the currently defined primary repository + */ + String getPrimaryRepository(); + + /** + * Sets the primary repository + * + * SIDE EFFECT: If the repository is not known as general repository (via + * addRepository), the given repository is added to the list of known + * repositories + * + * @param uri + */ + void setPrimaryRepository(String uri); + + /** + * Checks whether the primary repository is available to be used. Typically, + * this method should return "true". In case of network or server failures, + * the result is "false". Note that the availability may change over time + * and also a repository might become unavailable during querying it. + * + * This method also returns "false" if no primary repository is set. For + * instance, this is the case of no repository is registered at the client. + * + * @return true if the repository is reachable over network, false otherwise + */ + boolean primaryRepositoryAvailable(); +} diff --git a/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/WineryRepositoryClient.java b/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/WineryRepositoryClient.java new file mode 100644 index 0000000..216c623 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/WineryRepositoryClient.java @@ -0,0 +1,746 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.client; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.beans.NamespaceIdOptionalName; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.IdUtil; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.interfaces.QNameAlreadyExistsException; +import org.eclipse.winery.common.interfaces.QNameWithName; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TDefinitions; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory; +import com.sun.jersey.client.urlconnection.URLConnectionClientHandler; +import com.sun.jersey.core.util.MultivaluedMapImpl; + +public final class WineryRepositoryClient implements IWineryRepositoryClient { + + private static final Logger logger = LoggerFactory.getLogger(WineryRepositoryClient.class); + + // switch off validation, currently causes more trouble than it brings + private static final boolean VALIDATING = false; + + private final Collection<String> knownURIs = new HashSet<String>(); + private final Collection<WebResource> repositoryResources = new HashSet<WebResource>(); + private final Client client; + private final ObjectMapper mapper = new ObjectMapper(); + + private final Map<Class<? extends TEntityType>, Map<QName, TEntityType>> entityTypeDataCache; + + private final Map<GenericId, String> nameCache; + private static final int MAX_NAME_CACHE_SIZE = 1000; + + private String primaryRepository = null; + private WebResource primaryWebResource = null; + + // thread-safe JAXB as inspired by https://jaxb.java.net/guide/Performance_and_thread_safety.html + // The other possibility: Each subclass sets JAXBContext.newInstance(theSubClass.class); in its static {} part. + // This seems to be more complicated than listing all subclasses in initContext + public final static JAXBContext context = WineryRepositoryClient.initContext(); + + // schema aware document builder + private final DocumentBuilder toscaDocumentBuilder; + + + // taken from http://stackoverflow.com/a/15253142/873282 + private static class ConnectionFactory implements HttpURLConnectionFactory { + + Proxy proxy; + + + private void initializeProxy() { + this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8888)); + } + + @Override + public HttpURLConnection getHttpURLConnection(URL url) throws IOException { + this.initializeProxy(); + return (HttpURLConnection) url.openConnection(this.proxy); + } + } + + + /** + * Creates the client without the use of any proxy + */ + public WineryRepositoryClient() { + this(false); + } + + /** + * @param useProxy if a debugging proxy should be used + * + * @throws IllegalStateException if DOM parser could not be created + */ + public WineryRepositoryClient(boolean useProxy) { + ClientConfig clientConfig = new DefaultClientConfig(); + clientConfig.getClasses().add(JacksonJsonProvider.class); + if (useProxy) { + URLConnectionClientHandler ch = new URLConnectionClientHandler(new ConnectionFactory()); + this.client = new Client(ch, clientConfig); + } else { + this.client = Client.create(clientConfig); + } + + this.entityTypeDataCache = new HashMap<>(); + this.nameCache = new HashMap<>(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + if (WineryRepositoryClient.VALIDATING) { + factory.setValidating(true); + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema; + URL resource = this.getClass().getResource("/TOSCA-v1.0.xsd"); + try { + schema = schemaFactory.newSchema(resource); + } catch (SAXException e) { + throw new IllegalStateException("Schema could not be initalized", e); + } + factory.setSchema(schema); + } + try { + this.toscaDocumentBuilder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new IllegalStateException("document builder could not be initalized", e); + } + /* + TODO: include this somehow - in the case of VALIDATING + + Does not work with TTopolgoyTemplate as this is not allowed in the root of an XML document + this.toscaDocumentBuilder.setErrorHandler(new ErrorHandler() { + + @Override + public void warning(SAXParseException arg0) throws SAXException { + throw arg0; + } + + @Override + public void fatalError(SAXParseException arg0) throws SAXException { + throw arg0; + } + + @Override + public void error(SAXParseException arg0) throws SAXException { + throw arg0; + } + }); + */ + } + + private static JAXBContext initContext() { + // code copied+adapted from JAXBSupport + + JAXBContext context; + try { + // For winery classes, eventually the package+jaxb.index method could be better. See http://stackoverflow.com/a/3628525/873282 + // @formatter:off + context = JAXBContext.newInstance( + TDefinitions.class, + WinerysPropertiesDefinition.class); + // @formatter:on + } catch (JAXBException e) { + WineryRepositoryClient.logger.error("Could not initialize JAXBContext", e); + throw new IllegalStateException(e); + } + return context; + } + + /** + * Creates a marshaller + * + * @throws IllegalStateException if marshaller could not be instantiated + */ + private static Marshaller createMarshaller() { + // code copied+adapted from JAXBSupport + Marshaller m; + try { + m = WineryRepositoryClient.context.createMarshaller(); + // pretty printed output is required as the XML is sent 1:1 to the browser for editing + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + // not possible here: m.setProperty("com.sun.xml.bind.namespacePrefixMapper", JAXBSupport.prefixMapper); + } catch (JAXBException e) { + WineryRepositoryClient.logger.error("Could not instantiate marshaller", e); + throw new IllegalStateException(e); + } + return m; + } + + /** + * Creates a unmarshaller + * + * @throws IllegalStateException if unmarshaller could not be instantiated + */ + private static Unmarshaller createUnmarshaller() { + Unmarshaller um; + try { + um = WineryRepositoryClient.context.createUnmarshaller(); + } catch (JAXBException e) { + WineryRepositoryClient.logger.error("Could not instantiate unmarshaller", e); + throw new IllegalStateException(e); + } + return um; + } + + /*** methods directly from IWineryRepositoryClient ***/ + + /** + * {@inheritDoc} + */ + @Override + public void addRepository(String uri) { + if (this.knownURIs.add(uri)) { + // URI is not already known, add a new resource + WebResource wr = this.client.resource(uri); + this.repositoryResources.add(wr); + if (this.primaryRepository == null) { + this.primaryRepository = uri; + this.primaryWebResource = wr; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getPrimaryRepository() { + return this.primaryRepository; + } + + /** + * {@inheritDoc} + */ + @Override + public void setPrimaryRepository(String uri) { + this.addRepository(uri); + // now we are sure that a web resource for the uri exists + this.primaryRepository = uri; + // Update the reference to the primaryWebResource + // The appropriate resource has been created via + // this.addRepository(uri); + for (WebResource wr : this.repositoryResources) { + if (wr.getURI().equals(uri)) { + this.primaryWebResource = wr; + break; + } + } + assert (this.primaryWebResource != null); + } + + /*** methods directly from IWineryRepository ***/ + + /** + * {@inheritDoc} + */ + @Override + public SortedSet<String> getNamespaces() { + SortedSet<String> res = new TreeSet<String>(); + for (WebResource wr : this.repositoryResources) { + WebResource namespacesResource = wr.path("admin").path("namespaces"); + + // this could be parsed using JAXB + // (http://jersey.java.net/nonav/documentation/latest/json.html), + // but we are short in time, so we do a quick hack + String nsList = namespacesResource.accept(MediaType.APPLICATION_JSON).get(String.class); + WineryRepositoryClient.logger.trace(nsList); + List<String> nsListList; + try { + nsListList = this.mapper.readValue(nsList, new TypeReference<List<String>>() { + }); + } catch (Exception e) { + WineryRepositoryClient.logger.error(e.getMessage(), e); + continue; + } + res.addAll(nsListList); + } + return res; + } + + /** + * Base method for getQNameListOfAllTypes and getAllTypes. + */ + private <T extends TExtensibleElements> Map<WebResource, List<NamespaceIdOptionalName>> getWRtoNamespaceAndIdListMapOfAllTypes(String path) { + Map<WebResource, List<NamespaceIdOptionalName>> res = new HashMap<WebResource, List<NamespaceIdOptionalName>>(); + for (WebResource wr : this.repositoryResources) { + WebResource componentListResource = wr.path(path); + + // this could be parsed using JAXB + // (http://jersey.java.net/nonav/documentation/latest/json.html), + // but we are short in time, so we do a quick hack + // The result also contains the optional name + String idList = componentListResource.accept(MediaType.APPLICATION_JSON).get(String.class); + WineryRepositoryClient.logger.trace(idList); + List<NamespaceIdOptionalName> nsAndIdList; + try { + nsAndIdList = this.mapper.readValue(idList, new TypeReference<List<NamespaceIdOptionalName>>() { + }); + } catch (Exception e) { + WineryRepositoryClient.logger.error(e.getMessage(), e); + continue; + } + res.put(wr, nsAndIdList); + } + return res; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName(GenericId id) { + if (this.nameCache.containsKey(id)) { + return this.nameCache.get(id); + } + + String name = null; + for (WebResource wr : this.repositoryResources) { + String pathFragment = IdUtil.getURLPathFragment(id); + WebResource resource = wr.path(pathFragment).path("name"); + ClientResponse response = resource.accept(MediaType.TEXT_PLAIN_TYPE).get(ClientResponse.class); + if (response.getClientResponseStatus() == ClientResponse.Status.OK) { + name = response.getEntity(String.class); + // break loop as the first match is the final result + break; + } + } + // if all resources did not return "OK", "null" is returned + + if (name != null) { + if (this.nameCache.size() > WineryRepositoryClient.MAX_NAME_CACHE_SIZE) { + // if cache grew too large, clear it. + this.nameCache.clear(); + } + this.nameCache.put(id, name); + } + + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public <T extends TEntityType> List<QName> getQNameListOfAllTypes(Class<T> className) { + String path = Util.getURLpathFragmentForCollection(className); + Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this.getWRtoNamespaceAndIdListMapOfAllTypes(path); + Collection<List<NamespaceIdOptionalName>> namespaceAndIdListCollection = wRtoNamespaceAndIdListMapOfAllTypes.values(); + List<QName> res = new ArrayList<QName>(namespaceAndIdListCollection.size()); + for (List<NamespaceIdOptionalName> namespaceAndIdList : namespaceAndIdListCollection) { + for (NamespaceIdOptionalName namespaceAndId : namespaceAndIdList) { + QName qname = new QName(namespaceAndId.getNamespace(), namespaceAndId.getId()); + res.add(qname); + } + } + return res; + } + + /** + * Fetches java objects at a given URL + * + * @param path the path to use. E.g., "nodetypes" for node types, ... + * @param className the class of the expected return type. May be + * TDefinitions or TEntityType. TDefinitions the mode is that the + * import statement are recursively resolved and added to the + * returned Defintitions elment + */ + // we convert an object to T if it T is definitions + // does not work without compiler error + @SuppressWarnings("unchecked") + private <T extends TExtensibleElements> Collection<T> getAllTypes(String path, Class<T> className) { + Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this.getWRtoNamespaceAndIdListMapOfAllTypes(path); + // now we now all QNames. We have to fetch the full content now + + Collection<T> res = new LinkedList<T>(); + for (WebResource wr : wRtoNamespaceAndIdListMapOfAllTypes.keySet()) { + WebResource componentListResource = wr.path(path); + + // go through all ids and fetch detailed information on each + // type + + for (NamespaceIdOptionalName nsAndId : wRtoNamespaceAndIdListMapOfAllTypes.get(wr)) { + TDefinitions definitions = WineryRepositoryClient.getDefinitions(componentListResource, nsAndId.getNamespace(), nsAndId.getId()); + if (definitions == null) { + // try next one + continue; + } + + T result; + + if (TDefinitions.class.equals(className)) { + // mode: complete definitions + result = (T) definitions; + } else { + // mode: only the nested element + // convention: first element in list is the element we look for + if (definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().isEmpty()) { + result = null; + WineryRepositoryClient.logger.error("Type {}/{} was found, but did not return any data", nsAndId.getNamespace(), nsAndId.getId()); + } else { + WineryRepositoryClient.logger.trace("Probably found valid data for {}/{}", nsAndId.getNamespace(), nsAndId.getId()); + result = (T) definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + + this.cache((TEntityType) result, new QName(nsAndId.getNamespace(), nsAndId.getId())); + } + } + + // TODO: if multiple repositories are used, the new element + // should be put "sorted" into the list. This could be done by + // add(parsedResult, index), where index is calculated by + // incrementing index as long as the current element is smaller + // than the element to insert. + if (result != null) { + res.add(result); + } + } + } + return res; + } + + /** + * Caches the TEntityType data of a QName to avoid multiple get requests + * + * NOT thread safe + */ + private void cache(TEntityType et, QName qName) { + Map<QName, TEntityType> map; + if ((map = this.entityTypeDataCache.get(et.getClass())) == null) { + map = new HashMap<>(); + this.entityTypeDataCache.put(et.getClass(), map); + } else { + // quick hack to keep cache size small + if (map.size() > 1000) { + map.clear(); + } + } + map.put(qName, et); + } + + private static WebResource getTopologyTemplateWebResource(WebResource base, QName serviceTemplate) { + String nsEncoded = Util.DoubleURLencode(serviceTemplate.getNamespaceURI()); + String idEncoded = Util.DoubleURLencode(serviceTemplate.getLocalPart()); + WebResource res = base.path("servicetemplates").path(nsEncoded).path(idEncoded).path("topologytemplate"); + return res; + } + + /** + * {@inheritDoc} + */ + @Override + public Collection<QNameWithName> getListOfAllInstances(Class<? extends TOSCAComponentId> clazz) { + // inspired by getQNameListOfAllTypes + String path = Util.getRootPathFragment(clazz); + Map<WebResource, List<NamespaceIdOptionalName>> wRtoNamespaceAndIdListMapOfAllTypes = this.getWRtoNamespaceAndIdListMapOfAllTypes(path); + Collection<List<NamespaceIdOptionalName>> namespaceAndIdListCollection = wRtoNamespaceAndIdListMapOfAllTypes.values(); + List<QNameWithName> res = new ArrayList<QNameWithName>(namespaceAndIdListCollection.size()); + + for (List<NamespaceIdOptionalName> namespaceAndIdList : namespaceAndIdListCollection) { + for (NamespaceIdOptionalName namespaceAndId : namespaceAndIdList) { + QNameWithName qn = new QNameWithName(); + qn.qname = new QName(namespaceAndId.getNamespace(), namespaceAndId.getId()); + qn.name = namespaceAndId.getName(); + res.add(qn); + } + } + return res; + } + + /** + * {@inheritDoc} + */ + @Override + public <T extends TEntityType> Collection<T> getAllTypes(Class<T> c) { + String urlPathFragment = Util.getURLpathFragmentForCollection(c); + Collection<T> allTypes = this.getAllTypes(urlPathFragment, c); + return allTypes; + } + + @Override + @SuppressWarnings("unchecked") + public <T extends TEntityType> T getType(QName qname, Class<T> type) { + T res = null; + if (this.entityTypeDataCache.containsKey(type)) { + Map<QName, TEntityType> map = this.entityTypeDataCache.get(type); + if (map.containsKey(qname)) { + res = (T) map.get(qname); + } + } + + if (res == null) { + // not yet seen, try to fetch resource + + for (WebResource wr : this.repositoryResources) { + String path = Util.getURLpathFragmentForCollection(type); + + TDefinitions definitions = WineryRepositoryClient.getDefinitions(wr, path, qname.getNamespaceURI(), qname.getLocalPart()); + + if (definitions == null) { + // in case of an error, just try the next one + continue; + } + + res = (T) definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + this.cache(res, qname); + break; + } + } + + return res; + } + + /** + * Tries to retrieve a TDefinitions from the given resource / encoded(ns) / + * encoded(localPart) + * + * @return null if 404 or other error + */ + private static TDefinitions getDefinitions(WebResource wr, String path, String ns, String localPart) { + WebResource componentListResource = wr.path(path); + return WineryRepositoryClient.getDefinitions(componentListResource, ns, localPart); + } + + /** + * Tries to retrieve a TDefinitions from the given resource / encoded(ns) / + * encoded(localPart) + * + * @return null if 404 or other error + */ + private static TDefinitions getDefinitions(WebResource componentListResource, String ns, String localPart) { + // we need double encoding as the client decodes the URL once + String nsEncoded = Util.DoubleURLencode(ns); + String idEncoded = Util.DoubleURLencode(localPart); + + WebResource instanceResource = componentListResource.path(nsEncoded).path(idEncoded); + + // TODO: org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsWithAssociatedThings() could be used to do the resolving at the server + + ClientResponse response = instanceResource.accept(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS).get(ClientResponse.class); + if (response.getStatus() != 200) { + // also handles 404 + return null; + } + + TDefinitions definitions; + try { + Unmarshaller um = WineryRepositoryClient.createUnmarshaller(); + definitions = (TDefinitions) um.unmarshal(response.getEntityInputStream()); + } catch (JAXBException e) { + WineryRepositoryClient.logger.error("Could not umarshal TDefinitions", e); + // try next service + return null; + } + return definitions; + } + + /** + * {@inheritDoc} + */ + @Override + public <T extends TEntityType> Collection<TDefinitions> getAllTypesWithAssociatedElements(Class<T> c) { + String urlPathFragment = Util.getURLpathFragmentForCollection(c); + Collection<TDefinitions> allTypes = this.getAllTypes(urlPathFragment, TDefinitions.class); + return allTypes; + } + + /** + * + * @param stream the stream to parse + * @return null if document is invalid + */ + private Document parseAndValidateTOSCAXML(InputStream stream) { + Document document; + try { + document = this.toscaDocumentBuilder.parse(stream); + } catch (SAXException | IOException e) { + WineryRepositoryClient.logger.debug("Could not parse TOSCA file", e); + return null; + } + return document; + } + + /** + * {@inheritDoc} + */ + @Override + public TTopologyTemplate getTopologyTemplate(QName serviceTemplate) { + // we try all repositories until the first hit + for (WebResource wr : this.repositoryResources) { + WebResource r = WineryRepositoryClient.getTopologyTemplateWebResource(wr, serviceTemplate); + ClientResponse response = r.accept(MediaType.TEXT_XML).get(ClientResponse.class); + if (response.getClientResponseStatus() == ClientResponse.Status.OK) { + TTopologyTemplate topologyTemplate; + Document doc = this.parseAndValidateTOSCAXML(response.getEntityInputStream()); + if (doc == null) { + // no valid document + return null; + } + try { + topologyTemplate = WineryRepositoryClient.createUnmarshaller().unmarshal(doc.getDocumentElement(), TTopologyTemplate.class).getValue(); + } catch (JAXBException e) { + WineryRepositoryClient.logger.debug("Could not parse topology, returning null", e); + return null; + } + // first hit: immediately stop and return result + return topologyTemplate; + } + } + // nothing found + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public void setTopologyTemplate(QName serviceTemplate, TTopologyTemplate topologyTemplate) throws Exception { + WebResource r = WineryRepositoryClient.getTopologyTemplateWebResource(this.primaryWebResource, serviceTemplate); + String xmlAsString = Util.getXMLAsString(TTopologyTemplate.class, topologyTemplate); + ClientResponse response = r.type(MediaType.TEXT_XML).put(ClientResponse.class, xmlAsString); + WineryRepositoryClient.logger.debug(response.toString()); + int status = response.getStatus(); + if ((status < 200) || (status >= 300)) { + throw new Exception(response.toString()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public QName getArtifactTypeQNameForExtension(String extension) { + // we try all repositories until the first hit + for (WebResource wr : this.repositoryResources) { + WebResource artifactTypesResource = wr.path("artifacttypes").queryParam("extension", extension); + ClientResponse response = artifactTypesResource.accept(MediaType.TEXT_PLAIN).get(ClientResponse.class); + if (response.getClientResponseStatus() == ClientResponse.Status.OK) { + QName res = QName.valueOf(response.getEntity(String.class)); + return res; + } + } + return null; + } + + /** + * {@inheritDoc} + * + * Does NOT check for global QName uniqueness, only in the scope of all + * artifact templates + */ + @Override + public void createArtifactTemplate(QName qname, QName artifactType) throws QNameAlreadyExistsException { + WebResource artifactTemplates = this.primaryWebResource.path("artifacttemplates"); + MultivaluedMap<String, String> map = new MultivaluedMapImpl(); + map.putSingle("namespace", qname.getNamespaceURI()); + map.putSingle("name", qname.getLocalPart()); + map.putSingle("type", artifactType.toString()); + ClientResponse response = artifactTemplates.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, map); + if (response.getClientResponseStatus() != ClientResponse.Status.CREATED) { + // TODO: pass ClientResponse.Status somehow + // TODO: more fine grained checking for error message. Not all + // failures are that the QName already exists + WineryRepositoryClient.logger.debug(String.format("Error %d when creating id %s from URI %s", response.getStatus(), qname.toString(), this.primaryWebResource.getURI().toString())); + throw new QNameAlreadyExistsException(); + } + // no further return is made + } + + /** + * {@inheritDoc} + */ + @Override + public void createComponent(QName qname, Class<? extends TOSCAComponentId> idClass) throws QNameAlreadyExistsException { + WebResource resource = this.primaryWebResource.path(Util.getRootPathFragment(idClass)); + MultivaluedMap<String, String> map = new MultivaluedMapImpl(); + map.putSingle("namespace", qname.getNamespaceURI()); + map.putSingle("name", qname.getLocalPart()); + ClientResponse response = resource.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, map); + if (response.getClientResponseStatus() != ClientResponse.Status.CREATED) { + // TODO: pass ClientResponse.Status somehow + // TODO: more fine grained checking for error message. Not all failures are that the QName already exists + WineryRepositoryClient.logger.debug(String.format("Error %d when creating id %s from URI %s", response.getStatus(), qname.toString(), this.primaryWebResource.getURI().toString())); + throw new QNameAlreadyExistsException(); + } + // no further return is made + } + + @Override + public void forceDelete(GenericId id) throws IOException { + String pathFragment = IdUtil.getURLPathFragment(id); + for (WebResource wr : this.repositoryResources) { + ClientResponse response = wr.path(pathFragment).delete(ClientResponse.class); + if ((response.getClientResponseStatus() != ClientResponse.Status.NO_CONTENT) || (response.getClientResponseStatus() != ClientResponse.Status.NOT_FOUND)) { + WineryRepositoryClient.logger.debug(String.format("Error %d when deleting id %s from URI %s", response.getStatus(), id.toString(), wr.getURI().toString())); + } + } + } + + @Override + public boolean primaryRepositoryAvailable() { + if (this.primaryWebResource == null) { + return false; + } + + ClientResponse response = this.primaryWebResource.get(ClientResponse.class); + boolean res = (response.getClientResponseStatus() == ClientResponse.Status.OK); + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/WineryRepositoryClientFactory.java b/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/WineryRepositoryClientFactory.java new file mode 100644 index 0000000..59f0166 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/main/java/org/eclipse/winery/repository/client/WineryRepositoryClientFactory.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.client; + +public class WineryRepositoryClientFactory { + + public static IWineryRepositoryClient getWineryRepositoryClient() { + return new WineryRepositoryClient(); + } + +} diff --git a/winery/org.eclipse.winery.repository.client/src/main/resources/TOSCA-v1.0.xsd b/winery/org.eclipse.winery.repository.client/src/main/resources/TOSCA-v1.0.xsd new file mode 100644 index 0000000..8bed0e0 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/main/resources/TOSCA-v1.0.xsd @@ -0,0 +1,791 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Topology and Orchestration Specification for Cloud Applications Version 1.0 + Committee Specification Draft 08 + 09 May 2013 + Copyright (c) OASIS Open 2013. All rights reserved. + Source: http://docs.oasis-open.org/tosca/TOSCA/v1.0/csd08/schemas/ +--> +<xs:schema targetNamespace="http://docs.oasis-open.org/tosca/ns/2011/12" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns="http://docs.oasis-open.org/tosca/ns/2011/12" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> + <xs:element name="documentation" type="tDocumentation"/> + <xs:complexType name="tDocumentation" mixed="true"> + <xs:sequence> + <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="source" type="xs:anyURI"/> + <xs:attribute ref="xml:lang"/> + </xs:complexType> + <xs:complexType name="tExtensibleElements"> + <xs:sequence> + <xs:element ref="documentation" minOccurs="0" maxOccurs="unbounded"/> + <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:anyAttribute namespace="##other" processContents="lax"/> + </xs:complexType> + <xs:complexType name="tImport"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="namespace" type="xs:anyURI"/> + <xs:attribute name="location" type="xs:anyURI"/> + <xs:attribute name="importType" type="importedURI" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:element name="Definitions"> + <xs:complexType> + <xs:complexContent> + <xs:extension base="tDefinitions"/> + </xs:complexContent> + </xs:complexType> + </xs:element> + <xs:complexType name="tDefinitions"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Extensions" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Extension" type="tExtension" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Import" type="tImport" minOccurs="0" maxOccurs="unbounded"/> + <xs:element name="Types" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:choice maxOccurs="unbounded"> + <xs:element name="ServiceTemplate" type="tServiceTemplate"/> + <xs:element name="NodeType" type="tNodeType"/> + <xs:element name="NodeTypeImplementation" type="tNodeTypeImplementation"/> + <xs:element name="RelationshipType" type="tRelationshipType"/> + <xs:element name="RelationshipTypeImplementation" type="tRelationshipTypeImplementation"/> + <xs:element name="RequirementType" type="tRequirementType"/> + <xs:element name="CapabilityType" type="tCapabilityType"/> + <xs:element name="ArtifactType" type="tArtifactType"/> + <xs:element name="ArtifactTemplate" type="tArtifactTemplate"/> + <xs:element name="PolicyType" type="tPolicyType"/> + <xs:element name="PolicyTemplate" type="tPolicyTemplate"/> + </xs:choice> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tServiceTemplate"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="BoundaryDefinitions" type="tBoundaryDefinitions" minOccurs="0"/> + <xs:element name="TopologyTemplate" type="tTopologyTemplate"/> + <xs:element name="Plans" type="tPlans" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="targetNamespace" type="xs:anyURI"/> + <xs:attribute name="substitutableNodeType" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tTags"> + <xs:sequence> + <xs:element name="Tag" type="tTag" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tTag"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="value" type="xs:string" use="required"/> + </xs:complexType> + <xs:complexType name="tBoundaryDefinitions"> + <xs:sequence> + <xs:element name="Properties" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other"/> + <xs:element name="PropertyMappings" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="PropertyMapping" type="tPropertyMapping" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="PropertyConstraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="PropertyConstraint" type="tPropertyConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Requirements" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Requirement" type="tRequirementRef" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Capabilities" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Capability" type="tCapabilityRef" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Policies" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Policy" type="tPolicy" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Interfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tExportedInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tPropertyMapping"> + <xs:attribute name="serviceTemplatePropertyRef" type="xs:string" use="required"/> + <xs:attribute name="targetObjectRef" type="xs:IDREF" use="required"/> + <xs:attribute name="targetPropertyRef" type="xs:string" use="required"/> + </xs:complexType> + <xs:complexType name="tRequirementRef"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + <xs:complexType name="tCapabilityRef"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + <xs:complexType name="tEntityType" abstract="true"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="DerivedFrom" minOccurs="0"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="PropertiesDefinition" minOccurs="0"> + <xs:complexType> + <xs:attribute name="element" type="xs:QName"/> + <xs:attribute name="type" type="xs:QName"/> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + <xs:attribute name="abstract" type="tBoolean" default="no"/> + <xs:attribute name="final" type="tBoolean" default="no"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tEntityTemplate" abstract="true"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Properties" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="PropertyConstraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="PropertyConstraint" type="tPropertyConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="type" type="xs:QName" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tNodeTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:sequence> + <xs:element name="Requirements" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Requirement" type="tRequirement" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Capabilities" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Capability" type="tCapability" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="Policies" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Policy" type="tPolicy" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="DeploymentArtifacts" type="tDeploymentArtifacts" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="minInstances" type="xs:int" use="optional" default="1"/> + <xs:attribute name="maxInstances" use="optional" default="1"> + <xs:simpleType> + <xs:union> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:pattern value="([1-9]+[0-9]*)"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="unbounded"/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tTopologyTemplate"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:choice maxOccurs="unbounded"> + <xs:element name="NodeTemplate" type="tNodeTemplate"/> + <xs:element name="RelationshipTemplate" type="tRelationshipTemplate"/> + </xs:choice> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRelationshipType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:sequence> + <xs:element name="InstanceStates" type="tTopologyElementInstanceStates" minOccurs="0"/> + <xs:element name="SourceInterfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="TargetInterfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="ValidSource" minOccurs="0"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="ValidTarget" minOccurs="0"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRelationshipTypeImplementation"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="DerivedFrom" minOccurs="0"> + <xs:complexType> + <xs:attribute name="relationshipTypeImplementationRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RequiredContainerFeatures" type="tRequiredContainerFeatures" minOccurs="0"/> + <xs:element name="ImplementationArtifacts" type="tImplementationArtifacts" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + <xs:attribute name="relationshipType" type="xs:QName" use="required"/> + <xs:attribute name="abstract" type="tBoolean" use="optional" default="no"/> + <xs:attribute name="final" type="tBoolean" use="optional" default="no"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRelationshipTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:sequence> + <xs:element name="SourceElement"> + <xs:complexType> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="TargetElement"> + <xs:complexType> + <xs:attribute name="ref" type="xs:IDREF" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RelationshipConstraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="RelationshipConstraint" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="constraintType" type="xs:anyURI" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tNodeType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:sequence> + <xs:element name="RequirementDefinitions" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="RequirementDefinition" type="tRequirementDefinition" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="CapabilityDefinitions" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="CapabilityDefinition" type="tCapabilityDefinition" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="InstanceStates" type="tTopologyElementInstanceStates" minOccurs="0"/> + <xs:element name="Interfaces" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Interface" type="tInterface" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tNodeTypeImplementation"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Tags" type="tTags" minOccurs="0"/> + <xs:element name="DerivedFrom" minOccurs="0"> + <xs:complexType> + <xs:attribute name="nodeTypeImplementationRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RequiredContainerFeatures" type="tRequiredContainerFeatures" minOccurs="0"/> + <xs:element name="ImplementationArtifacts" type="tImplementationArtifacts" minOccurs="0"/> + <xs:element name="DeploymentArtifacts" type="tDeploymentArtifacts" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + <xs:attribute name="nodeType" type="xs:QName" use="required"/> + <xs:attribute name="abstract" type="tBoolean" use="optional" default="no"/> + <xs:attribute name="final" type="tBoolean" use="optional" default="no"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRequirementType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:attribute name="requiredCapabilityType" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRequirementDefinition"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Constraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Constraint" type="tConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="requirementType" type="xs:QName" use="required"/> + <xs:attribute name="lowerBound" type="xs:int" use="optional" default="1"/> + <xs:attribute name="upperBound" use="optional" default="1"> + <xs:simpleType> + <xs:union> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:pattern value="([1-9]+[0-9]*)"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="unbounded"/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tRequirement"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:attribute name="name" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tCapabilityType"> + <xs:complexContent> + <xs:extension base="tEntityType"/> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tCapabilityDefinition"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Constraints" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="Constraint" type="tConstraint" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="capabilityType" type="xs:QName" use="required"/> + <xs:attribute name="lowerBound" type="xs:int" use="optional" default="1"/> + <xs:attribute name="upperBound" use="optional" default="1"> + <xs:simpleType> + <xs:union> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:pattern value="([1-9]+[0-9]*)"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="unbounded"/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tCapability"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:attribute name="name" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tArtifactType"> + <xs:complexContent> + <xs:extension base="tEntityType"/> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tArtifactTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:sequence> + <xs:element name="ArtifactReferences" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="ArtifactReference" type="tArtifactReference" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:string" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tDeploymentArtifacts"> + <xs:sequence> + <xs:element name="DeploymentArtifact" type="tDeploymentArtifact" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tDeploymentArtifact"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="artifactType" type="xs:QName" use="required"/> + <xs:attribute name="artifactRef" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tImplementationArtifacts"> + <xs:sequence> + <xs:element name="ImplementationArtifact" maxOccurs="unbounded"> + <xs:complexType> + <xs:complexContent> + <xs:extension base="tImplementationArtifact"/> + </xs:complexContent> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tImplementationArtifact"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="interfaceName" type="xs:anyURI" use="optional"/> + <xs:attribute name="operationName" type="xs:NCName" use="optional"/> + <xs:attribute name="artifactType" type="xs:QName" use="required"/> + <xs:attribute name="artifactRef" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tPlans"> + <xs:sequence> + <xs:element name="Plan" type="tPlan" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional"/> + </xs:complexType> + <xs:complexType name="tPlan"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Precondition" type="tCondition" minOccurs="0"/> + <xs:element name="InputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="InputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="OutputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="OutputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:choice> + <xs:element name="PlanModel"> + <xs:complexType> + <xs:sequence> + <xs:any namespace="##other" processContents="lax"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="PlanModelReference"> + <xs:complexType> + <xs:attribute name="reference" type="xs:anyURI" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:sequence> + <xs:attribute name="id" type="xs:ID" use="required"/> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="planType" type="xs:anyURI" use="required"/> + <xs:attribute name="planLanguage" type="xs:anyURI" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tPolicyType"> + <xs:complexContent> + <xs:extension base="tEntityType"> + <xs:sequence> + <xs:element name="AppliesTo" type="tAppliesTo" minOccurs="0"/> + </xs:sequence> + <xs:attribute name="policyLanguage" type="xs:anyURI" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tPolicyTemplate"> + <xs:complexContent> + <xs:extension base="tEntityTemplate"> + <xs:attribute name="name" type="xs:string" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tAppliesTo"> + <xs:sequence> + <xs:element name="NodeTypeReference" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="typeRef" type="xs:QName" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tPolicy"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="name" type="xs:string" use="optional"/> + <xs:attribute name="policyType" type="xs:QName" use="required"/> + <xs:attribute name="policyRef" type="xs:QName" use="optional"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tConstraint"> + <xs:sequence> + <xs:any namespace="##other" processContents="lax"/> + </xs:sequence> + <xs:attribute name="constraintType" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tPropertyConstraint"> + <xs:complexContent> + <xs:extension base="tConstraint"> + <xs:attribute name="property" type="xs:string" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tExtensions"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="Extension" type="tExtension" maxOccurs="unbounded"/> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tExtension"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:attribute name="namespace" type="xs:anyURI" use="required"/> + <xs:attribute name="mustUnderstand" type="tBoolean" use="optional" default="yes"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tParameter"> + <xs:attribute name="name" type="xs:string" use="required"/> + <xs:attribute name="type" type="xs:string" use="required"/> + <xs:attribute name="required" type="tBoolean" use="optional" default="yes"/> + </xs:complexType> + <xs:complexType name="tInterface"> + <xs:sequence> + <xs:element name="Operation" type="tOperation" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="name" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tExportedInterface"> + <xs:sequence> + <xs:element name="Operation" type="tExportedOperation" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="name" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tOperation"> + <xs:complexContent> + <xs:extension base="tExtensibleElements"> + <xs:sequence> + <xs:element name="InputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="InputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="OutputParameters" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="OutputParameter" type="tParameter" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="name" type="xs:NCName" use="required"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + <xs:complexType name="tExportedOperation"> + <xs:choice> + <xs:element name="NodeOperation"> + <xs:complexType> + <xs:attribute name="nodeRef" type="xs:IDREF" use="required"/> + <xs:attribute name="interfaceName" type="xs:anyURI" use="required"/> + <xs:attribute name="operationName" type="xs:NCName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="RelationshipOperation"> + <xs:complexType> + <xs:attribute name="relationshipRef" type="xs:IDREF" use="required"/> + <xs:attribute name="interfaceName" type="xs:anyURI" use="required"/> + <xs:attribute name="operationName" type="xs:NCName" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="Plan"> + <xs:complexType> + <xs:attribute name="planRef" type="xs:IDREF" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="name" type="xs:NCName" use="required"/> + </xs:complexType> + <xs:complexType name="tCondition"> + <xs:sequence> + <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="expressionLanguage" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tTopologyElementInstanceStates"> + <xs:sequence> + <xs:element name="InstanceState" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="state" type="xs:anyURI" use="required"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tArtifactReference"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="Include"> + <xs:complexType> + <xs:attribute name="pattern" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + <xs:element name="Exclude"> + <xs:complexType> + <xs:attribute name="pattern" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="reference" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:complexType name="tRequiredContainerFeatures"> + <xs:sequence> + <xs:element name="RequiredContainerFeature" type="tRequiredContainerFeature" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="tRequiredContainerFeature"> + <xs:attribute name="feature" type="xs:anyURI" use="required"/> + </xs:complexType> + <xs:simpleType name="tBoolean"> + <xs:restriction base="xs:string"> + <xs:enumeration value="yes"/> + <xs:enumeration value="no"/> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="importedURI"> + <xs:restriction base="xs:anyURI"/> + </xs:simpleType> +</xs:schema> diff --git a/winery/org.eclipse.winery.repository.client/src/test/java/META-INF/MANIFEST.MF b/winery/org.eclipse.winery.repository.client/src/test/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..254272e --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/test/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/winery/org.eclipse.winery.repository.client/src/test/java/org/eclipse/winery/repository/client/TestWineryRepositoryClient.java b/winery/org.eclipse.winery.repository.client/src/test/java/org/eclipse/winery/repository/client/TestWineryRepositoryClient.java new file mode 100644 index 0000000..77ab588 --- /dev/null +++ b/winery/org.eclipse.winery.repository.client/src/test/java/org/eclipse/winery/repository/client/TestWineryRepositoryClient.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.client; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.eclipse.winery.model.tosca.TDefinitions; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.interfaces.QNameAlreadyExistsException; + +/** + * Tests client methods with a pre-configured client stored in a local static + * field. + * + * Client creation and multiple repositories are not tested. This should be + * subject to other test classes. + * + * TODO: This class expects things to be existent in the namespace "test". This + * should be enforced in a preload. + */ +@RunWith(JUnit4.class) +public class TestWineryRepositoryClient { + + // private final String repositoryURI = "http://2471.de:8080/wineydev"; + private static final String repositoryURI = "http://localhost:8080/winery"; + + private static final boolean USE_PROXY = true; + + private static final IWineryRepositoryClient client = new WineryRepositoryClient(TestWineryRepositoryClient.USE_PROXY); + static { + TestWineryRepositoryClient.client.addRepository(TestWineryRepositoryClient.repositoryURI); + } + + /** + * The namespace to put new things in. <br /> + * TODO: Is deleted completely after testing + */ + private static final String namespaceForNewArtifacts = "http://www.example.org/test/wineryclient/"; + + + @Test + public void getAllNodeTypes() { + Collection<TNodeType> allTypes = TestWineryRepositoryClient.client.getAllTypes(TNodeType.class); + for (TNodeType type : allTypes) { + Assert.assertNotNull("name is null", type.getName()); + Assert.assertNotNull("target namespace is null", type.getTargetNamespace()); + } + } + + @Test + public void getAllRelationshipTypes() { + Collection<TRelationshipType> allTypes = TestWineryRepositoryClient.client.getAllTypes(TRelationshipType.class); + for (TRelationshipType type : allTypes) { + Assert.assertNotNull("name is null", type.getName()); + Assert.assertNotNull("target namespace is null", type.getTargetNamespace()); + } + } + + @Test + public void getAllNodeTypesWithAssociatedElements() { + Collection<TDefinitions> allTypes = TestWineryRepositoryClient.client.getAllTypesWithAssociatedElements(TNodeType.class); + Assert.assertNotNull(allTypes); + } + + @Test + public void getAllRelationshipTypesWithAssociatedElements() { + Collection<TDefinitions> allTypes = TestWineryRepositoryClient.client.getAllTypesWithAssociatedElements(TRelationshipType.class); + Assert.assertNotNull(allTypes); + } + + @Test + public void getPropertiesOfAllNodeTypes() { + // TODO + } + + @Test + public void getPropertiesOfAllRelationshipTypes() { + // TODO + } + + @Test + public void getTestTopologyTemplate() { + QName serviceTemplate = new QName("test", "test"); + TTopologyTemplate topologyTemplate = TestWineryRepositoryClient.client.getTopologyTemplate(serviceTemplate); + Assert.assertNotNull(topologyTemplate); + } + + @Test + public void getPropertiesOfTestTopologyTemplate() { + QName serviceTemplate = new QName("test", "test"); + TTopologyTemplate topologyTemplate = TestWineryRepositoryClient.client.getTopologyTemplate(serviceTemplate); + Assert.assertNotNull(topologyTemplate); + List<TEntityTemplate> allTemplates = topologyTemplate.getNodeTemplateOrRelationshipTemplate(); + for (TEntityTemplate e : allTemplates) { + // TODO + } + } + + @Test + public void artifactTypeForWARfiles() { + QName artifactType = TestWineryRepositoryClient.client.getArtifactTypeQNameForExtension("war"); + Assert.assertNotNull("Artifact Type for .war does not exist", artifactType); + } + + @Test + public void createArtifactTemplate() throws IOException, QNameAlreadyExistsException { + // assure that the artifact type exists + QName artifactTypeQName = TestWineryRepositoryClient.client.getArtifactTypeQNameForExtension("war"); + Assert.assertNotNull("Artifact Type for .war does not exist", artifactTypeQName); + + // assure that the artifact template does not yet exist + // one possibility is to delete the artifact template, the other + // possibility is to + + QName artifactTemplateQName = new QName(TestWineryRepositoryClient.namespaceForNewArtifacts, "artifactTemplate"); + ArtifactTemplateId atId = new ArtifactTemplateId(artifactTemplateQName); + + // ensure that the template does not exist yet + TestWineryRepositoryClient.client.forceDelete(atId); + + TestWineryRepositoryClient.client.createArtifactTemplate(artifactTemplateQName, artifactTypeQName); + } +} diff --git a/winery/org.eclipse.winery.repository/.bowerrc b/winery/org.eclipse.winery.repository/.bowerrc new file mode 100644 index 0000000..eb92b22 --- /dev/null +++ b/winery/org.eclipse.winery.repository/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory" : "src/main/webapp/components" +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/.gitattributes b/winery/org.eclipse.winery.repository/.gitattributes new file mode 100644 index 0000000..3c3f5df --- /dev/null +++ b/winery/org.eclipse.winery.repository/.gitattributes @@ -0,0 +1,6 @@ +.gitattributes -crlf
+.gitmodules -crlf
+*.pdf binary
+*.vsd binary
+*.ppt* binary
+bower.json eol=lf
diff --git a/winery/org.eclipse.winery.repository/.gitignore b/winery/org.eclipse.winery.repository/.gitignore new file mode 100644 index 0000000..9d4d64c --- /dev/null +++ b/winery/org.eclipse.winery.repository/.gitignore @@ -0,0 +1,23 @@ +.classpath +/.gradle +.project +.settings/.jsdtscope +.settings/org.eclipse.core.resources.prefs +.settings/org.eclipse.jdt.core.prefs +.settings/org.eclipse.m2e.core.prefs +.settings/org.eclipse.wst.common.component +.settings/org.eclipse.wst.common.project.facet.core.xml +.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +.settings/org.eclipse.wst.jsdt.ui.superType.container +.settings/org.eclipse.wst.jsdt.ui.superType.name +.settings/org.eclipse.wst.validation.prefs +/.sonar +/bin +/build +/conf/valesca.properties +sonar-project.properties +/src/main/resources/rebel.xml +/src/main/webapp/components +/src/main/webapp/valesca.properties +/src/main/webapp/META-INF/MANIFEST.MF +/target diff --git a/winery/org.eclipse.winery.repository/README.md b/winery/org.eclipse.winery.repository/README.md new file mode 100644 index 0000000..92527a2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/README.md @@ -0,0 +1,63 @@ +# Winery Repository + +Setup, usage, and implementation hints are given in the [Eclipse Wiki] + +## REST API +Winery offers a REST API to communicate with the backend. +When issuing an `OPTIONS` request to `winery/`, a [RestDoc] description of the possible interactions is presented. +The returned JSON can be views in a browsable html format using [restdoc-renderer]. +If you install restdoc-renderer as `restdoc.html` in the `ROOT` of the tomcat, Winery automatically displays a link to the renderer in the about dialog. + +## About the code +The code tries to make use of EL and JSP tags wherever possible. All data is accessible via a REST API. +The REST API does **not** follow the HATEOAS approach. +The URLs follow the pattern `/<type>/<encoded namespace>/<encoded id>`, where `type` is `servicetemplate`, `nodetype`, ... +Below a concrete instanance, subresources such as `name` exist. + +Definitions are not modeled as explicit element. Only the nested elements are handled by Winery. +That means, it is not possible to specify custom definitions bundling a customized subset of available elements. + +Intentionally, a QName should be unique within the repository. +We did not follow this assumption, but only require that QNames are unique within a type. +That means, the repository allows `{http://www.example.org}id` for both a service template and a node type. +We introduced TOSCAcomponentId uniquely identifying a TOSCA element. +Future versions might redesign the backend to use a QName as the unique key. + +Currently, Winery is switching from plain Javascript library loading to [RequireJS]. + +The file `src/main/webapp/WEB-INF/common-functions.tld` and the files in `src/main/webapp/WEB-INF/tags/common` are copied from the sister project `org.eclipse.winery.topologymodler` at `mvn generate-sources`. + +### Trouble shooting +In case, `Version.java` is not found, then run `mvn compile`, which should trigger a regeneration of Version.java. + +The error message +`HTTP Status 500 - com.sun.jersey.api.container.ContainerException: org.apache.jasper.JasperException: The absolute uri: http://www.eclipse.org/winery/functions cannot be resolved in either web.xml or the jar files deployed with this application` indicates that `mvn generate-sources` was not run. + +In case `javax.servlet.jsp.PageContext` cannot be found: +Project -> right click -> Properties -> Project Facets -> Dynamic Web Module -> "Runtimes" -> "New..." + +When running in jetty 9.0.5, there is always the error message "Request Entity Too Large" when uploading a file. +There is the `maxFormContentSize` set in `jetty-web.xml`, but it currently does not help to solve this issue. + +When doing a copy-libs-to-tomcat hack, possibly "W3C_XML_SCHEMA_NS_URI cannot be resolved or is not a field" appears. +Remove `stax-api-1.0.1.jar` out of `tomcat7/lib`: Java's `rt.jar` should be used instead for `javax.xml.XMLConstants`. + +## License +Copyright (c) 2012-2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + + + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html + [Eclipse Wiki]: http://wiki.eclipse.org/winery + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html + [RequireJS]: http://requirejs.org/ + [RestDoc]: http://www.restdoc.org + [restdoc-renderer]: https://github.com/hoegertn/restdoc-renderer diff --git a/winery/org.eclipse.winery.repository/about.html b/winery/org.eclipse.winery.repository/about.html new file mode 100644 index 0000000..46675ad --- /dev/null +++ b/winery/org.eclipse.winery.repository/about.html @@ -0,0 +1,1064 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<p>The Content includes items that have been sourced from third parties as set out below. If you +did not receive this Content directly from the Eclipse Foundation, the following is provided +for informational purposes only, and you should look to the Redistributor's license for +terms and conditions of use.</p> + +<h4>JavaScript libraries</h4> + +<h5>biltong – Version 0.1</h5> +<table> + <tr> + <td>Files</td> + <td>The library is completely included in jsPlumb as “jsPlumbGeom v0.1</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/jsplumb/biltong">https://github.com/jsplumb/biltong</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-bitlong.txt" target="_blank">LICENSE-bitlong.txt</a> and is also available at <a href="https://github.com/sporritt/biltong/blob/master/src/biltong-0.1.js" target="_blank">github</a></td> + </tr> +</table> + +<h5>Bootstrap – Version 3.1.1</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/bootstrap</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://getbootstrap.com/">http://getbootstrap.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-bootstrap.txt" target="_blank">LICENSE-bootstrap.txt</a> and is also available at <a href="https://github.com/twbs/bootstrap/blob/v3.1.0/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h5>bootstrap-spinedit – Version 1.0.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/bootstrap-spinedit</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/scyv/bootstrap-spinedit">https://github.com/scyv/bootstrap-spinedit</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="https://github.com/scyv/bootstrap-spinedit/blob/v1.0.0/LICENSE.txt" target="_blank">github</a></td> + </tr> +</table> + +<h5>bootstrap-switch – Version 1.9.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/bootstrap-switch</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://www.bootstrap-switch.org/">http://www.bootstrap-switch.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/LICENSE-bootstrap-switch.txt" target="_blank">LICENSE-bootstrap-switch.txt</a> and is also available at <a href="https://github.com/nostalgiaz/bootstrap-switch/blob/v1.9.0/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h5>bootstrap3-wysihtml5-bower – Version 0.2.8</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/bootstrap3-wysihtml5-bower</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/Waxolunist/bootstrap3-wysihtml5-bower">https://github.com/Waxolunist/bootstrap3-wysihtml5-bower</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-bootstrap3-wysihtml5-bower.txt" target="_blank">LICENSE-bootstrap3-wysihtml5-bower.txt</a> and is also available at <a href="https://github.com/Waxolunist/bootstrap3-wysihtml5-bower/blob/v0.2.7/LICENCE" target="_blank">github</a></td> + </tr> +</table> + +<h5>Color Wheel – Version 1.0.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/colorwheel</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jweir.github.io/colorwheel/">http://jweir.github.io/colorwheel/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>DataTables – Version 1.9.4</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/datatables</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://datatables.net/">http://datatables.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>DataTables is dual licensed under the GPL v2 license (<a href="http://datatables.net/license_gpl2">http://datatables.net/license_gpl2</a>)or a BSD (3 clauses) license (<a href="http://datatables.net/license_bsd">http://datatables.net/license_bsd</a>). + The Eclipse Foundation elects to include this software in this distribution under the BSD license. + A copy of the license is contained in the file <a href="about_files/LICENSE-datatables.txt" target="_blank">LICENSE-datatables.txt</a>.</td> + </tr> +</table> + +<h5>Handlebars – Version 1.3.0</h5> +<table> + <tr> + <td>Path</td> + <td>src/main/webapp/components/handlebars/</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://handlebarsjs.com/">http://handlebarsjs.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-handlebars.txt" target="_blank">LICENSE-handlebars</a> and is also available at <a href="https://github.com/wycats/handlebars.js/blob/v1.3.0/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h5>JavaScript Canvas to Blob – Version 2.1.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-canvas-to-blob</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/JavaScript-Canvas-to-Blob">https://github.com/blueimp/JavaScript-Canvas-to-Blob</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>JavaScript Load Image – Version 1.11.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-load-image</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/JavaScript-Load-Image">https://github.com/blueimp/JavaScript-Load-Image</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>JavaScript Templates – Version 2.5.3</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-tmpl</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/JavaScript-Templates">https://github.com/blueimp/JavaScript-Templates</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>jQuery – Version 2.0.3</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jquery</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jquery.com/">http://jquery.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-jQuery.txt" target="_blank">LICENSE-jQuery.txt</a> and is also available at <a href="https://jquery.org/license/" target="_blank">https://jquery.org/license/</a></td> + </tr> +</table> + +<h5>jQuery Typing – v0.3.2-2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jquery-typing</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/tnajdek/jquery-typing">https://github.com/tnajdek/jquery-typing</a></td> + </tr> + <tr> + <td>License</td> + <td>Public domain. An explicit license is not provided, only a link to <a href="http://unlicense.org/" target="_blank">unlicense.org</a> is provided.</td> + </tr> +</table> + +<h5>jQuery File Upload Plugin – Version 9.5.3</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-file-upload</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/jQuery-File-Upload">https://github.com/blueimp/jQuery-File-Upload</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>jQuery UI – Version 1.10.3</h5> +This library is required by jsPlumb only +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jquery-ui</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jqueryui.com/">http://jqueryui.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-jQuery-UI.txt" target="_blank">LICENSE-jQuery-UI.txt</a> and is also available at <a href="https://github.com/jquery/jquery-ui/blob/master/MIT-LICENSE.txt" target="_blank">https://github.com/jquery/jquery-ui/blob/master/MIT-LICENSE.txt</a></td> + </tr> +</table> + +<h5>jsBezier – Version 0.6</h5> +<table> + <tr> + <td>Files</td> + <td>The library is completly included in jsPlumb</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/jsplumb/jsBezier">https://github.com/jsplumb/jsBezier</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. An explicit license is not provided, only an entry in the header of <a href="https://github.com/jsplumb/jsBezier/blob/master/js/0.6/jsBezier-0.6.js">jsBezier-0.6.js</a>.</td> + </tr> +</table> + + +<h5>jsPlumb – Version 1.5.4</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jsPlumb</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jsplumb.org/">http://jsplumb.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>All 1.x.x versions of jsPlumb are dual-licensed under both MIT and GPLv2 (<a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0">http://www.gnu.org/licenses/old-licenses/gpl-2.0</a>). + The Eclipse Foundation elects to include this software in this distribution under the MIT license. + A copy of the license is contained in the file <a href="about_files/LICENSE-jsPlumb-MIT" target="_blank">LICENSE-jsPlumb-MIT</a> and is also available at <a href="https://github.com/sporritt/jsPlumb/blob/1.5.4/jsPlumb-MIT-LICENSE.txt" target="_blank">github</a></td> + </tr> +</table> + +<h5>KeyboardJS – Version 0.4.2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/KeyboardJS</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/RobertWHurst/KeyboardJS/tree/v0.4.2">https://github.com/RobertWHurst/KeyboardJS/tree/v0.4.2</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD (2 clauses). A copy of the license is contained in the file <a href="about_files/LICENSE-KeyboardJS.txt" target="_blank">LICENSE-KeyboardJS.txt</a> and is also available at <a href="https://github.com/RobertWHurst/KeyboardJS/blob/v0.4.2/license.txt" target="_blank">https://github.com/RobertWHurst/KeyboardJS/blob/v0.4.2/license.txt</a></td> + </tr> +</table> + +<h5>Orion – Version 5.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/orion/editor/releases/5.0/built-editor.js">http://eclipse.org/orion/editor/releases/5.0/built-editor.js</a></td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://www.eclipse.org/orion/">http://www.eclipse.org/orion/</a></td> + </tr> + <tr> + <td>License</td> + <td>Eclipse Public License v1.0 and Eclipse Distribution License v1.0. + A copy of the licenses is contained in the files <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a> and <a href="about_files/EDL.txt" target="_blank">EDL.txt</a>. + A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the EDL is available at <a href="http://www.eclipse.org/org/documents/edl-v10.html">http://www.eclipse.org/org/documents/edl-v10.html</a>.</td> + </tr> +</table> + +<h5>PNotify – Version 1.3.1</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/pnotify</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://sciactive.com/pnotify/">http://sciactive.com/pnotify/</a></td> + </tr> + <tr> + <td>License</td> + <td>PNotify is distributed under the GPL (<a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>), + LGPL (<a href="http://www.gnu.org/licenses/lgpl.html">http://www.gnu.org/licenses/lgpl.html</a>), and + MPL (<a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the MPL license. + A copy of the license is contained in the file <a href="about_files/MPL-v1.1.txt" target="_blank">MPL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>RequireJS – Version 2.1.5</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/requirejs</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://requirejs.org/">http://requirejs.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD and MIT (see <a href="https://github.com/jrburke/requirejs/blob/master/LICENSE">https://github.com/jrburke/requirejs/blob/master/LICENSE</a>). + The Eclipse Foundation elects to include this software in this distribution under the MIT license. + A copy of the license is contained in the file <a href="about_files/LICENSE-requirejs.txt" target="_blank">LICENSE-requirejs.txt</a>.</td> + </tr> +</table> + +<h5>Select2 – Version 3.4.5</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/select2</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://ivaynberg.github.io/select2/">http://ivaynberg.github.io/select2/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0 (<a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>) and GPL2 (<a href="http://www.gnu.org/licenses/gpl-2.0.html">http://www.gnu.org/licenses/gpl-2.0.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the Apache 2.0 license. + A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a>.</td> + </tr> +</table> + +<h5>URI.js – Version 3.4.5</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/uri.js</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://medialize.github.io/URI.js/">http://medialize.github.io/URI.js/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT (<a href="http://www.opensource.org/licenses/mit-license">http://www.opensource.org/licenses/mit-license</a>) and GPL3 (<a href="http://www.gnu.org/licenses/gpl-3.0.html">http://www.gnu.org/licenses/gpl-3.0.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the MIT license.</td> + </tr> +</table> + +<h5>wysihtml5 – Version 0.3.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/wysihtml5</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/xing/wysihtml5">https://github.com/xing/wysihtml5</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-wysihtml5.txt" target="_blank">LICENSE-wysihtml5.txt</a> and is also available at <a href="https://github.com/xing/wysihtml5/blob/master/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h5>X-editable – Version 1.5.1</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/x-editable</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://vitalets.github.io/x-editable/">http://vitalets.github.io/x-editable/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-x-editable.txt" target="_blank">LICENSE-x-editable.txt</a> and is also available at <a href="https://github.com/vitalets/x-editable/blob/master/LICENSE-MIT" target="_blank">github</a></td> + </tr> +</table> + +<h5>XMLTree – Version 3.1.2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/xmltree</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://koppor.github.com/xmltree">http://koppor.github.com/xmltree</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-xmltree.txt" target="_blank">LICENSE-xmltree.txt</a> and is also available at <a href="https://github.com/koppor/xmltree/blob/master/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h5>XMLWriter – Version v1.0.2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/XMLWriter</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/flesler/XMLWriter">https://github.com/flesler/XMLWriter</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD. A copy of the license is contained in the file <a href="about_files/LICENSE-XMLWriter.txt" target="_blank">LICENSE-XMLWriter.txt</a> and is also available at <a href="https://github.com/flesler/XMLWriter/blob/master/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h4>Java Libraries</h4> + +<h5>Apache Commons Compress – Version 1.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-compress/">http://commons.apache.org/proper/commons-compress/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Configuration – Version 1.9</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-configuration/">http://commons.apache.org/proper/commons-configuration/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons HTTP Client – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://hc.apache.org/httpclient-3.x/">http://hc.apache.org/httpclient-3.x/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> + <tr> + <td>Note</td> + <td>Only <code>org.apache.http.impl.cookie.DateUtils</code> is included. It was stripped down to fit the requirements of winery</td> + </tr> +</table> + +<h5>Apache Commons IO – Version 2.4</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-io/">http://commons.apache.org/proper/commons-io/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang – Version 2.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang3 – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Tika – Version 1.3</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://tika.apache.org/">http://tika.apache.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Xerces – Version 2.9.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://xerces.apache.org/">http://xerces.apache.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>ASM – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://asm.ow2.org/">http://asm.ow2.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD (3 clauses). A copy of the license is contained in the file <a href="about_files/LICENSE-ASM.txt" target="_blank">LICENSE-ASM.txt</a> and is also available at <a href="http://asm.ow2.org/license.html" target="_blank">http://asm.ow2.org/license.html</a></td> + </tr> +</table> + +<h5>Guava – Version 15.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://code.google.com/p/guava-libraries/">http://code.google.com/p/guava-libraries/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-annotations – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-annotations">https://github.com/FasterXML/jackson-annotations</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> + <tr> + <td>Note</td> + <td>The license was explictily added in version 2.2.3 and 2.3.0. See <a href="https://github.com/FasterXML/jackson-annotations/issues/14">Issue #14</a> and <a href="https://github.com/FasterXML/jackson-annotations/blob/master/src/main/resources/META-INF/LICENSE">LICENSE in the source repository</a>.</td> + </tr> +</table> + +<h5>jackson-core – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-core">https://github.com/FasterXML/jackson-core</a> and <a href="http://wiki.fasterxml.com/JacksonHome">http://wiki.fasterxml.com/JacksonHome</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-databind – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-databind">https://github.com/FasterXML/jackson-databind</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-jaxrs-base – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base">https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-jaxrs-json-provider – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/json">https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/json</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-module-jaxb-annotations – Version 2.3.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-module-jaxb-annotations">https://github.com/FasterXML/jackson-module-jaxb-annotations</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a>. + The license is added via the <a href="https://github.com/FasterXML/oss-parent">oss-parent</a> project.</td> + </tr> +</table> + +<h5>jackson-module-jsonSchema – Version 2.3.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-module-jsonSchema">https://github.com/FasterXML/jackson-module-jsonSchema</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>JavaEWAH – Version 0.5.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://code.google.com/p/javaewah/">https://code.google.com/p/javaewah/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Java Manifest Parser – Version 2.0.5</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://ebr.springsource.com/repository/app/bundle/version/detail?name=com.springsource.util.parser.manifest&version=2.0.5.RELEASE">http://ebr.springsource.com/repository/app/bundle/version/detail?name=com.springsource.util.parser.manifest&version=2.0.5.RELEASE</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. The sources do not contain a license file, but each .java file contains an Apache 2.0 license header. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>JAXB Standard Implementation – Version 2.2.5</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://java.net/projects/jaxb/">https://java.net/projects/jaxb/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://java.net/projects/jaxb/sources/version2/content/tags/jaxb-2_2_5/License.txt?rev=4179" target="_blank">https://java.net/projects/jaxb/sources/version2/content/tags/jaxb-2_2_5/License.txt?rev=4179</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + + +<h5>Jersey Core – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Jersey Contribs: Jersey-Multipart – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Jersey Server – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Jersey Servlet – Version 1.11</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>JGit – Version 3.0.0.201306101825-r</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.eclipse.org/jgit/">http://www.eclipse.org/jgit/</a></td> + </tr> + <tr> + <td>License</td> + <td>Eclipse Distribution Licencse - v 1.0. A copy of the license is contained in the file <a href="about_files/EDL.txt" target="_blank">EDL.txt</a> and is also available at <a href="http://www.eclipse.org/org/documents/edl-v10.php" target="_blank">http://www.eclipse.org/org/documents/edl-v10.php</a></td> + </tr> +</table> + +<h5>JSch – Version 0.1.46</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.jcraft.com/jsch/">http://www.jcraft.com/jsch/</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD (3 clause). A copy of the license is contained in the file <a href="about_files/LICENSE-JSch.txt" target="_blank">LICENSE-JSch.txt</a> and is also available at <a href="http://www.jcraft.com/jsch/LICENSE.txt" target="_blank">http://www.jcraft.com/jsch/LICENSE.txt</a></td> + </tr> +</table> + +<h5>JSP Standard Tag Library – Version 1.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://jstl.java.net/">https://jstl.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Logback Classic – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>Mimepull – Version 1.9.4</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://mimepull.java.net/">https://mimepull.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>RestDoc API – Version 1.3.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/RestDoc/restdoc-api">https://github.com/RestDoc/restdoc-api</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>RestDoc Jersey Server Jersey – Version 1.0.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/koppor/restdoc-server-jersey">https://github.com/koppor/restdoc-server-jersey</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>RestDoc Java Server (JAX-RS 1.1) – Version 1.7.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/hoegertn/restdoc-java-server/tree/jaxrs11">https://github.com/hoegertn/restdoc-java-server/tree/jaxrs11</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>RestDoc Renderer – v1.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/hoegertn/restdoc-renderer">https://github.com/hoegertn/restdoc-renderer</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.5</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: jcl-over-slf4j – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>SLF4J: slf4j-ext – Version 1.7.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/extensions.html">http://www.slf4j.org/extensions.html</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-ext.txt" target="_blank">LICENSE-slf4j-ext.txt</a> and is also available at <a href="https://github.com/qos-ch/slf4j/blob/master/LICENSE.txt" target="_blank">https://github.com/qos-ch/slf4j/blob/master/LICENSE.txt</a></td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.common – ${project.version}</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.generators.ia – ${project.version}</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.csar.toscametafile – Version 0.0.3</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.selfservice – Version 0.1.19</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.tosca – Version 0.1.20</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.repository.client – ${project.version}</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>XML Commons External Components XML APIs Extensions (xml-apis) – Version 1.3.04</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://xml.apache.org/commons/components/external">http://xml.apache.org/commons/components/external</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>xz for Java – Version 1.3</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://tukaani.org/xz/java.html">http://tukaani.org/xz/java.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Public domain. A copy of the license is available at <a href="http://tukaani.org/xz/java.html" target="_blank">http://tukaani.org/xz/java.html</a></td> + </tr> +</table> +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.repository/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.repository/about_files/CDDL-v1.1.txt b/winery/org.eclipse.winery.repository/about_files/CDDL-v1.1.txt new file mode 100644 index 0000000..7cc8719 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/CDDL-v1.1.txt @@ -0,0 +1,129 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL - Version 1.1) +1. Definitions. + + 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + + 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + + 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + + 1.4. “Executable” means the Covered Software in any form other than Source Code. + + 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + + 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + + 1.7. “License” means this document. + + 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + + 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + + 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + + 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/EDL.txt b/winery/org.eclipse.winery.repository/about_files/EDL.txt new file mode 100644 index 0000000..52c7ca2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/EDL.txt @@ -0,0 +1,13 @@ +Eclipse Distribution License - v 1.0 + +Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-ASM.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-ASM.txt new file mode 100644 index 0000000..7676ba5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-ASM.txt @@ -0,0 +1,29 @@ +Copyright (c) 2000-2011 INRIA, France Telecom +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-JSch.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-JSch.txt new file mode 100644 index 0000000..81c8eac --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-JSch.txt @@ -0,0 +1,30 @@ +JSch 0.0.* was released under the GNU LGPL license. Later, we have switched +over to a BSD-style license. + +------------------------------------------------------------------------------ +Copyright (c) 2002-2012 Atsuhiko Yamanaka, JCraft,Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-KeyboardJS.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-KeyboardJS.txt new file mode 100644 index 0000000..e71620b --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-KeyboardJS.txt @@ -0,0 +1,25 @@ +Copyright 2011 Robert Hurst. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY ROBERT HURST ''AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ROBERT HURST OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the +authors and should not be interpreted as representing official policies, either expressed +or implied, of Robert Hurst.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-XMLWriter.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-XMLWriter.txt new file mode 100644 index 0000000..2676da3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-XMLWriter.txt @@ -0,0 +1,27 @@ +Copyright (c) 2014, Ariel Flesler +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-biltong.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-biltong.txt new file mode 100644 index 0000000..11cb215 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-biltong.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Simon Porritt + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-boostrap.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-boostrap.txt new file mode 100644 index 0000000..8d94aa9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-boostrap.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2011-2014 Twitter, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-bootstrap-switch.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-bootstrap-switch.txt new file mode 100644 index 0000000..d9a10c0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-bootstrap-switch.txt @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-bootstrap3-wysihtml5-bower.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-bootstrap3-wysihtml5-bower.txt new file mode 100644 index 0000000..af8b31e --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-bootstrap3-wysihtml5-bower.txt @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2012 JFHollingworth LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-colorPicker.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-colorPicker.txt new file mode 100644 index 0000000..d717c4b --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-colorPicker.txt @@ -0,0 +1,22 @@ +Copyright (c) 2012 Lakshan Perera + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-datatables.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-datatables.txt new file mode 100644 index 0000000..2477290 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-datatables.txt @@ -0,0 +1,10 @@ +Copyright (c) 2008-2013, Allan Jardine +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of Allan Jardine nor SpryMedia may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-handlebars.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-handlebars.txt new file mode 100644 index 0000000..f466a93 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-handlebars.txt @@ -0,0 +1,19 @@ +Copyright (C) 2011 by Yehuda Katz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-jQuery-UI.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-jQuery-UI.txt new file mode 100644 index 0000000..1c693e3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-jQuery-UI.txt @@ -0,0 +1,26 @@ +Copyright 2013 jQuery Foundation and other contributors, +http://jqueryui.com/ + +This software consists of voluntary contributions made by many +individuals (AUTHORS.txt, http://jqueryui.com/about) For exact +contribution history, see the revision history and logs, available +at http://jquery-ui.googlecode.com/svn/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-jQuery.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-jQuery.txt new file mode 100644 index 0000000..957f26d --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-jQuery.txt @@ -0,0 +1,21 @@ +Copyright 2013 jQuery Foundation and other contributors +http://jquery.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-jsPlumb-MIT.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-jsPlumb-MIT.txt new file mode 100644 index 0000000..b5bc650 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-jsPlumb-MIT.txt @@ -0,0 +1,20 @@ +Copyright (c) 2013 Simon Porritt, http://jsplumb.org/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-open-sans.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-open-sans.txt new file mode 100644 index 0000000..392c811 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-open-sans.txt @@ -0,0 +1,204 @@ +License for 'Open Sans' +Apache License + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + License shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + Licensor shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + Legal Entity shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + control means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + You (or Your) shall mean an individual or Legal Entity + exercising permissions granted by this License. + + Source form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + Object form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + Work shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + Derivative Works shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + Contribution shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, submitted + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as Not a Contribution. + + Contributor shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a NOTICE text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an AS IS BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets [] + replaced with your own identifying information. (Dont include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same printed page as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the License); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an AS IS BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-requirejs.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-requirejs.txt new file mode 100644 index 0000000..de4ee29 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-requirejs.txt @@ -0,0 +1,58 @@ +RequireJS is released under two licenses: new BSD, and MIT. You may pick the +license that best suits your development needs. The text of both licenses are +provided below. + + +The "New" BSD License: +---------------------- + +Copyright (c) 2010-2013, The Dojo Foundation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the Dojo Foundation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +MIT License +----------- + +Copyright (c) 2010-2013, The Dojo Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-slf4j-ext.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-slf4j-ext.txt new file mode 100644 index 0000000..361d2ce --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-slf4j-ext.txt @@ -0,0 +1,24 @@ +Copyright (c) 2004-2013 QOS.ch +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-wysihtml5.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-wysihtml5.txt new file mode 100644 index 0000000..e5083d0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-wysihtml5.txt @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2012 XING AG + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-x-editable.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-x-editable.txt new file mode 100644 index 0000000..eeb9357 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-x-editable.txt @@ -0,0 +1,22 @@ +Copyright (c) 2012 Vitaliy Potapov + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/LICENSE-xmltree.txt b/winery/org.eclipse.winery.repository/about_files/LICENSE-xmltree.txt new file mode 100644 index 0000000..7a28063 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/LICENSE-xmltree.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitya <mitya@mitya.co.uk> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winery/org.eclipse.winery.repository/about_files/MPL-v1.1.txt b/winery/org.eclipse.winery.repository/about_files/MPL-v1.1.txt new file mode 100644 index 0000000..a8cd934 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/MPL-v1.1.txt @@ -0,0 +1,470 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the MPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/winery/org.eclipse.winery.repository/about_files/file-icons.txt b/winery/org.eclipse.winery.repository/about_files/file-icons.txt new file mode 100644 index 0000000..f7a8560 --- /dev/null +++ b/winery/org.eclipse.winery.repository/about_files/file-icons.txt @@ -0,0 +1,27 @@ +http://www.splitbrain.org/projects/file_icons + +Released to the Public Domain +Free to use. Provided as is. No warranties. + +Note: The big majority of icons where created by the creators listed + below. Only a few ones where found on the net. They were too + widespread to determine the original author and thus were + considered public domain. + If you are the author of one of those icons just send a short + mail to either be included in the list below or have the icon + removed from the package. + +Creators: + + Andreas Gohr <andi@splitbrain.org> + Michael Klier <chi@chimeric.de> + Andreas Barton <andreas.barton@web.de> + Hubert Chathi <hubert@uhoreg.ca> + Johan Koehne <johankohne@gmail.com> + Rudi von Staden <rudivs@iafrica.com> + Daniel Darvish <ddarvish@hibm.org> + Andy Pascall <apascall@engineering.ucsb.edu> + Seth <seth.holcomb@gmail.com> + David Carella <david.carella@gmail.com> + Tom N. Harris <telliamed@fastmail.us> + Brandon Carmon Colvin <b.carmon.colvin@gmail.com> diff --git a/winery/org.eclipse.winery.repository/bower.json b/winery/org.eclipse.winery.repository/bower.json new file mode 100644 index 0000000..58abbbb --- /dev/null +++ b/winery/org.eclipse.winery.repository/bower.json @@ -0,0 +1,60 @@ +{ + "name": "Winery", + "version": "0.1.37-SNAPSHOT", + "author": "Oliver Kopp <kopp.dev@gmail.com>", + "contributors": [ + { + "name": "Uwe Breitenbücher" + }, + { + "name": "Kálmán Képes" + }, + { + "name": "Yves Schubert" + }, + { + "name": "Timur Sungur" + }, + { + "name": "Jerome Tagliaferri" + } + ], + "licenses": [ + { + "type": "EPL", + "url": "http://www.eclipse.org/legal/epl-v10.html" + }, + { + "type": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + ], + "dependencies": { + "blueimp-file-upload": "9.5.3", + "blueimp-tmpl": "2.5.3", + "bootstrap": "3.1.1", + "bootstrap-spinedit": "https://github.com/scyv/bootstrap-spinedit.git#1.0.0", + "bootstrap-switch": "v1.9.0", + "colorwheel": "https://github.com/koppor/colorwheel.git#bower", + "datatables": "1.9.4", + "jquery": "2.0.3", + "jquery-typing": "https://github.com/tnajdek/jquery-typing.git#0.3.2-2", + "jsPlumb": "1.5.4", + "KeyboardJS": "git://github.com/RobertWHurst/KeyboardJS.git#v0.4.2", + "pnotify": "1.3.1", + "requirejs": "2.1.5", + "select2": "https://github.com/ivaynberg/select2/archive/3.4.5.zip", + "uri.js": "v1.12.0", + "x-editable": "1.5.1", + "bootstrap3-wysihtml5-bower": "0.2.8", + "wysihtml5": "0.3.0", + "xmltree": "3.1.2", + "XMLWriter": "1.0.2" + }, + "keywords": [ + "TOSCA" + ], + "resolutions": { + "jquery": "2.0.3" + } +} diff --git a/winery/org.eclipse.winery.repository/conf/winery.properties.dist b/winery/org.eclipse.winery.repository/conf/winery.properties.dist new file mode 100644 index 0000000..6554dd8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/conf/winery.properties.dist @@ -0,0 +1,49 @@ +#URL for the topology modeler +#topologymodeler=http://opentosca-winery.appspot.com + +#Warning to be displayed +warning = Development version ${project.version} + +#BPMN4TOSCA Modeler URI +#default: nothing +#bpmn4toscamodelerBaseURI= + +############################################################################# +# Repository Storage Configuration +############################################################################# + + +# Option A: plain file-based repository +# locally stored +############################################################################# + +#use slashes +#repositoryPath=c:/winery-repository + + +# Option B: git based repository, based on Option A +# locally stored +############################################################################# +# first, configure Option A + +#additionally: +#for http-based username/password authentification +#git.username=username +#git.password=password + + +# Option C: jclouds-based repository +# +# !! NOT SUPPORTED YET !! +# +# See http://www.jclouds.org/documentation/reference/supported-providers/ +# for a list of supported providers +############################################################################# + +#jclouds.context.provider=aws-s3 +#jclouds.context.identity=OOV7VOHYFEE7AIGOKAEM9TAH +#jclouds.context.credential=iw4DoopGui4is4eze7Eeph4/aeYoo7re + +# optional options +#jclouds.blobstore.location=US-EAST +#jclouds.blobstore.container=repository.winery diff --git a/winery/org.eclipse.winery.repository/package.json b/winery/org.eclipse.winery.repository/package.json new file mode 100644 index 0000000..b59dbe9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/package.json @@ -0,0 +1,22 @@ +{ + "name": "openo-winery", + "version": "1.0.0", + "description": "openo winery", + "dependencies": { + }, + "devDependencies": { + "bower": "~1.7.9" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "http://oip.zte.com.cn/oipgit/git/Open-O-Community/common-services-common-utilities.git" + }, + "keywords": [ + "openo-winery" + ], + "author": "openo", + "license": "Apache-2.0" +} diff --git a/winery/org.eclipse.winery.repository/pom.xml b/winery/org.eclipse.winery.repository/pom.xml new file mode 100644 index 0000000..7138039 --- /dev/null +++ b/winery/org.eclipse.winery.repository/pom.xml @@ -0,0 +1,511 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Unger - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.winery</groupId> + <artifactId>winery</artifactId> + <version>0.1.37-SNAPSHOT</version> + </parent> + <artifactId>org.eclipse.winery.repository</artifactId> + <packaging>war</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.2.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.2.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-core</artifactId> + <version>1.17</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.6</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <!-- Version 1.3 is approved by Eclipse, Version 1.4 is not --> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>xerces</groupId> + <artifactId>xercesImpl</artifactId> + <version>2.9.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.0.1</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.tika</groupId> + <artifactId>tika-core</artifactId> + <version>1.3</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.restdoc</groupId> + <artifactId>restdoc-server-jersey</artifactId> + <version>1.0.1</version> + <scope>compile</scope> + <!-- we have to stick with Orbit's versions of the libraries --> + <exclusions> + <exclusion> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-server</artifactId> + </exclusion> + <exclusion> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + </exclusion> + <exclusion> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </exclusion> + <exclusion> + <!-- provided by jersey --> + <groupId>javax.ws.rs</groupId> + <artifactId>jsr311-api</artifactId> + </exclusion> + <exclusion> + <!-- version 2.2.2 explicitly included above --> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </exclusion> + <exclusion> + <!-- version 2.2.2 explicitly included above --> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </exclusion> + <exclusion> + <!-- other version included via logback --> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.sun.jersey.contribs</groupId> + <artifactId>jersey-multipart</artifactId> + <version>1.17</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <groupId>org.jvnet</groupId> + <artifactId>mimepull</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.jvnet.mimepull</groupId> + <artifactId>mimepull</artifactId> + <version>1.9.4</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.selfservice</artifactId> + <!-- in case of a change at the version, adapt about.html --> + <version>0.1.20-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.7.6</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + <version>1.11</version> + <scope>compile</scope> + <!-- 1.11 depends on server 1.11, but we use 1.17 --> + <exclusions> + <exclusion> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-server</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-server</artifactId> + <version>1.17</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>jstl</groupId> + <artifactId>jstl</artifactId> + <version>1.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.model.csar.toscametafile</artifactId> + <!-- in case of a change at the version, adapt about.html --> + <version>0.0.4-SNAPSHOT</version> + </dependency> + <!-- use jackson-jaxrs-json-provider instead of jersey-json as suggested by http://stackoverflow.com/a/17006866/873282 --> + <dependency> + <groupId>com.fasterxml.jackson.jaxrs</groupId> + <artifactId>jackson-jaxrs-json-provider</artifactId> + <version>2.2.2</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-ext</artifactId> + <version>1.7.2</version> + <scope>compile</scope> + <!-- not approved by Eclipse legal --> + <exclusions> + <exclusion> + <groupId>ch.qos.cal10n</groupId> + <artifactId>cal10n-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.common</artifactId> + <version>0.1.37-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.generators.ia</artifactId> + <version>0.1.37-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.repository.client</artifactId> + <version>0.1.37-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>commons-configuration</groupId> + <artifactId>commons-configuration</artifactId> + <version>1.9</version> + <scope>compile</scope> + <exclusions> + <!-- provided by jcl-over-slf4j to enable logging via logback --> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.jgit</groupId> + <artifactId>org.eclipse.jgit</artifactId> + <version>3.0.0.201306101825-r</version> + <scope>compile</scope> + </dependency> + <dependency> + <!-- Required for com.sun.xml.bind.namespacePrefixMapper --> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-impl</artifactId> + <version>2.2.5</version> + </dependency> + <!-- no review, but approval is required for test-only dependencies: http://wiki.eclipse.org/Development_Resources/IP/Test_and_Build_Dependencies --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.jayway.restassured</groupId> + <artifactId>rest-assured</artifactId> + <version>1.9.0</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <resources> + <resource> + <directory>.</directory> + <filtering>true</filtering> + <includes> + <include>about.html</include> + </includes> + </resource> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>winery.properties</include> + <include>logback.xml</include> + <include>logback-test.xml</include> + </includes> + </resource> + <resource> + <directory>src/main/templates</directory> + <includes> + <include>*.java</include> + </includes> + <filtering>true</filtering> + <targetPath>${project.build.directory}/generated-sources/java/org/eclipse/winery/repository</targetPath> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>2.4</version> + <configuration> + <webResources> + <resource> + <directory>${basedir}/src/main/webapp/WEB-INF</directory> + <filtering>true</filtering> + <targetPath>WEB-INF</targetPath> + <includes> + <include>tags/about.tag</include> + <include>tags/genericpage.tag</include> + </includes> + </resource> + </webResources> + <attachClasses>true</attachClasses> + </configuration> + </plugin> + <plugin> + <groupId>com.github.eirslett</groupId> + <artifactId>frontend-maven-plugin</artifactId> + <version>1.0</version> + <!-- optional --> + <configuration> + <nodeVersion>v4.5.0</nodeVersion> + <npmVersion>2.15.9</npmVersion> + <nodeDownloadRoot>https://nodejs.org/dist/</nodeDownloadRoot> + <npmDownloadRoot>https://registry.npmjs.org/npm/-/</npmDownloadRoot> + </configuration> + <executions> + <execution> + <id>install node and npm</id> + <!-- optional: default phase is "generate-resources" --> + <phase>initialize</phase> + <goals> + <goal>install-node-and-npm</goal> + <goal>npm</goal> + </goals> + </execution> + <execution> + <id>bower install</id> + <phase>initialize</phase> + <goals> + <goal>bower</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.7</version> + <executions> + <execution> + <phase>generate-sources</phase> + <id>default-cli</id> + <configuration> + <target> + <copy todir="${project.basedir}/src/main/webapp/WEB-INF/tags/common" overwrite="true"> + <fileset dir="${project.basedir}/../org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common" /> + </copy> + <copy todir="${project.basedir}/src/main/webapp/jsp/shared" overwrite="true"> + <fileset dir="${project.basedir}/../org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared" /> + </copy> + <copy todir="${project.basedir}/src/main/webapp/WEB-INF" overwrite="true" file="${project.basedir}/../org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/common-functions.tld" /> + <copy todir="${project.basedir}/src/main/webapp/js" overwrite="true" file="${project.basedir}/../org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common-topologyrendering.js" /> + <copy todir="${project.basedir}/src/main/webapp/js" overwrite="true" file="${project.basedir}/../org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-support-common.js" /> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-clean-plugin</artifactId> + <version>2.5</version> + <configuration> + <filesets> + <fileset> + <!-- delete the files copied by generate source / the ant-task above. This ensures that deleted files being deleted at the topology modeler are also deleted at the repository --> + <directory>${project.basedir}/src/main/webapp/WEB-INF/tags/common</directory> + <excludes> + <exclude>.gitignore</exclude> + </excludes> + <followSymlinks>false</followSymlinks> + </fileset> + <fileset> + <!-- delete the files copied by generate source / the ant-task above. This ensures that deleted files being deleted at the topology modeler are also deleted at the repository --> + <directory>${project.basedir}/src/main/webapp/jsp/shared</directory> + <excludes> + <exclude>.gitignore</exclude> + </excludes> + <followSymlinks>false</followSymlinks> + </fileset> + </filesets> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.16</version> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <version>1.8</version> + <executions> + <execution> + <id>add-source</id> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${project.build.directory}/generated-sources/java/</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + <finalName>winery</finalName> + <pluginManagement> + <plugins> + <plugin> + <!-- hint by http://wiki.eclipse.org/M2E_plugin_execution_not_covered --> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <versionRange>[1.0.0,)</versionRange> + <goals> + <goal>run</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore /> + </action> + </pluginExecution> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <versionRange>[1.0.0,)</versionRange> + <goals> + <goal>resources</goal> + </goals> + </pluginExecutionFilter> + <action> + <execute> + <runOnConfiguration>true</runOnConfiguration> + <runOnIncremental>false</runOnIncremental> + </execute> + </action> + </pluginExecution> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <versionRange>[1.0,)</versionRange> + <goals> + <goal>parse-version</goal> + <goal>add-source</goal> + <goal>maven-version</goal> + <goal>add-resource</goal> + <goal>add-test-resource</goal> + <goal>add-test-source</goal> + </goals> + </pluginExecutionFilter> + <action> + <execute> + <runOnConfiguration>true</runOnConfiguration> + <runOnIncremental>true</runOnIncremental> + </execute> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> +</project> diff --git a/winery/org.eclipse.winery.repository/sonar-project.java.properties b/winery/org.eclipse.winery.repository/sonar-project.java.properties new file mode 100644 index 0000000..2c182ef --- /dev/null +++ b/winery/org.eclipse.winery.repository/sonar-project.java.properties @@ -0,0 +1,24 @@ +# required metadata +sonar.projectKey=org.eclipse.winery.repository-java +sonar.projectName=org.eclipse.winery.repository-java +sonar.projectVersion=0.1.2 + +# path to source directories (required) +sonar.sources=src/main/java + +# path to test source directories (optional) +#sonar.tests= + +# path to project binaries (optional), for example directory of Java bytecode +#sonar.binaries=binDir + +# optional comma-separated list of paths to libraries. Only path to JAR file and path to directory of classes are supported. +#sonar.libraries=org.eclipse.jgit-2.1.0.201209190230-r.jar + +# The value of the property must be the key of the language. +sonar.language=java + +# enforece Java 1.7 to enable analysis of diamon operator by PMD +sonar.java.source=1.7 + +sonar.sourceEncoding=UTF-8 diff --git a/winery/org.eclipse.winery.repository/sonar-project.twomodules.properties b/winery/org.eclipse.winery.repository/sonar-project.twomodules.properties new file mode 100644 index 0000000..a03160f --- /dev/null +++ b/winery/org.eclipse.winery.repository/sonar-project.twomodules.properties @@ -0,0 +1,29 @@ +# required metadata +sonar.projectKey=valesca +sonar.projectName=Valesca +sonar.projectVersion=1.0 + +# path to source directories (required) +sonar.sources=. +sonar.sourceEncoding=UTF-8 + +sonar.modules=java,jsp + +## Java +java.sonar.projectBaseDir=src/main/java +java.sonar.language=java + +# path to test source directories (optional) +#java.sonar.tests= + +# path to project binaries (optional), for example directory of Java bytecode +#java.sonar.binaries=binDir + +# optional comma-separated list of paths to libraries. Only path to JAR file and path to directory of classes are supported. +#java.sonar.libraries=org.eclipse.jgit-2.1.0.201209190230-r.jar + +## jsp +#http://docs.codehaus.org/display/SONAR/Web+Plugin +jsp.sonar.projectBaseDir=src/main/webapp +jsp.sonar.language=web +jsp.sonar.web.sourceDirectory=src/main/webapp diff --git a/winery/org.eclipse.winery.repository/sonar-project.web.properties b/winery/org.eclipse.winery.repository/sonar-project.web.properties new file mode 100644 index 0000000..bd3ab14 --- /dev/null +++ b/winery/org.eclipse.winery.repository/sonar-project.web.properties @@ -0,0 +1,16 @@ +# required metadata +sonar.projectKey=org.eclipse.winery.repository-web +sonar.projectName=org.eclipse.winery.repository-web +sonar.projectVersion=0.1.2 + +# path to source directories (required) +sonar.sources=src/main/ +sonar.exclusions=webapp/components/** + +# The value of the property must be the key of the language. +sonar.language=web + +sonar.sourceEncoding=UTF-8 + +#http://docs.codehaus.org/display/SONAR/Web+Plugin +sonar.web.sourceDirectory=src/main/webapp
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/apache/http/impl/cookie/DateUtils.java b/winery/org.eclipse.winery.repository/src/main/java/org/apache/http/impl/cookie/DateUtils.java new file mode 100644 index 0000000..33f9c70 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/apache/http/impl/cookie/DateUtils.java @@ -0,0 +1,68 @@ +/* + * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.0-beta1/module-client/src/main/java/org/apache/http/impl/cookie/DateUtils.java $ + * $Revision: 677240 $ + * $Date: 2008-07-16 13:25:47 +0200 (Wed, 16 Jul 2008) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + */ + +package org.apache.http.impl.cookie; + +/** + * A utility class for parsing and formatting HTTP dates as used in cookies and + * other headers. This class handles dates as defined by RFC 2616 section + * 3.3.1 as well as some other common non-standard formats. + * + * @author Christopher Brown + * @author Michael Becke + * + * Shortened by Oliver Kopp to contain DEFAULT_PATTERNS and related artifacts only. + */ +public final class DateUtils { + + /** + * Date format pattern used to parse HTTP date headers in RFC 1123 format. + */ + public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; + + /** + * Date format pattern used to parse HTTP date headers in RFC 1036 format. + */ + public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz"; + + /** + * Date format pattern used to parse HTTP date headers in ANSI C + * <code>asctime()</code> format. + */ + public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy"; + + public static final String[] DEFAULT_PATTERNS = new String[] { + PATTERN_RFC1036, + PATTERN_RFC1123, + PATTERN_ASCTIME + }; + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java new file mode 100644 index 0000000..966b5f2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerResponse; +import com.sun.jersey.spi.container.ContainerResponseFilter; + +/** + * Required for the BPMN4TOSCA modeler when not running on the same machine + */ +public class CORSFilter implements ContainerResponseFilter { + + @Override + public ContainerResponse filter(ContainerRequest containerRequest, ContainerResponse containerResponse) { + ResponseBuilder response = Response.fromResponse(containerResponse.getResponse()); + response.header("Access-Control-Allow-Origin", "*").header("Access-Control-Allow-Methods", "GET, PUT, OPTIONS"); + containerResponse.setResponse(response.build()); + return containerResponse; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java new file mode 100644 index 0000000..60eacdd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.util.Calendar; +import java.util.Date; + +public class Constants { + + /** repository specific **/ + public static final String DEFAULT_REPO_NAME = "winery-repository"; + // this directory is checked for existence. If it does not exist + // $HOME/DEFAULT_REPO_NAME is used + public static final String GLOBAL_REPO_PATH_WINDOWS = "C:\\" + Constants.DEFAULT_REPO_NAME; + + /** file-system in general **/ + public static final String newline = System.getProperty("line.separator"); + + // Path to images for extensions + // Currently, we require the format <filenamextension>.png + public static final String PATH_MIMETYPEIMAGES = "/images/mime-types/"; + + // suffix for BPMN4TOSCA + public static final String SUFFIX_BPMN4TOSCA = ".bpmn4tosca"; + + // suffix for CSAR files + public static final String SUFFIX_CSAR = ".csar"; + + // suffix for files in the directory PATH_MIMETYPEIMAGES, including "." + public static final String SUFFIX_MIMETYPEIMAGES = ".png"; + + // suffix for files storing the mimetype of the belonging files + // used in implementors if IRepository of no appropriate implementation for storing a mimetype is available + public static final String SUFFIX_MIMETYPE = ".mimetype"; + + // suffix for all property files + public static final String SUFFIX_PROPERTIES = ".properties"; + + // suffix for all files storing Definitions + // following line 2935 of TOSCA cos01 + public static final String SUFFIX_TOSCA_DEFINITIONS = ".tosca"; + + // at each new start of the application, the modified date changes + // reason: the default values of the properties or the JSP could have + // changed + public static final Date LASTMODIFIEDDATE_FOR_404 = Calendar.getInstance().getTime(); + + public static final String TOSCA_PLANTYPE_BUILD_PLAN = "http://docs.oasis-open.org/tosca/ns/2011/12/PlanTypes/BuildPlan"; + public static final String TOSCA_PLANTYPE_TERMINATION_PLAN = "http://docs.oasis-open.org/tosca/ns/2011/12/PlanTypes/TerminationPlan"; + + public static final String DIRNAME_SELF_SERVICE_METADATA = "SELFSERVICE-Metadata"; + + /* used for IA generation */ + //public static final String NAMESPACE_ARTIFACTTYPE_WAR = "http://www.opentosca.org/types"; + public static final String NAMESPACE_ARTIFACTTYPE_WAR = "http://www.example.com/ToscaTypes"; + public static final String LOCALNAME_ARTIFACTTYPE_WAR = "WAR"; + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java new file mode 100644 index 0000000..876c015 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TDefinitions; +import org.eclipse.winery.repository.backend.MockXMLElement; +import org.eclipse.winery.repository.resources.admin.NamespacesResource; +import org.eclipse.winery.model.selfservice.Application; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.xml.bind.marshaller.NamespacePrefixMapper; + +// if com.sun.xml.bind.marshaller.NamespacePrefixMapper cannot be resolved, +// possibly +// http://mvnrepository.com/artifact/com.googlecode.jaxb-namespaceprefixmapper-interfaces/JAXBNamespacePrefixMapper/2.2.4 +// helps +// also com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper could be the +// right package + +/** + * Bundles all general JAXB functionality + */ +public class JAXBSupport { + + private static final Logger logger = LoggerFactory.getLogger(JAXBSupport.class); + + // thread-safe JAXB as inspired by https://jaxb.java.net/guide/Performance_and_thread_safety.html + // The other possibility: Each subclass sets JAXBContext.newInstance(theSubClass.class); in its static {} part. + // This seems to be more complicated than listing all subclasses in initContext + public final static JAXBContext context = JAXBSupport.initContext(); + + private final static PrefixMapper prefixMapper = new PrefixMapper(); + + + /** + * Follows + * https://jaxb.java.net/2.2.5/docs/release-documentation.html#marshalling + * -changing-prefixes + * + * See http://www.jarvana.com/jarvana/view/com/sun/xml/bind/jaxb-impl/2.2.2/ + * jaxb-impl-2.2.2-javadoc.jar!/com/sun/xml/bind/marshaller/ + * NamespacePrefixMapper.html for a JavaDoc of the NamespacePrefixMapper + */ + private static class PrefixMapper extends NamespacePrefixMapper { + + @Override + public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { + if (namespaceUri.equals("")) { + return ""; + } + + // this does not work to get TOSCA elements without prefix + // possibly because the attribute "name" is present without prefix + // if (namespaceUri.equals(Namespaces.TOSCA_NAMESPACE)) { + // return ""; + // } + + String prefix = NamespacesResource.getPrefix(namespaceUri); + return prefix; + } + } + + + private static JAXBContext initContext() { + JAXBContext context; + try { + // For winery classes, eventually the package+jaxb.index method could be better. See http://stackoverflow.com/a/3628525/873282 + // @formatter:off + context = JAXBContext.newInstance( + TDefinitions.class, // all other elements are referred by "@XmlSeeAlso" + WinerysPropertiesDefinition.class, + // for the self-service portal + Application.class, + // MockXMLElement is added for testing purposes only. + MockXMLElement.class); + // @formatter:on + } catch (JAXBException e) { + JAXBSupport.logger.error("Could not initialize JAXBContext", e); + throw new IllegalStateException(e); + } + return context; + } + + /** + * Creates a marshaller + * + * @throws IllegalStateException if marshaller could not be instantiated + */ + public static Marshaller createMarshaller(boolean includeProcessingInstruction) { + Marshaller m; + try { + m = JAXBSupport.context.createMarshaller(); + // pretty printed output is required as the XML is sent 1:1 to the browser for editing + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + m.setProperty("com.sun.xml.bind.namespacePrefixMapper", JAXBSupport.prefixMapper); + if (!includeProcessingInstruction) { + // side effect of JAXB_FRAGMENT property (when true): processing instruction is not included + m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); + } + } catch (JAXBException e) { + JAXBSupport.logger.error("Could not instantiate marshaller", e); + throw new IllegalStateException(e); + } + + return m; + } + + /** + * Creates an unmarshaller + * + * @throws IllegalStateException if unmarshaller could not be instantiated + */ + public static Unmarshaller createUnmarshaller() { + try { + return JAXBSupport.context.createUnmarshaller(); + } catch (JAXBException e) { + JAXBSupport.logger.error("Could not instantiate unmarshaller", e); + throw new IllegalStateException(e); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java new file mode 100644 index 0000000..cbb120f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java @@ -0,0 +1,332 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + * C. Timurhan Sungur - jClouds preferences + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.AccessControlException; +import java.util.Locale; +import java.util.Properties; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.eclipse.winery.common.TOSCADocumentBuilderFactory; +import org.eclipse.winery.repository.backend.IRepository; +import org.eclipse.winery.repository.backend.filebased.FilebasedRepository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; +import org.eclipse.winery.repository.runtimeintegration.OpenTOSCAContainerConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Prefs implements ServletContextListener { + + // set by the constructors + // We have to do this hack as the servlet container initializes this class + // on its own and we want to have a *single* instance of this class. + public static Prefs INSTANCE; + + private static final Logger logger = LoggerFactory.getLogger(Prefs.class); + + protected IRepository repository = null; + + private ServletContext context; + + private Boolean isContainerLocallyAvailable = null; + + private Boolean isRestDocDocumentationAvailable = null; + + private Boolean isPlanBuilderAvailable = null; + + // location of the winery topology modeler + private String wineryTopologyModelerPath = null; + + // the properties from winery.properties + protected Properties properties = null; + + // package visibility to ease testing + static final String PROP_JCLOUDS_CONTEXT_PROVIDER = "jclouds.context.provider"; + static final String PROP_JCLOUDS_CONTEXT_IDENTITY = "jclouds.context.identity"; + static final String PROP_JCLOUDS_CONTEXT_CREDENTIAL = "jclouds.context.credential"; + static final String PROP_JCLOUDS_BLOBSTORE_LOCATION = "jclouds.blobstore.location"; + static final String PROP_JCLOUDS_CONTAINERNAME = "jclouds.blobstore.container"; + static final String PROP_JCLOUDS_END_POINT = "jclouds.blobstore.endpoint"; + + static final String PROP_BPMN4TOSCA_MODELER_URI = "bpmn4toscamodelerBaseURI"; + + + /** + * This constructor is called at handling at servlets, too. Therefore, we + * make it private. If testing is needed, an additional paramater has to be + * passed + */ + public Prefs() { + Prefs.INSTANCE = this; + } + + /** + * Constructor for Unit testing ONLY! + * + * @param initializeRepository true if the repository should be initialized + * as provided in winery.properties + * @throws IOException + * @warning Do not call! (except from Unit testing code) + */ + protected Prefs(boolean initializeRepository) throws IOException { + this(); + + // emulate behavior of doInitialization(Context) + Properties p = new Properties(); + InputStream is = this.getClass().getClassLoader().getResourceAsStream("winery.properties"); + if (is != null) { + p.load(is); + } + this.properties = p; + + if (initializeRepository) { + this.doRepositoryInitialization(); + } + } + + /** + * Initialization code for the repository. Should go into separate class, + * but being here should be OK for a prototype + * + * Called from both the constructor for JUnit and the servlet-based + * initialization + * + * Pre-Condition: this.properties is set. + */ + private void doRepositoryInitialization() { + assert (this.properties != null); + + String provider = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_PROVIDER); + if (provider != null) { + // repository runs via jclouds + // String identity = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_IDENTITY); + // String credential = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_CREDENTIAL); + // String location = this.properties.getProperty(Prefs.PROP_JCLOUDS_BLOBSTORE_LOCATION); + // String containerName = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTAINERNAME); + // String endPoint = this.properties.getProperty(Prefs.PROP_JCLOUDS_END_POINT); + Prefs.logger.error("jClouds is currently not supported due to jClouds not yet approved by Eclipse. Falling back to local storages"); + provider = null; + // Prefs.logger.info("Using jclouds as interface to the repository"); + // this.repository = new JCloudsBasedRepository(provider, identity, credential, location, containerName, endPoint); + } // else { + if (provider == null) { + String repositoryLocation = this.properties.getProperty("repositoryPath"); + Prefs.logger.debug("Repository location: {}", repositoryLocation); + Prefs.logger.debug("Trying git-based backend"); + try { + this.repository = new GitBasedRepository(repositoryLocation); + Prefs.logger.debug("git-based backend is used"); + } catch (Throwable e) { + Prefs.logger.trace(e.getMessage()); + Prefs.logger.debug("There seems to be no git repository at the specified location. We fall back to the file-based repository"); + this.repository = new FilebasedRepository(repositoryLocation); + } + } + } + + private void doInitialization(ServletContext ctx) { + if (Locale.getDefault() != Locale.ENGLISH) { + try { + // needed for {@link + // org.eclipse.winery.repository.filesystem.Utils.returnFile(File, + // String)} + Locale.setDefault(Locale.ENGLISH); + } catch (AccessControlException e) { + // Happens at Google App Engine + Prefs.logger.error("Could not switch locale to English", e); + } + } + + this.context = ctx; + + // Reading // + final String fn = "/WEB-INF/classes/winery.properties"; + Prefs.logger.debug("Trying to read ".concat(ctx.getRealPath(fn))); + InputStream inStream = ctx.getResourceAsStream(fn); + // alternative: InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("winery.properties"); + Properties p = new Properties(); + if (inStream == null) { + Prefs.logger.info(fn + " does not exist."); + + // We search for winery.properties on the filesystem in the repository + + File propFile = new File(FilebasedRepository.getDefaultRepositoryFilePath(), "winery.properties"); + Prefs.logger.info("Trying " + propFile.getAbsolutePath()); + if (propFile.exists()) { + Prefs.logger.info("Found"); + // if winery.property exists in the root of the default repository path (~/winery-repository), load it + try (InputStream is2 = new FileInputStream(propFile)) { + p.load(is2); + } catch (IOException e) { + Prefs.logger.error("Could not load winery.properties", e); + } + } else { + Prefs.logger.info("Not found"); + } + } else { + try { + p.load(inStream); + try { + inStream.close(); + } catch (IOException e) { + Prefs.logger.error("Could not close stream of winery.properties", e); + } + } catch (FileNotFoundException e) { + // OK if file does not exist + } catch (IOException e) { + Prefs.logger.error("Could not load winery.properties", e); + } + } + + this.wineryTopologyModelerPath = p.getProperty("topologymodeler"); + + // make the properties known in the class + this.properties = p; + + this.doRepositoryInitialization(); + + // Initialize XSD validation in the background. Takes up a few seconds. + // If we do not do it here, the first save by a user takes a few seconds, which is inconvenient + new Thread() { + + @Override + public void run() { + Prefs.logger.debug("Initializing XML validation"); + @SuppressWarnings("unused") + TOSCADocumentBuilderFactory tdbf = TOSCADocumentBuilderFactory.INSTANCE; + Prefs.logger.debug("Initialized XML validation"); + } + }.start(); + } + + public IRepository getRepository() { + return this.repository; + } + + @Override + public void contextInitialized(ServletContextEvent arg0) { + Prefs.INSTANCE.doInitialization(arg0.getServletContext()); + } + + @Override + public void contextDestroyed(ServletContextEvent arg0) { + // nothing to do at tear down + } + + /** + * @return the path of the root resource + */ + public String getResourcePath() { + return this.context.getContextPath(); + } + + /** + * @return the path to the winery topology modeler. Without trailing slash + */ + public String getWineryTopologyModelerPath() { + if (this.wineryTopologyModelerPath == null) { + // derive the path from the current path + String res = this.getResourcePath(); + if (res.endsWith("/")) { + res = res.substring(0, res.length() - 1); + } + int pos = res.lastIndexOf("/"); + if (pos <= 0) { + res = "/winery-topologymodeler"; + } else { + res = res.substring(0, pos); + res = res + "winery-topologymodeler"; + } + return res; + } else { + assert (this.wineryTopologyModelerPath != null); + return this.wineryTopologyModelerPath; + } + } + + /** + * Returns the read content from winery.properties. + * + * @return the internal object held by this class. Manipulations on this + * object may cause trouble. + */ + public Properties getProperties() { + return this.properties; + } + + /** + * @return the version of winery + */ + public String getVersion() { + return Version.VERSION; + } + + /** + * @return true if the OpenTOSCA container is locally available + */ + public boolean isContainerLocallyAvailable() { + if (this.isContainerLocallyAvailable == null) { + // we initialize the variable at the first read + // The container and Winery are started simultaneously + // Therefore, the container might not be available if Winery is starting + // When checking at the first read, chances are high that the container started + this.isContainerLocallyAvailable = OpenTOSCAContainerConnection.isContainerLocallyAvailable(); + } + return this.isContainerLocallyAvailable; + } + + /** + * @return true if the plan generator is available + */ + public boolean isPlanBuilderAvailable() { + // similar implementation as isContainerLocallyAvailable() + if (this.isPlanBuilderAvailable == null) { + String planBuilderURI = "http://localhost:1339/planbuilder"; + this.isPlanBuilderAvailable = Utils.isResourceAvailable(planBuilderURI); + } + return this.isPlanBuilderAvailable; + } + + /** + * Quick hack to check whether a RestDoc documentation is available at + * /restdoc.html. We do not deliver + */ + public boolean isRestDocDocumentationAvailable() { + String path = "http://localhost:8080/restdoc.html"; + if (this.isRestDocDocumentationAvailable == null) { + // we initialize the variable at the first read + // The container and Winery are started simultaneously + // Therefore, the container might not be available if Winery is starting + // When checking at the first read, chances are high that the container started + this.isRestDocDocumentationAvailable = Utils.isResourceAvailable(path); + } + return this.isRestDocDocumentationAvailable; + } + + /** + * @return the base URL of the BPMN4TOSCA plan modeler. NULL if not + * configured. May also be empty. + */ + public String getBPMN4TOSCABaseURL() { + return this.properties.getProperty(Prefs.PROP_BPMN4TOSCA_MODELER_URI); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java new file mode 100644 index 0000000..12d84e9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.repository; + +import org.eclipse.winery.repository.resources.MainResource; +import org.restdoc.jersey.server.RestDocFeature; + +public class RestDocFilter extends RestDocFeature { + + @Override + protected Class<?>[] getClasses() { + Class<?>[] res = {MainResource.class}; + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java new file mode 100644 index 0000000..e989324 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java @@ -0,0 +1,787 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.Response.Status.Family; +import javax.ws.rs.core.StreamingOutput; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.namespace.QName; + +import org.apache.taglibs.standard.functions.Functions; +import org.apache.tika.detect.Detector; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.parser.AutoDetectParser; +import org.apache.xerces.xs.XSConstants; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.model.tosca.TArtifactType; +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TPolicyType; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.admin.AdminId; +import org.eclipse.winery.repository.export.CSARExporter; +import org.eclipse.winery.repository.export.TOSCAExportUtil; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource; +import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportResource; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; +import org.w3c.dom.Element; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; + +/** + * Contains utility functionality concerning with everything that is + * <em>not</em> related only to the repository, but more. For instance, resource + * functionality. Utility functionality for the repository is contained at + * {@link BackendUtils} + */ +public class Utils { + + private static final XLogger logger = XLoggerFactory.getXLogger(Utils.class); + + + public static URI createURI(String uri) { + try { + return new URI(uri); + } catch (URISyntaxException e) { + throw new IllegalStateException(); + } + } + + + // RegExp inspired by http://stackoverflow.com/a/5396246/873282 + // NameStartChar without ":" + // stackoverflow: -dfff, standard: d7fff + private static final String RANGE_NCNAMESTARTCHAR = "A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d" + "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff" + "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\x10000-\\xEFFFF"; + private static final String REGEX_NCNAMESTARTCHAR = "[" + Utils.RANGE_NCNAMESTARTCHAR + "]"; + + private static final String RANGE_NCNAMECHAR = Utils.RANGE_NCNAMESTARTCHAR + "\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040"; + private static final String REGEX_INVALIDNCNAMESCHAR = "[^" + Utils.RANGE_NCNAMECHAR + "]"; + + + /** + * Creates a (valid) XML ID (NCName) based on the passed name + * + * Valid NCNames: http://www.w3.org/TR/REC-xml-names/#NT-NCName / + * http://www.w3.org/TR/xml/#NT-Name http://www.w3.org/TR/xml/#NT-Name + * + */ + public static XMLId createXMLid(String name) { + return new XMLId(Utils.createXMLidAsString(name), false); + } + + /** + * Creates a (valid) XML ID (NCName) based on the passed name + * + * Valid NCNames: http://www.w3.org/TR/REC-xml-names/#NT-NCName / + * http://www.w3.org/TR/xml/#NT-Name http://www.w3.org/TR/xml/#NT-Name + * + * TODO: this method seems to be equal to {@link + * org.eclipse.winery.common.Util.makeNCName(String)}. The methods should be + * merged into one. + * + */ + public static String createXMLidAsString(String name) { + String id = name; + if (!id.substring(0, 1).matches(Utils.REGEX_NCNAMESTARTCHAR)) { + id = "_".concat(id); + } + // id starts with a valid character + + // before we wipe out all invalid characters, we do a readable + // replacement for appropriate characters + id = id.replace(' ', '_'); + + // keep length of ID, only wipe out invalid characters + // alternative: replace invalid characters by URLencoded version. As the + // ID is visible only in the URL, this quick hack should be OK + // ID is visible only in the URL, this quick hack should be OK + id = id.replaceAll(Utils.REGEX_INVALIDNCNAMESCHAR, "_"); + + return id; + } + + /** + * Returns the plain XML for the selected resource + * + * @param uri + */ + public static Response getDefinitionsOfSelectedResource(final AbstractComponentInstanceResource resource, final URI uri) { + final TOSCAExportUtil exporter = new TOSCAExportUtil(); + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + Map<String, Object> conf = new HashMap<>(); + conf.put(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString(), uri); + try { + exporter.exportTOSCA(resource.getId(), output, conf); + } catch (JAXBException e) { + throw new WebApplicationException(e); + } + output.close(); + } + }; + /* + * this code is for offering a download action // Browser offers save as + * // .tosca is more or less needed for debugging, only a CSAR makes + * sense. // Therefore, we want to have the xml opened in the browser. + * StringBuilder sb = new StringBuilder(); + * sb.append("attachment;filename=\""); + * sb.append(resource.getXmlId().getEncoded()); sb.append(" - "); + * sb.append(resource.getNamespace().getEncoded()); sb.append(".xml"); + * sb.append("\""); return Response.ok().header("Content-Disposition", + * sb + * .toString()).type(MediaType.APPLICATION_XML_TYPE).entity(so).build(); + */ + return Response.ok().type(MediaType.APPLICATION_XML).entity(so).build(); + } + + public static Response getCSARofSelectedResource(final AbstractComponentInstanceResource resource) { + final CSARExporter exporter = new CSARExporter(); + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + try { + exporter.writeCSAR(resource.getId(), output); + } catch (Exception e) { + throw new WebApplicationException(e); + } + } + }; + StringBuilder sb = new StringBuilder(); + sb.append("attachment;filename=\""); + sb.append(resource.getXmlId().getEncoded()); + sb.append(org.eclipse.winery.repository.Constants.SUFFIX_CSAR); + sb.append("\""); + return Response.ok().header("Content-Disposition", sb.toString()).type(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP).entity(so).build(); + } + + /** + * @return Singular type name for the given resource. E.g., + * "ServiceTemplateResource" gets "ServiceTemplate" + */ + public static String getTypeForInstance(Class<? extends AbstractComponentInstanceResource> resClass) { + String res = resClass.getName(); + // Everything between the last "." and before "Resource" is the Type + int dotIndex = res.lastIndexOf('.'); + assert (dotIndex >= 0); + return res.substring(dotIndex + 1, res.length() - "Resource".length()); + } + + /** + * @return Singular type name for the given id. E.g., "ServiceTemplateId" + * gets "ServiceTemplate" + */ + public static String getTypeForAdminId(Class<? extends AdminId> idClass) { + return Util.getEverythingBetweenTheLastDotAndBeforeId(idClass); + } + + /** + * @return Singular type name for given AbstractComponentsResource. E.g, + * "ServiceTemplatesResource" gets "ServiceTemplate" + */ + public static String getTypeForComponentContainer(Class<? extends AbstractComponentsResource> containerClass) { + String res = containerClass.getName(); + // Everything between the last "." and before "sResource" is the Type + int dotIndex = res.lastIndexOf('.'); + assert (dotIndex >= 0); + return res.substring(dotIndex + 1, res.length() - "sResource".length()); + } + + @SuppressWarnings("unchecked") + public static Class<? extends TOSCAComponentId> getComponentIdClass(String idClassName) { + String pkg = "org.eclipse.winery.common.ids.definitions."; + if (idClassName.contains("Import")) { + // quick hack to handle imports, which reside in their own package + pkg = pkg + "imports."; + } + String fullClassName = pkg + idClassName; + try { + return (Class<? extends TOSCAComponentId>) Class.forName(fullClassName); + } catch (ClassNotFoundException e) { + // quick hack for Ids local to winery repository + try { + fullClassName = "org.eclipse.winery.repository.datatypes.ids.admin." + idClassName; + return (Class<? extends TOSCAComponentId>) Class.forName(fullClassName); + } catch (ClassNotFoundException e2) { + String errorMsg = "Could not find id class for component container, " + fullClassName; + Utils.logger.error(errorMsg); + throw new IllegalStateException(errorMsg); + } + } + } + + /** + * Returns a class object for ids of components nested in the given + * AbstractComponentsResource + */ + public static Class<? extends TOSCAComponentId> getComponentIdClassForComponentContainer(Class<? extends AbstractComponentsResource> containerClass) { + // the name of the id class is the type + "Id" + String idClassName = Utils.getTypeForComponentContainer(containerClass) + "Id"; + + return Utils.getComponentIdClass(idClassName); + } + + public static Class<? extends TOSCAComponentId> getComponentIdClassForTExtensibleElements(Class<? extends TExtensibleElements> clazz) { + // we assume that the clazzName always starts with a T. + // Therefore, we fetch everything after the last dot (plus offest 1) + String idClassName = clazz.getName(); + int dotIndex = idClassName.lastIndexOf('.'); + assert (dotIndex >= 0); + idClassName = idClassName.substring(dotIndex + 2) + "Id"; + + return Utils.getComponentIdClass(idClassName); + } + + + private static final String slashEncoded = Util.URLencode("/"); + + + public static String getURLforPathInsideRepo(String pathInsideRepo) { + // first encode the whole string + String res = Util.URLencode(pathInsideRepo); + // issue: "/" is also encoded. This has to be undone: + res = res.replaceAll(Utils.slashEncoded, "/"); + return res; + } + + + /** + * Shared object to map JSONs + */ + public static final ObjectMapper mapper = new ObjectMapper(); + + + public static String Object2JSON(Object o) { + String res; + try { + res = Utils.mapper.writeValueAsString(o); + } catch (Exception e) { + Utils.logger.error(e.getMessage(), e); + return null; + } + return res; + } + + @SuppressWarnings("unchecked") + public static Class<? extends GenericId> getGenericIdClassForType(String typeIdType) { + Class<? extends GenericId> res; + // quick hack - we only need definitions right now + String pkg = "org.eclipse.winery.repository.datatypes.ids.definitions."; + String className = typeIdType; + className = pkg + className; + try { + res = (Class<? extends GenericId>) Class.forName(className); + } catch (ClassNotFoundException e) { + Utils.logger.error("Could not find id class for id type", e); + res = null; + } + return res; + } + + /** + * @return the absolute path for the given id + */ + public static String getAbsoluteURL(GenericId id) { + return Prefs.INSTANCE.getResourcePath() + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id)); + } + + /** + * @param baseURI the URI from which the path should start + * @param id the generic id to resolve + * + * @return the relative path for the given id + */ + public static String getRelativeURL(URI baseURI, GenericId id) { + String absolutePath = Prefs.INSTANCE.getResourcePath() + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id)); + return baseURI.relativize(URI.create(absolutePath)).toString(); + } + + /** + * @return the absolute path for the given id + */ + public static String getAbsoluteURL(RepositoryFileReference ref) { + return Prefs.INSTANCE.getResourcePath() + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref)); + } + + public static URI getAbsoluteURI(GenericId id) { + return Utils.createURI(Utils.getAbsoluteURL(id)); + } + + public static String doubleEscapeHTMLAndThenConvertNL2BR(String txt) { + String res = Functions.escapeXml(txt); + res = Functions.escapeXml(res); + res = res.replaceAll("\\n", "<br/>"); + return res; + } + + /** + * This method is similar to {@link + * org.eclipse.winery.common.Util.qname2href()}, but treats winery's + * internal ID model instead of the global TOSCA model + * + * @param id the id to create an <code>a href</code> element for + * @return an <code>a</code> HTML element pointing to the given id + */ + public static String getHREF(TOSCAComponentId id) { + String res = "<a href=\"" + Utils.getAbsoluteURL(id) + "\">" + Functions.escapeXml(id.getXmlId().getDecoded()) + "</a>"; + return res; + } + + public static String artifactTypeQName2href(QName qname) { + return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TArtifactType.class, qname); + } + + public static String nodeTypeQName2href(QName qname) { + return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TNodeType.class, qname); + } + + public static String relationshipTypeQName2href(QName qname) { + return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TRelationshipType.class, qname); + } + + public static String policyTypeQName2href(QName qname) { + return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TPolicyType.class, qname); + } + + /** + * Returns the middle part of the package name or the JSP location + * + * @param type the type + * @param separator the separator to be used, "." or "/" + * @return string which can be used "in the middle" of a package or of a + * path to a JSP + */ + public static String getIntermediateLocationStringForType(String type, String separator) { + String location; + if (type.contains("ServiceTemplate")) { + location = "servicetemplates"; + } else { + if (type.contains("TypeImplementation")) { + location = "entitytypeimplementations"; + } else if (type.contains("Type")) { + location = "entitytypes"; + } else if (type.contains("Import")) { + location = "imports"; + } else { + assert (type.contains("Template")); + location = "entitytemplates"; + } + // location now is the super pkg, we have to add a pkg of the type + location = location + separator + type.toLowerCase() + "s"; + } + return location; + } + + /** + * Required by topologyedit.jsp + * + * @return all known nodetype resources + */ + public static Collection<NodeTypeResource> getAllNodeTypeResources() { + @SuppressWarnings("unchecked") + Collection<NodeTypeResource> res = (Collection<NodeTypeResource>) (Collection<?>) new NodeTypesResource().getAll(); + return res; + } + + /** + * Required by topologyedit.jsp + * + * @return all known relation ship type resources + */ + public static Collection<RelationshipTypeResource> getAllRelationshipTypeResources() { + @SuppressWarnings("unchecked") + Collection<RelationshipTypeResource> res = (Collection<RelationshipTypeResource>) (Collection<?>) new RelationshipTypesResource().getAll(); + return res; + } + + /** + * @return the path to the Winery topology modeler. Required by + * functions.tld + */ + public static String getWineryTopologyModelerPath() { + return Prefs.INSTANCE.getWineryTopologyModelerPath(); + } + + /** + * Detect the mime type of the stream. The stream is marked at the beginning + * and reset at the end + * + * @param is the stream + * @param fileName the fileName of the file belonging to the stream + */ + public static String getMimeType(BufferedInputStream bis, String fn) throws IOException { + AutoDetectParser parser = new AutoDetectParser(); + Detector detector = parser.getDetector(); + Metadata md = new Metadata(); + md.add(Metadata.RESOURCE_NAME_KEY, fn); + org.apache.tika.mime.MediaType mediaType = detector.detect(bis, md); + return mediaType.toString(); + } + + + private static final MediaType MEDIATYPE_APPLICATION_OCTET_STREAM = MediaType.valueOf("application/octet-stream"); + + + /** + * Fixes the mediaType if it is too vague (such as application/octet-stream) + * + * @return a more fitting MediaType or the original one if it is appropriate + * enough + */ + public static MediaType getFixedMimeType(BufferedInputStream is, String fileName, MediaType mediaType) { + if (mediaType.equals(Utils.MEDIATYPE_APPLICATION_OCTET_STREAM)) { + // currently, we fix application/octet-stream only + + // TODO: instead of using apache tika, we could hve a user-configured map storing + // * media type + // * file extension + + try { + return MediaType.valueOf(Utils.getMimeType(is, fileName)); + } catch (Exception e) { + Utils.logger.debug("Could not determine mimetype for " + fileName, e); + // just keep the old one + return mediaType; + } + } else { + return mediaType; + } + } + + /** + * Converts the given object to XML. + * + * Used in cases the given element is not annotated with @XmlRoot + * + * We cannot use {@literal Class<? extends TExtensibleElements>} as, for + * instance, {@link TConstraint} does not inherit from + * {@link TExtensibleElements} + * + * @param clazz the Class of the passed object, required if obj is null + * @param obj the object to serialize + */ + public static <T extends Object> Response getXML(Class<T> clazz, T obj) { + // see commit ab4b5c547619c058990 for an implementation using getJAXBElement, + // which can be directly passed as entity + // the issue is that we want to have a *formatted* XML + // Therefore, we serialize "by hand". + String xml = Utils.getXMLAsString(clazz, obj, false); + + return Response.ok().type(MediaType.TEXT_XML).entity(xml).build(); + } + + public static <T extends Object> String getXMLAsString(Class<T> clazz, T obj, boolean includeProcessingInstruction) { + JAXBElement<T> rootElement = Util.getJAXBElement(clazz, obj); + Marshaller m = JAXBSupport.createMarshaller(includeProcessingInstruction); + StringWriter w = new StringWriter(); + try { + m.marshal(rootElement, w); + } catch (JAXBException e) { + Utils.logger.error("Could not put content to string", e); + throw new IllegalStateException(e); + } + String res = w.toString(); + return res; + } + + public static String getXMLAsString(Object obj) { + if (obj instanceof Element) { + // in case the object is a DOM element, we use the DOM functionality + return Util.getXMLAsString((Element) obj); + } else { + return Utils.getXMLAsString(obj, false); + } + } + + public static <T extends Object> String getXMLAsString(T obj, boolean includeProcessingInstruction) { + if (obj == null) { + return ""; + } + @SuppressWarnings("unchecked") + Class<T> clazz = (Class<T>) obj.getClass(); + return Utils.getXMLAsString(clazz, obj, includeProcessingInstruction); + } + + public static String getAllXSDElementDefinitionsForTypeAheadSelection() { + Utils.logger.entry(); + try { + return Utils.getAllXSDefinitionsForTypeAheadSelection(XSConstants.ELEMENT_DECLARATION); + } finally { + Utils.logger.exit(); + } + } + + public static String getAllXSDTypeDefinitionsForTypeAheadSelection() { + Utils.logger.entry(); + try { + return Utils.getAllXSDefinitionsForTypeAheadSelection(XSConstants.TYPE_DEFINITION); + } finally { + Utils.logger.exit(); + } + } + + public static String getAllXSDefinitionsForTypeAheadSelection(short type) { + SortedSet<XSDImportId> allImports = Repository.INSTANCE.getAllTOSCAComponentIds(XSDImportId.class); + + Map<Namespace, Collection<String>> data = new HashMap<Namespace, Collection<String>>(); + + for (XSDImportId id : allImports) { + XSDImportResource resource = new XSDImportResource(id); + Collection<String> allLocalNames = resource.getAllDefinedLocalNames(type); + + Collection<String> list; + if ((list = data.get(id.getNamespace())) == null) { + // list does not yet exist + list = new ArrayList<String>(); + data.put(id.getNamespace(), list); + } + assert (list != null); + + list.addAll(allLocalNames); + } + + ArrayNode rootNode = Utils.mapper.createArrayNode(); + + // ensure ordering in JSON object + Collection<Namespace> allns = new TreeSet<Namespace>(); + allns.addAll(data.keySet()); + + for (Namespace ns : allns) { + Collection<String> localNames = data.get(ns); + if (!localNames.isEmpty()) { + ObjectNode groupEntry = Utils.mapper.createObjectNode(); + rootNode.add(groupEntry); + groupEntry.put("text", ns.getDecoded()); + ArrayNode children = Utils.mapper.createArrayNode(); + groupEntry.put("children", children); + Collection<String> sortedLocalNames = new TreeSet<String>(); + sortedLocalNames.addAll(localNames); + for (String localName : sortedLocalNames) { + String value = "{" + ns.getDecoded() + "}" + localName; + String text = localName; + ObjectNode o = Utils.mapper.createObjectNode(); + o.put("text", text); + o.put("value", value); + children.add(o); + } + } + } + + try { + return Utils.mapper.writeValueAsString(rootNode); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Could not create JSON", e); + } + } + + public static Response getResponseForException(Exception e) { + String msg; + if (e.getCause() != null) { + msg = e.getCause().getMessage(); + } else { + msg = e.getMessage(); + } + Response res = Response.status(Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + return res; + } + + /** + * Returns the stored type for the given template + * + * Goes to the repository to retrieve stored data + * + * @param template the template to determine the type for + */ + // we suppress "unchecked" as we use Class.forName + @SuppressWarnings("unchecked") + public static TEntityType getTypeForTemplate(TEntityTemplate template) { + QName type = template.getType(); + + // Possibilities: + // a) try all possibly types whether an appropriate QName exists + // b) derive type class from template class. Determine appropriate resource afterwards. + // We go for b) + + String instanceResourceClassName = template.getClass().toString(); + int idx = instanceResourceClassName.lastIndexOf('.'); + // get everything from ".T", where "." is the last dot + instanceResourceClassName = instanceResourceClassName.substring(idx + 2); + // strip off "Template" + instanceResourceClassName = instanceResourceClassName.substring(0, instanceResourceClassName.length() - "Template".length()); + // add "Type" + instanceResourceClassName += "Type"; + + // an id is required to instantiate the resource + String idClassName = "org.eclipse.winery.common.ids.definitions." + instanceResourceClassName + "Id"; + + String packageName = "org.eclipse.winery.repository.resources.entitytypes." + instanceResourceClassName.toLowerCase() + "s"; + // convert from NodeType to NodeTypesResource + instanceResourceClassName += "Resource"; + instanceResourceClassName = packageName + "." + instanceResourceClassName; + + Utils.logger.debug("idClassName: {}", idClassName); + Utils.logger.debug("className: {}", instanceResourceClassName); + + // Get instance of id class having "type" as id + Class<? extends TOSCAComponentId> idClass; + try { + idClass = (Class<? extends TOSCAComponentId>) Class.forName(idClassName); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not determine id class", e); + } + Constructor<? extends TOSCAComponentId> idConstructor; + try { + idConstructor = idClass.getConstructor(QName.class); + } catch (NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Could not get QName id constructor", e); + } + TOSCAComponentId typeId; + try { + typeId = idConstructor.newInstance(type); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + throw new IllegalStateException("Could not instantiate type", e); + } + + // now instantiate the resource, where the type belongs to + Class<? extends AbstractComponentInstanceResource> instanceResourceClass; + try { + instanceResourceClass = (Class<? extends AbstractComponentInstanceResource>) Class.forName(instanceResourceClassName); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not determine component instance resource class", e); + } + Constructor<? extends AbstractComponentInstanceResource> resConstructor; + try { + resConstructor = instanceResourceClass.getConstructor(typeId.getClass()); + } catch (NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Could not get contructor", e); + } + AbstractComponentInstanceResource typeResource; + try { + typeResource = resConstructor.newInstance(typeId); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + throw new IllegalStateException("Could not instantiate resoruce", e); + } + + // read the data from the resource and store it + TEntityType entityType = (TEntityType) typeResource.getElement(); + + return entityType; + } + + /** + * referenced by functions.tld + */ + public static Boolean isContainerLocallyAvailable() { + return Prefs.INSTANCE.isContainerLocallyAvailable(); + } + + /** + * referenced by functions.tld + * + * We need the bridge as functions (at tld) require a static method. We did + * not want to put two methods in Prefs and therefore, we put the method + * here. + */ + public static Boolean isRestDocDocumentationAvailable() { + return Prefs.INSTANCE.isRestDocDocumentationAvailable(); + } + + public static boolean isSuccessFulResponse(Response res) { + return Status.fromStatusCode(res.getStatus()).getFamily().equals(Family.SUCCESSFUL); + } + + /** + * Converts the given String to an integer. Fallback if String is a float. + * If String is an invalid number, "0" is returned + */ + public static int convertStringToInt(String number) { + int intTop = 0; + try { + intTop = Integer.parseInt(number); + } catch (NumberFormatException e) { + try { + float floatTop = Float.parseFloat(number); + intTop = Math.round(floatTop); + } catch (NumberFormatException e2) { + // do nothing + } + } + + return intTop; + } + + /** + * Checks whether a given resource (with absolute URL!) is available with a + * HEAD request on it. + */ + public static boolean isResourceAvailable(String path) { + Client client = Client.create(); + WebResource wr = client.resource(path); + boolean res; + try { + ClientResponse response = wr.head(); + res = (response.getClientResponseStatus().getFamily().equals(Family.SUCCESSFUL)); + } catch (com.sun.jersey.api.client.ClientHandlerException ex) { + // In the case of a java.net.ConnectException, return false + res = false; + } + return res; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java new file mode 100644 index 0000000..6417df6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.io.IOUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides basic implementations for {@link IRepository} + */ +public abstract class AbstractRepository implements IRepository { + + private static final Logger logger = LoggerFactory.getLogger(AbstractRepository.class); + + + /** + * + * @param ref the file reference to store the mime type for + * @return a reference to the file holding the mime type + */ + private RepositoryFileReference getMimeFileRef(RepositoryFileReference ref) { + String fileName = ref.getFileName() + Constants.SUFFIX_MIMETYPE; + RepositoryFileReference mimeFileRef = new RepositoryFileReference(ref.getParent(), fileName); + return mimeFileRef; + } + + /** + * {@inheritDoc} + * + * This is a simple implementation using the information put by + * setMimeType(RepositoryFileReference ref) or determining the mime type + * using Utils.getMimeType. If the latter is done, the mime type is + * persisted using setMimeType + */ + @Override + public String getMimeType(RepositoryFileReference ref) throws IOException { + RepositoryFileReference mimeFileRef = this.getMimeFileRef(ref); + String mimeType; + if (this.exists(mimeFileRef)) { + InputStream is = this.newInputStream(mimeFileRef); + mimeType = IOUtils.toString(is, "UTF-8"); + is.close(); + } else { + // repository has been manipulated manually, + // create mimetype information + mimeType = null; + try (InputStream is = this.newInputStream(ref); + BufferedInputStream bis = new BufferedInputStream(is);) { + mimeType = Utils.getMimeType(bis, ref.getFileName()); + } + if (mimeType != null) { + // successful execution + this.setMimeType(ref, MediaType.valueOf(mimeType)); + } else { + AbstractRepository.logger.debug("Could not determine mimetype"); + } + } + return mimeType; + } + + /** + * Stores the mime type of the given file reference in a separate file + * + * This method calls putContentToFile(), where the filename is appended with + * Constants.SUFFIX_MIMETYPE and a null mime type. The latter indicates that + * no "normal" file is stored. + * + * @param ref the file reference + * @param mediaType the mimeType + */ + protected void setMimeType(RepositoryFileReference ref, MediaType mediaType) throws IOException { + RepositoryFileReference mimeFileRef = this.getMimeFileRef(ref); + this.putContentToFile(mimeFileRef, mediaType.toString(), null); + } + + @Override + public Date getConfigurationLastUpdate(GenericId id) { + RepositoryFileReference ref = BackendUtils.getRefOfConfiguration(id); + return this.getLastUpdate(ref); + } + + @Override + public Configuration getConfiguration(GenericId id) { + RepositoryFileReference ref = BackendUtils.getRefOfConfiguration(id); + return this.getConfiguration(ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java new file mode 100644 index 0000000..eeddfba --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java @@ -0,0 +1,995 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.nio.file.attribute.FileTime; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.SortedSet; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.namespace.QName; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.XSImplementationImpl; +import org.apache.xerces.xs.XSComplexTypeDefinition; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSImplementation; +import org.apache.xerces.xs.XSLoader; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSModelGroup; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSParticle; +import org.apache.xerces.xs.XSTerm; +import org.apache.xerces.xs.XSTypeDefinition; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.IdUtil; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.definitions.EntityTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.common.ids.elements.PlansId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.ObjectFactory; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.JAXBSupport; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.datatypes.ids.admin.AdminId; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.admin.NamespacesResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportsResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.ls.LSInput; + +import com.sun.jersey.core.header.ContentDisposition; + +/** + * Contains generic utility functions for the Backend + * + * Contains everything that is useful for our ids etc. Does <em>not</em> contain + * anything that has to do with resources + */ +public class BackendUtils { + + private static final Logger logger = LoggerFactory.getLogger(BackendUtils.class); + + + /** + * Deletes given file/dir and returns appropriate response code + */ + public static Response delete(GenericId id) { + if (!Repository.INSTANCE.exists(id)) { + return Response.status(Status.NOT_FOUND).build(); + } + try { + Repository.INSTANCE.forceDelete(id); + } catch (IOException e) { + BackendUtils.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + return Response.noContent().build(); + } + + /** + * Deletes given file and returns appropriate response code + */ + public static Response delete(RepositoryFileReference ref) { + if (!Repository.INSTANCE.exists(ref)) { + return Response.status(Status.NOT_FOUND).build(); + } + try { + Repository.INSTANCE.forceDelete(ref); + } catch (IOException e) { + BackendUtils.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + return Response.ok().build(); + } + + /** + * Generates given TOSCA element and returns appropriate response code <br /> + * + * In the case of an existing resource, the other possible return code is + * 302. This code has no Status constant, therefore we use Status.CONFLICT, + * which is also possible. + * + * @return <ul> + * <li> + * <ul> + * <li>Status.CREATED (201) if the resource has been created,</li> + * <li>Status.CONFLICT if the resource already exists,</li> + * <li>Status.INTERNAL_SERVER_ERROR (500) if something went wrong</li> + * </ul> + * </li> + * <li>URI: the absolute URI of the newly created resource</li> + * </ul> + */ + public static ResourceCreationResult create(GenericId id) { + ResourceCreationResult res = new ResourceCreationResult(); + if (Repository.INSTANCE.exists(id)) { + // res.setStatus(302); + res.setStatus(Status.CONFLICT); + } else { + if (Repository.INSTANCE.flagAsExisting(id)) { + res.setStatus(Status.CREATED); + // @formatter:off + // This method is a generic method + // We cannot return an "absolute" URL as the URL is always + // relative to the caller + // Does not work: String path = Prefs.INSTANCE.getResourcePath() + // + "/" + + // Utils.getURLforPathInsideRepo(id.getPathInsideRepo()); + // We distinguish between two cases: TOSCAcomponentId and + // TOSCAelementId + // @formatter:on + String path; + if (id instanceof TOSCAComponentId) { + // here, we return namespace + id, as it is only possible to + // post on the TOSCA component*s* resource to create an + // instance of a TOSCA component + TOSCAComponentId tcId = (TOSCAComponentId) id; + path = tcId.getNamespace().getEncoded() + "/" + tcId.getXmlId().getEncoded() + "/"; + } else { + assert (id instanceof TOSCAElementId); + // We just return the id as we assume that only the parent + // of this id may create sub elements + path = id.getXmlId().getEncoded() + "/"; + } + // we have to encode it twice to get correct URIs + path = Utils.getURLforPathInsideRepo(path); + URI uri = Utils.createURI(path); + res.setUri(uri); + res.setId(id); + } else { + res.setStatus(Status.INTERNAL_SERVER_ERROR); + } + } + return res; + } + + /** + * + * Sends the file if modified and "not modified" if not modified future work + * may put each file with a unique id in a separate folder in tomcat * use + * that static URL for each file * if file is modified, URL of file changes + * * -> client always fetches correct file + * + * additionally "Vary: Accept" header is added (enables caching of the + * response) + * + * method header for calling method public <br /> + * <code>Response getXY(@HeaderParam("If-Modified-Since") String modified) {...}</code> + * + * + * @param ref references the file to be send + * @param modified - HeaderField "If-Modified-Since" - may be "null" + * @return Response to be sent to the client + */ + public static Response returnRepoPath(RepositoryFileReference ref, String modified) { + return BackendUtils.returnRefAsResponseBuilder(ref, modified).build(); + } + + /** + * @return true if given fileDate is newer then the modified date (or + * modified is null) + */ + public static boolean isFileNewerThanModifiedDate(long millis, String modified) { + if (modified == null) { + return true; + } + + Date modifiedDate = null; + + assert (Locale.getDefault() == Locale.ENGLISH); + try { + modifiedDate = DateUtils.parseDate(modified, org.apache.http.impl.cookie.DateUtils.DEFAULT_PATTERNS); + } catch (ParseException e) { + BackendUtils.logger.error(e.getMessage(), e); + } + + if (modifiedDate != null) { + // modifiedDate does not carry milliseconds, but fileDate does + // therefore we have to do a range-based comparison + if ((millis - modifiedDate.getTime()) < DateUtils.MILLIS_PER_SECOND) { + return false; + } + } + + return true; + } + + /** + * This is not repository specific, but we leave it close to the only caller + * + * If the passed ref is newer than the modified date (or the modified date + * is null), an OK response with an inputstream pointing to the path is + * returned + */ + private static ResponseBuilder returnRefAsResponseBuilder(RepositoryFileReference ref, String modified) { + if (!Repository.INSTANCE.exists(ref)) { + return Response.status(Status.NOT_FOUND); + } + + FileTime lastModified; + try { + lastModified = Repository.INSTANCE.getLastModifiedTime(ref); + } catch (IOException e1) { + BackendUtils.logger.debug("Could not get lastModifiedTime", e1); + return Response.serverError(); + } + + // do we really need to send the file or can send "not modified"? + if (!BackendUtils.isFileNewerThanModifiedDate(lastModified.toMillis(), modified)) { + return Response.status(Status.NOT_MODIFIED); + } + + ResponseBuilder res; + try { + res = Response.ok(Repository.INSTANCE.newInputStream(ref)); + } catch (IOException e) { + BackendUtils.logger.debug("Could not open input stream", e); + return Response.serverError(); + } + res = res.lastModified(new Date(lastModified.toMillis())); + // vary:accept header is always set to be safe + res = res.header(HttpHeaders.VARY, HttpHeaders.ACCEPT); + // determine and set MIME content type + try { + res = res.header(HttpHeaders.CONTENT_TYPE, Repository.INSTANCE.getMimeType(ref)); + } catch (IOException e) { + BackendUtils.logger.debug("Could not determine mime type", e); + return Response.serverError(); + } + // set filename + ContentDisposition contentDisposition = ContentDisposition.type("attachment").fileName(ref.getFileName()).modificationDate(new Date(lastModified.toMillis())).build(); + res.header("Content-Disposition", contentDisposition); + return res; + } + + /** + * Updates the given property in the given configuration. Currently always + * returns "no content", because the underlying class does not report any + * errors during updating. <br /> + * + * If null or "" is passed as value, the property is cleared + * + * @return Status.NO_CONTENT + */ + public static Response updateProperty(Configuration configuration, String property, String val) { + if (StringUtils.isBlank(val)) { + configuration.clearProperty(property); + } else { + configuration.setProperty(property, val); + } + return Response.noContent().build(); + } + + /** + * Persists the resource and returns appropriate response + */ + public static Response persist(IPersistable res) { + Response r; + try { + res.persist(); + } catch (IOException e) { + BackendUtils.logger.debug("Could not persist resource", e); + r = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + return r; + } + r = Response.noContent().build(); + return r; + } + + /** + * Writes data to file. Replaces the file's content with the given content. + * The file does not need to exist + * + * @param ref Reference to the File to write to (overwrite) + * @param content the data to write + * @return a JAX-RS Response containing the result. NOCONTENT if successful, + * InternalSeverError otherwise + */ + public static Response putContentToFile(RepositoryFileReference ref, String content, MediaType mediaType) { + try { + Repository.INSTANCE.putContentToFile(ref, content, mediaType); + } catch (IOException e) { + BackendUtils.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + return Response.noContent().build(); + } + + public static Response putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) { + try { + Repository.INSTANCE.putContentToFile(ref, inputStream, mediaType); + } catch (IOException e) { + BackendUtils.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + return Response.noContent().build(); + } + + public static <T extends TOSCAComponentId> T getTOSCAcomponentId(Class<T> idClass, String qnameStr) { + QName qname = QName.valueOf(qnameStr); + return BackendUtils.getTOSCAcomponentId(idClass, qname.getNamespaceURI(), qname.getLocalPart(), false); + } + + public static <T extends TOSCAComponentId> T getTOSCAcomponentId(Class<T> idClass, QName qname) { + // we got two implementation possibilities: one is to directly use the + // QName constructor, + // the other is to use a namespace, localname, urlencoded constructor + // we opt for the latter one, which forces the latter constructor to + // exist at all ids + return BackendUtils.getTOSCAcomponentId(idClass, qname.getNamespaceURI(), qname.getLocalPart(), false); + } + + public static <T extends TOSCAComponentId> T getTOSCAcomponentId(Class<T> idClass, String namespace, String id, boolean URLencoded) { + Constructor<T> constructor; + try { + constructor = idClass.getConstructor(String.class, String.class, boolean.class); + } catch (NoSuchMethodException | SecurityException e) { + BackendUtils.logger.error("Could not get constructor for id " + idClass.getName(), e); + throw new IllegalStateException(e); + } + T tcId; + try { + tcId = constructor.newInstance(namespace, id, URLencoded); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + BackendUtils.logger.error("Could not create id instance", e); + throw new IllegalStateException(e); + } + return tcId; + } + + /** + * @param id the id to determine the namespace of the parent for + * @return the namespace of the first TOSCAcomponentId found in the ID + * hierarchy + */ + public static Namespace getNamespace(TOSCAElementId id) { + GenericId parent = id.getParent(); + while (!(parent instanceof TOSCAComponentId)) { + parent = parent.getParent(); + } + return ((TOSCAComponentId) parent).getNamespace(); + } + + public static String getName(TOSCAComponentId instanceId) { + // TODO: Here is a performance issue as we don't use caching or a database + // Bad, but without performance loss: Use "text = instanceId.getXmlId().getDecoded();" + TExtensibleElements instanceElement = AbstractComponentsResource.getComponentInstaceResource(instanceId).getElement(); + return ModelUtilities.getNameWithIdFallBack(instanceElement); + } + +/** + * Do <em>not</em> use this for creating URLs. Use + * + * {@link org.eclipse.winery.repository.Utils.getURLforPathInsideRepo(String)} + * + * or + * + * {@link org.eclipse.winery.repository.Utils.getAbsoluteURL(GenericId) + * instead. + * + * @return the path starting from the root element to the current element. + * Separated by "/", URLencoded, but <b>not</b> double encoded. With + * trailing slash if sub-resources can exist + * @throws IllegalStateException if id is of an unknown subclass of id + */ + public static String getPathInsideRepo(GenericId id) { + if (id == null) { + throw new NullPointerException("id is null"); + } + + // for creating paths see also org.eclipse.winery.repository.Utils.getIntermediateLocationStringForType(String, String) + // and org.eclipse.winery.common.Util.getRootPathFragment(Class<? extends TOSCAcomponentId>) + if (id instanceof AdminId) { + return "admin/" + id.getXmlId().getEncoded() + "/"; + } else if (id instanceof GenericImportId) { + GenericImportId i = (GenericImportId) id; + String res = "imports/"; + res = res + Util.URLencode(i.getType()) + "/"; + res = res + i.getNamespace().getEncoded() + "/"; + res = res + i.getXmlId().getEncoded() + "/"; + return res; + } else if (id instanceof TOSCAComponentId) { + return IdUtil.getPathFragment(id); + } else if (id instanceof TOSCAElementId) { + // we cannot reuse IdUtil.getPathFragment(id) as this TOSCAelementId + // might be nested in an AdminId + return BackendUtils.getPathInsideRepo(id.getParent()) + id.getXmlId().getEncoded() + "/"; + } else { + throw new IllegalStateException("Unknown subclass of GenericId " + id.getClass()); + } + } + +/** + * Do <em>not</em> use this for creating URLs. Use + * + * {@link org.eclipse.winery.repository.Utils.getURLforPathInsideRepo(String)} + * + * or + * + * {@link org.eclipse.winery.repository.Utils.getAbsoluteURL(GenericId) + * instead. + * + * @return the path starting from the root element to the current element. + * Separated by "/", parent URLencoded. Without trailing slash. + */ + public static String getPathInsideRepo(RepositoryFileReference ref) { + return BackendUtils.getPathInsideRepo(ref.getParent()) + ref.getFileName(); + } + + /** + * Returns the reference to the definitions XML storing the TOSCA for the + * given id + * + * @param id the id to lookup + * @return the reference + */ + public static RepositoryFileReference getRefOfDefinitions(TOSCAComponentId id) { + String name = Util.getTypeForComponentId(id.getClass()); + name = name + Constants.SUFFIX_TOSCA_DEFINITIONS; + RepositoryFileReference ref = new RepositoryFileReference(id, name); + return ref; + } + + /** + * Returns the reference to the properties file storing the TOSCA + * information for the given id + * + * @param id the id to lookup + * @return the reference + */ + public static RepositoryFileReference getRefOfConfiguration(GenericId id) { + String name; + // Hack to determine file name + if (id instanceof TOSCAComponentId) { + name = Util.getTypeForComponentId(((TOSCAComponentId) id).getClass()); + name = name + Constants.SUFFIX_PROPERTIES; + } else if (id instanceof AdminId) { + name = Utils.getTypeForAdminId(((AdminId) id).getClass()); + name = name + Constants.SUFFIX_PROPERTIES; + } else { + assert (id instanceof TOSCAElementId); + TOSCAElementId tId = (TOSCAElementId) id; + if (tId instanceof PlansId) { + name = Filename.FILENAME_PROPERTIES_PLANCONTAINER; + } else if (tId instanceof VisualAppearanceId) { + // quick hack for special name here + name = Filename.FILENAME_PROPERTIES_VISUALAPPEARANCE; + } else { + name = Util.getTypeForElementId(tId.getClass()) + Constants.SUFFIX_PROPERTIES; + } + } + + RepositoryFileReference ref = new RepositoryFileReference(id, name); + return ref; + } + + /** + * @param qNameOfTheType the QName of the type, where all TOSCAComponentIds, + * where the associated element points to the type + * @param clazz the Id class of the entities to discover + */ + public static <X extends TOSCAComponentId> Collection<X> getAllElementsRelatedWithATypeAttribute(Class<X> clazz, QName qNameOfTheType) { + // we do not use any database system, + // therefore we have to crawl through each node type implementation by ourselves + SortedSet<X> allIds = Repository.INSTANCE.getAllTOSCAComponentIds(clazz); + Collection<X> res = new HashSet<>(); + for (X id : allIds) { + IHasTypeReference resource; + try { + resource = (IHasTypeReference) AbstractComponentsResource.getComponentInstaceResource(id); + } catch (ClassCastException e) { + String error = "Requested following the type, but the component instance does not implmenet IHasTypeReference"; + BackendUtils.logger.error(error); + throw new IllegalStateException(error); + } + // The resource may have been freshly initialized due to existence of a directory + // then it has no node type assigned leading to ntiRes.getType() being null + // we ignore this error here + if (qNameOfTheType.equals(resource.getType())) { + // the component instance is an implementation of the associated node type + res.add(id); + } + } + return res; + } + + /** + * Returns a list of the topology template nested in the given service + * template + */ + public static List<TNodeTemplate> getAllNestedNodeTemplates(TServiceTemplate serviceTemplate) { + List<TNodeTemplate> l = new ArrayList<TNodeTemplate>(); + TTopologyTemplate topologyTemplate = serviceTemplate.getTopologyTemplate(); + if (topologyTemplate == null) { + return Collections.emptyList(); + } + for (TEntityTemplate t : topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (t instanceof TNodeTemplate) { + l.add((TNodeTemplate) t); + } + } + return l; + } + + private static Collection<QName> getAllReferencedArtifactTemplates(TDeploymentArtifacts tDeploymentArtifacts) { + if (tDeploymentArtifacts == null) { + return Collections.emptyList(); + } + List<TDeploymentArtifact> deploymentArtifacts = tDeploymentArtifacts.getDeploymentArtifact(); + if (deploymentArtifacts == null) { + return Collections.emptyList(); + } + Collection<QName> res = new ArrayList<>(); + for (TDeploymentArtifact da : deploymentArtifacts) { + QName artifactRef = da.getArtifactRef(); + if (artifactRef != null) { + res.add(artifactRef); + } + } + return res; + } + + private static Collection<QName> getAllReferencedArtifactTemplates(TImplementationArtifacts tImplementationArtifacts) { + if (tImplementationArtifacts == null) { + return Collections.emptyList(); + } + List<ImplementationArtifact> implementationArtifacts = tImplementationArtifacts.getImplementationArtifact(); + if (implementationArtifacts == null) { + return Collections.emptyList(); + } + Collection<QName> res = new ArrayList<>(); + for (ImplementationArtifact ia : implementationArtifacts) { + QName artifactRef = ia.getArtifactRef(); + if (artifactRef != null) { + res.add(artifactRef); + } + } + return res; + } + + public static Collection<QName> getArtifactTemplatesOfReferencedDeploymentArtifacts(TNodeTemplate nodeTemplate) { + List<QName> l = new ArrayList<QName>(); + + // DAs may be assigned directly to a node template + Collection<QName> allReferencedArtifactTemplates = BackendUtils.getAllReferencedArtifactTemplates(nodeTemplate.getDeploymentArtifacts()); + l.addAll(allReferencedArtifactTemplates); + + // DAs may be assigned via node type implementations + QName nodeTypeQName = nodeTemplate.getType(); + Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, nodeTypeQName); + for (NodeTypeImplementationId nodeTypeImplementationId : allNodeTypeImplementations) { + NodeTypeImplementationResource ntiRes = new NodeTypeImplementationResource(nodeTypeImplementationId); + allReferencedArtifactTemplates = BackendUtils.getAllReferencedArtifactTemplates(ntiRes.getNTI().getDeploymentArtifacts()); + l.addAll(allReferencedArtifactTemplates); + } + + return l; + } + + public static Collection<QName> getArtifactTemplatesOfReferencedImplementationArtifacts(TNodeTemplate nodeTemplate) { + List<QName> l = new ArrayList<QName>(); + + // IAs may be assigned via node type implementations + QName nodeTypeQName = nodeTemplate.getType(); + Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, nodeTypeQName); + for (NodeTypeImplementationId nodeTypeImplementationId : allNodeTypeImplementations) { + NodeTypeImplementationResource ntiRes = new NodeTypeImplementationResource(nodeTypeImplementationId); + Collection<QName> allReferencedArtifactTemplates = BackendUtils.getAllReferencedArtifactTemplates(ntiRes.getNTI().getImplementationArtifacts()); + l.addAll(allReferencedArtifactTemplates); + } + + return l; + } + + /** + * Creates a new TDefintions element wrapping a TOSCA Component instance. + * The namespace of the tosca component is used as namespace and + * {@code winery-defs-for-} concatenated with the (unique) ns prefix and + * idOfContainedElement is used as id + * + * @param toscAcomponentId the id of the element the wrapper is used for + * + * @return a definitions element prepared for wrapping a TOSCA component + * instance + */ + public static Definitions createWrapperDefinitions(TOSCAComponentId tcId) { + ObjectFactory of = new ObjectFactory(); + Definitions defs = of.createDefinitions(); + + // set target namespace + // an internal namespace is not possible + // a) tPolicyTemplate and tArtfactTemplate do NOT support the "targetNamespace" attribute + // b) the imports statement would look bad as it always imported the artificial namespace + defs.setTargetNamespace(tcId.getNamespace().getDecoded()); + + // set a unique id to create a valid definitions element + // we do not use UUID to be more human readable and deterministic (for debugging) + String prefix = NamespacesResource.getPrefix(tcId.getNamespace()); + String elId = tcId.getXmlId().getDecoded(); + String id = "winery-defs-for_" + prefix + "-" + elId; + defs.setId(id); + + return defs; + } + + /** + * @throws IOException if content could not be updated in the repository + * @throws IllegalStateException if an JAXBException occurred. This should + * never happen. + */ + public static void persist(Object o, RepositoryFileReference ref, MediaType mediaType) throws IOException { + // We assume that the object is not too large + // Otherwise, http://io-tools.googlecode.com/svn/www/easystream/apidocs/index.html should be used + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Marshaller m; + try { + m = JAXBSupport.createMarshaller(true); + m.marshal(o, out); + } catch (JAXBException e) { + BackendUtils.logger.error("Could not put content to file", e); + throw new IllegalStateException(e); + } + byte[] data = out.toByteArray(); + ByteArrayInputStream in = new ByteArrayInputStream(data); + // this may throw an IOExcpetion. We propagate this exception. + Repository.INSTANCE.putContentToFile(ref, in, mediaType); + } + + /** + * Updates the color if the color is not yet existent + * + * @param name the name of the component. Used as basis for a generated + * color + * @param qname the QName of the color attribute + * @param otherAttributes the plain "XML" attributes. They are used to check + * @param res + */ + public static String getColorAndSetDefaultIfNotExisting(String name, QName qname, Map<QName, String> otherAttributes, TopologyGraphElementEntityTypeResource res) { + String colorStr = otherAttributes.get(qname); + if (colorStr == null) { + colorStr = Util.getColor(name); + otherAttributes.put(qname, colorStr); + BackendUtils.persist(res); + } + return colorStr; + } + + /** + * + * @param tcId The element type id to get the location for + * @param uri uri to use if in XML export mode, null if in CSAR export mode + * @param wrapperElementLocalName the local name of the wrapper element + * @return + */ + public static String getImportLocationForWinerysPropertiesDefinitionXSD(EntityTypeId tcId, URI uri, String wrapperElementLocalName) { + String loc = BackendUtils.getPathInsideRepo(tcId); + loc = loc + "propertiesdefinition/"; + loc = Utils.getURLforPathInsideRepo(loc); + if (uri == null) { + loc = loc + wrapperElementLocalName + ".xsd"; + // for the import later, we need "../" in front + loc = "../" + loc; + } else { + loc = uri + loc + "xsd"; + } + return loc; + } + + /** + * @param ref the file to read from + */ + public static XSModel getXSModel(final RepositoryFileReference ref) { + if (ref == null) { + return null; + } + final InputStream is; + try { + is = Repository.INSTANCE.newInputStream(ref); + } catch (IOException e) { + BackendUtils.logger.debug("Could not create input stream", e); + return null; + } + + // we rely on xerces to parse the XSD + // idea based on http://stackoverflow.com/a/5165177/873282 + XSImplementation impl = new XSImplementationImpl(); + XSLoader schemaLoader = impl.createXSLoader(null); + + // minimal LSInput implementation sufficient for XSLoader in Oracle's JRE7 + LSInput input = new LSInput() { + + @Override + public void setSystemId(String systemId) { + } + + @Override + public void setStringData(String stringData) { + } + + @Override + public void setPublicId(String publicId) { + } + + @Override + public void setEncoding(String encoding) { + } + + @Override + public void setCharacterStream(Reader characterStream) { + } + + @Override + public void setCertifiedText(boolean certifiedText) { + } + + @Override + public void setByteStream(InputStream byteStream) { + } + + @Override + public void setBaseURI(String baseURI) { + } + + @Override + public String getSystemId() { + return null; + } + + @Override + public String getStringData() { + return null; + } + + @Override + public String getPublicId() { + return BackendUtils.getPathInsideRepo(ref); + } + + @Override + public String getEncoding() { + return "UTF-8"; + } + + @Override + public Reader getCharacterStream() { + try { + return new InputStreamReader(is, "UTF-8"); + } catch (UnsupportedEncodingException e) { + System.out.println("exeption"); + throw new IllegalStateException("UTF-8 is unkown", e); + } + } + + @Override + public boolean getCertifiedText() { + return false; + } + + @Override + public InputStream getByteStream() { + return null; + } + + @Override + public String getBaseURI() { + return null; + } + }; + XSModel model = schemaLoader.load(input); + return model; + } + + /** + * Derives Winery's Properties Definition from an existing properties + * definition + * + * @param ci the entity type to try to modify the WPDs + * @param errors the list to add errors to + */ + public static void deriveWPD(TEntityType ci, List<String> errors) { + BackendUtils.logger.trace("deriveWPD"); + PropertiesDefinition propertiesDefinition = ci.getPropertiesDefinition(); + QName element = propertiesDefinition.getElement(); + if (element == null) { + BackendUtils.logger.debug("only works for an element definition, not for types"); + } else { + BackendUtils.logger.debug("Looking for the definition of {" + element.getNamespaceURI() + "}" + element.getLocalPart()); + // fetch the XSD defining the element + XSDImportsResource importsRes = new XSDImportsResource(); + Map<String, RepositoryFileReference> mapFromLocalNameToXSD = importsRes.getMapFromLocalNameToXSD(element.getNamespaceURI(), false); + RepositoryFileReference ref = mapFromLocalNameToXSD.get(element.getLocalPart()); + if (ref == null) { + String msg = "XSD not found for " + element.getNamespaceURI() + " / " + element.getLocalPart(); + BackendUtils.logger.debug(msg); + errors.add(msg); + return; + } + + XSModel xsModel = BackendUtils.getXSModel(ref); + XSElementDeclaration elementDeclaration = xsModel.getElementDeclaration(element.getLocalPart(), element.getNamespaceURI()); + if (elementDeclaration == null) { + String msg = "XSD model claimed to contain declaration for {" + element.getNamespaceURI() + "}" + element.getLocalPart() + ", but it did not."; + BackendUtils.logger.debug(msg); + errors.add(msg); + return; + } + + // go through the XSD definition and + XSTypeDefinition typeDefinition = elementDeclaration.getTypeDefinition(); + if (typeDefinition instanceof XSComplexTypeDefinition) { + XSComplexTypeDefinition cTypeDefinition = (XSComplexTypeDefinition) typeDefinition; + XSParticle particle = cTypeDefinition.getParticle(); + if (particle == null) { + BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Complex type does not contain particles"); + } else { + XSTerm term = particle.getTerm(); + if (term instanceof XSModelGroup) { + XSModelGroup modelGroup = (XSModelGroup) term; + if (modelGroup.getCompositor() == XSModelGroup.COMPOSITOR_SEQUENCE) { + XSObjectList particles = modelGroup.getParticles(); + int len = particles.getLength(); + boolean everyThingIsASimpleType = true; + PropertyDefinitionKVList list = new PropertyDefinitionKVList(); + if (len != 0) { + for (int i = 0; i < len; i++) { + XSParticle innerParticle = (XSParticle) particles.item(i); + XSTerm innerTerm = innerParticle.getTerm(); + if (innerTerm instanceof XSElementDeclaration) { + XSElementDeclaration innerElementDeclaration = (XSElementDeclaration) innerTerm; + String name = innerElementDeclaration.getName(); + XSTypeDefinition innerTypeDefinition = innerElementDeclaration.getTypeDefinition(); + if (innerTypeDefinition instanceof XSSimpleType) { + XSSimpleType xsSimpleType = (XSSimpleType) innerTypeDefinition; + String typeNS = xsSimpleType.getNamespace(); + String typeName = xsSimpleType.getName(); + if (typeNS.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) { + PropertyDefinitionKV def = new PropertyDefinitionKV(); + def.setKey(name); + // convention at WPD: use "xsd" as prefix for XML Schema Definition + def.setType("xsd:" + typeName); + list.add(def); + } else { + everyThingIsASimpleType = false; + break; + } + } else { + everyThingIsASimpleType = false; + break; + } + } else { + everyThingIsASimpleType = false; + break; + } + } + } + if (everyThingIsASimpleType) { + // everything went allright, we can add a WPD + WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition(); + wpd.setIsDerivedFromXSD(Boolean.TRUE); + wpd.setElementName(element.getLocalPart()); + wpd.setNamespace(element.getNamespaceURI()); + wpd.setPropertyDefinitionKVList(list); + ModelUtilities.replaceWinerysPropertiesDefinition(ci, wpd); + BackendUtils.logger.debug("Successfully generated WPD"); + } else { + BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Not all types in the sequence are simple types"); + } + } else { + BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Model group is not a sequence"); + } + } else { + BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Not a model group"); + } + } + } else { + BackendUtils.logger.debug("XSD does not follow the requirements put by winery: No Complex Type Definition"); + } + } + } + + /** + * Returns all components available of the given id type + * + * Similar functionality as {@link + * org.eclipse.winery.repository.backend.IGenericRepository. + * getAllTOSCAComponentIds(Class<T>)}, but it crawls through the repository + * + * This method is required as we do not use a database. + * + * @param idClass class of the Ids to search for + * @return empty set if no ids are available + */ + public <T extends TOSCAElementId> SortedSet<T> getAllTOSCAElementIds(Class<T> idClass) { + throw new IllegalStateException("Not yet implemented"); + + /* + Implementation idea: + * switch of instance of idClass + * nodetemplate / relationshiptemplate -> fetch all service templates -> crawl through topology -> add all to res + * req/cap do as above, but inspect nodetemplate + * (other special handlings; check spec where each type can be linked from) + */ + } + + /** + * Converts the given collection of TOSCA Component Ids to a collection of + * QNames by using the getQName() method. + * + * This is required for QNameChooser.tag + */ + public static Collection<QName> convertTOSCAComponentIdCollectionToQNameCollection(Collection<? extends TOSCAComponentId> col) { + Collection<QName> res = new ArrayList<>(); + for (TOSCAComponentId id : col) { + res.add(id.getQName()); + } + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java new file mode 100644 index 0000000..9e7ba66 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.attribute.FileTime; +import java.util.Collection; +import java.util.Date; +import java.util.SortedSet; + +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.common.interfaces.IWineryRepositoryCommon; + +/** + * Enables access to the winery repository via Ids defined in package + * {@link org.eclipse.winery.common.ids} + * + * In contrast to {@link org.eclipse.winery.repository.backend.IRepository}, + * this is NOT dependent on a particular storage format for the properties. + * These two classes exist to make the need for reengineering explicit. + * + * This is a first attempt to offer methods via GenericId. It might happen, that + * methods, where GenericIds make sense, are simply added to "IWineryRepository" + * instead of being added here. + * + * The ultimate goal is to get rid of this class and to have + * IWineryRepositoryCommon only. + * + * Currently, this class is used internally only + */ +interface IGenericRepository extends IWineryRepositoryCommon { + + /** + * Flags the given TOSCA element as existing. The resources itself create + * appropriate data files. + * + * Pre-Condition: !exists(id)<br/> + * Post-Condition: exists(id) + * + * Typically, the given TOSCA element is created if a configuration is asked + * for + * + * @param id + * @return + */ + public boolean flagAsExisting(GenericId id); + + /** + * Checks whether the associated TOSA element exists + * + * @param id the id to check + * @return true iff the TOSCA element belonging to the given ID exists + */ + public boolean exists(GenericId id); + + /** + * Deletes the referenced object from the repository + * + * @param ref + */ + public void forceDelete(RepositoryFileReference ref) throws IOException; + + /** + * @param ref reference to check + * @return true if the file associated with the given reference exists + */ + public boolean exists(RepositoryFileReference ref); + + /** + * Puts the given content to the given file. Replaces existing content. + * + * If the parent of the reference does not exist, it is created. + * + * @param ref the reference to the file. Must not be null. + * @param content the content to put into the file. Must not be null. + * @param mediaType the media type of the file. Must not be null. + * + * @throws IOException if something goes wrong + */ + public void putContentToFile(RepositoryFileReference ref, String content, MediaType mediaType) throws IOException; + + /** + * Puts the given content to the given file. Replaces existing content. + * + * If the parent of the reference does not exist, it is created. + * + * @param ref the reference to the file + * @param content the content to put into the file + * @throws IOException if something goes wrong + */ + public void putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) throws IOException; + + /** + * Creates an opened inputStream of the contents referenced by ref. The + * stream has to be closed by the caller. + * + * @param ref the reference to the file + * @return an inputstream + * @throws IOException if something goes wrong + */ + public InputStream newInputStream(RepositoryFileReference ref) throws IOException; + + /** + * Returns the size of the file referenced by ref + * + * @param ref a refernce to the file stored in the repository + * @return the size in bytes + * @throws IOException if something goes wrong + */ + long getSize(RepositoryFileReference ref) throws IOException; + + /** + * Returns the last modification time of the entry. + * + * @param ref the reference to the file + * @return the time of the last modification + * @throws IOException if something goes wrong + */ + FileTime getLastModifiedTime(RepositoryFileReference ref) throws IOException; + + /** + * Returns the mimetype belonging to the reference. + * + * @param ref the reference to the file + * @return the mimetype as string + * @throws IOException if something goes wrong + * @throws IllegalStateException if an internal error occurs, which is not + * an IOException + */ + String getMimeType(RepositoryFileReference ref) throws IOException; + + /** + * @return the last change date of the file belonging to the given + * reference. NULL if the associated file does not exist. + */ + Date getLastUpdate(RepositoryFileReference ref); + + /** + * Returns all components available of the given id type + * + * @param idClass class of the Ids to search for + * @return empty set if no ids are available + */ + public <T extends TOSCAComponentId> SortedSet<T> getAllTOSCAComponentIds(Class<T> idClass); + + /** + * Returns the set of <em>all</em> ids nested in the given reference + * + * The generated Ids are linked as child to the id associated to the given + * reference + * + * Required for getting plans nested in a service template: plans are nested + * below the PlansOfOneServiceTemplateId + * + * @param ref a reference to the TOSCA element to be checked. The path + * belonging to this element is checked. + * @param idClass + * @return the set of Ids nested in the given reference. Empty set if there + * are no or the reference itself does not exist. + */ + public <T extends TOSCAElementId> SortedSet<T> getNestedIds(GenericId ref, Class<T> idClass); + + /** + * Returns the set of files nested in the given reference + */ + public SortedSet<RepositoryFileReference> getContainedFiles(GenericId id); + + /** + * Returns all namespaces used by all known TOSCA components + */ + public Collection<Namespace> getUsedNamespaces(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java new file mode 100644 index 0000000..cb9560b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import java.util.Date; + +import org.apache.commons.configuration.Configuration; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.GenericId; + +/** + * Provides interface to the backend. + * + * Currently a file-based backend is implemented. In the future, a git-based or + * a database-based backend is possible. + * + * The properties are managed by org.apache.commons.configuration. In case a new + * backend is added, the appropriate implementation of + * org.apache.commons.configuration.AbstrctConfiguration has to be chosen. + * + */ +public interface IRepository extends IGenericRepository { + + /** + * Returns the configuration of the specified id + * + * If the associated TOSCA element does not exist, an empty configuration is + * returned. That means, the associated TOSCA element is created (SIDE + * EFFECT) + * + * The returned configuration ensures that autoSave is activated + * + * @param id may be a reference to a TOSCAcomponent or to a nested + * TOSCAelement + * @return a Configuration, where isAutoSave == true + */ + Configuration getConfiguration(GenericId id); + + /** + * Enables resources to define additional properties. Currently used for + * tags. + * + * Currently, more a quick hack. A generic TagsManager should be introduced + * to enable auto completion of tag names + * + * If the associated TOSCA element does not exist, an empty configuration is + * returned. That means, the associated TOSCA element is created (SIDE + * EFFECT) + */ + Configuration getConfiguration(RepositoryFileReference ref); + + /** + * + * @return the last change date of the configuration belonging to the given + * id. NULL if the associated TOSCA element does not exist. + */ + Date getConfigurationLastUpdate(GenericId id); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java new file mode 100644 index 0000000..a373bdf --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Interface for low-level repository administration + */ +public interface IRepositoryAdministration { + + /** + * Dumps the content of the repository to the given output stream + * + * @param out stream to use to dump the data to. Currently, a ZIP output + * stream is returned. + * @throws IOException + */ + void doDump(OutputStream out) throws IOException; + + /** + * Removes all data + */ + void doClear(); + + /** + * Imports the content of the given stream into the repsotiry. + * + * @param in the stream to use. Currently, only ZIP input is supported. + */ + void doImport(InputStream in); +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java new file mode 100644 index 0000000..8887cb2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Class for testing getAny() + * + * It has to be in src/main as src/test is not compiled during production, but + * the jaxbcontext is initialized in src/test and cannot be updated in src/main + * + * Included in {@link oorg.eclipse.winery.repository.JAXBSupport.initContext()} + */ +@XmlRootElement +public class MockXMLElement { + + @XmlElement + public String mock = "mock"; +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java new file mode 100644 index 0000000..f333005 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import org.eclipse.winery.repository.Prefs; + +public class Repository { + + public final static IRepository INSTANCE = Prefs.INSTANCE.getRepository(); +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java new file mode 100644 index 0000000..2a75eba --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend; + +import java.net.URI; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ids.GenericId; + +public class ResourceCreationResult { + + private Status status = null; + private URI uri = null; + private GenericId id = null; + + + public ResourceCreationResult() { + } + + public ResourceCreationResult(Status status) { + this.setStatus(status); + } + + public ResourceCreationResult(Status status, URI uri, GenericId id) { + this.setStatus(status); + this.setId(id); + this.setUri(uri); + } + + public Status getStatus() { + return this.status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public URI getUri() { + return this.uri; + } + + public void setUri(URI uri) { + this.uri = uri; + } + + public GenericId getId() { + return this.id; + } + + public void setId(GenericId id) { + this.id = id; + } + + public boolean isSuccess() { + return this.getStatus() == Status.CREATED; + } + + /** + * The possibly existing URI is used as location in Response.created + * + * @return a Response created based on the contained data + */ + public Response getResponse() { + Response res; + if (this.getUri() == null) { + res = Response.status(this.getStatus()).build(); + } else { + assert (this.getStatus().equals(Status.CREATED)); + res = Response.created(this.getUri()).build(); + } + return res; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java new file mode 100644 index 0000000..23dc1b8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.constants; + +/** + * TODO: check which of them can be removed + */ +public class Filename { + + public static final String FILENAME_BIG_ICON = "bigIcon.png"; + public static final String FILENAME_SMALL_ICON = "smallIcon.png"; + + public static final String FILENAME_JSON_NODETEMPLATES = "nodetemplates.json"; + public static final String FILENAME_JSON_PARENTCACHE = "parents.json"; + public static final String FILENAME_JSON_PLAN = "Plan.json"; + public static final String FILENAME_JSON_RELATIONSHIPTEMPLATE = "realtionshiptemplates.json"; + public static final String FILENAME_JSON_TOPOLOGYTEMPLATE = "TopologyTemplate.json"; + public static final String FILENAME_JSON_OPERATION_WSDL = "wsdl.json"; + public static final String FILENAME_JSON_OPERATION_REST = "rest.json"; + public static final String FILENAME_JSON_OPERATION_SCRIPT = "script.json"; + public static final String FILENAME_XML_PLAN = "Plan.xml"; + public static final String FILENAME_PROPERTIES_ARTIFACT = "artifact.properties"; + public static final String FILENAME_PROPERTIES_ARTIFACTTEMPLATE = "artifacttemplate.properties"; + public static final String FILENAME_PROPERTIES_ARTIFACTTYPE = "artifacttype.properties"; + public static final String FILENAME_PROPERTIES_FILEEXTENSIONTOARTIFACTTYPE = "fileextension-to-artifacttype.properties"; + public static final String FILENAME_PROPERTIES_IMPORTS = "imports.properties"; + public static final String FILENAME_PROPERTIES_NODETYPE = "NodeType.properties"; + public static final String FILENAME_PROPERTIES_OPERATION = "operation.properties"; + public static final String FILENAME_PROPERTIES_PLANCONTAINER = "plancontainer.properties"; + public static final String FILENAME_PROPERTIES_PLANLANGUAGES = "planlanguages.properties"; + public static final String FILENAME_PROPERTIES_PLANTYPES = "plantypes.properties"; + public static final String FILENAME_PROPERTIES_PROPERTIES = "properties.properties"; + public static final String FILENAME_PROPERTIES_RELATIONSHIPTYPE = "RelationshipType.properties"; + public static final String FILENAME_PROPERTIES_SERVICETEMPLATE = "ServiceTemplate.properties"; + public static final String FILENAME_PROPERTIES_TAGS = "tags.properties"; + public static final String FILENAME_PROPERTIES_VISUALAPPEARANCE = "VisualAppearance.properties"; + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java new file mode 100644 index 0000000..46fe103 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.constants; + +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.constants.MimeTypes; + +/** + * see also {@link org.eclipse.winery.common.constants.MimeTypes} + */ +public class MediaTypes { + + public static final MediaType MEDIATYPE_TOSCA_DEFINITIONS = MediaType.valueOf(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java new file mode 100644 index 0000000..ce330a1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.filebased; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.configuration.event.ConfigurationEvent; +import org.apache.commons.configuration.event.ConfigurationListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * We do not count loads and saves as in + * {@link org.apache.commons.configuration.builder.AutoSaveListener}, because + * ConfigurationListener is not aware of such things + */ +class AutoSaveListener implements ConfigurationListener { + + private static final Logger logger = LoggerFactory.getLogger(AutoSaveListener.class); + + private final Path path; + private final PropertiesConfiguration configuration; + + + /** + * + * @param path the file path to write to + * @param configuration the configuration, where the change events come + * from. This is needed as <code>event.getSource()</code> does + * not work + */ + public AutoSaveListener(Path path, PropertiesConfiguration configuration) { + this.path = path; + this.configuration = configuration; + } + + @Override + public void configurationChanged(ConfigurationEvent event) { + if (!event.isBeforeUpdate()) { + try { + if (!Files.exists(this.path.getParent())) { + Files.createDirectories(this.path.getParent()); + } + } catch (IOException ce) { + AutoSaveListener.logger.error("Could not update properties file", ce); + return; + } + try (OutputStream out = Files.newOutputStream(this.path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + OutputStreamWriter writer = new OutputStreamWriter(out); + this.configuration.save(writer); + } catch (ConfigurationException | IOException ce) { + AutoSaveListener.logger.error("Could not update properties file", ce); + } + } + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java new file mode 100644 index 0000000..b970f96 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.filebased; + +import static java.nio.file.FileVisitResult.CONTINUE; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileUtils { + + private static final Logger logger = LoggerFactory.getLogger(FileUtils.class); + + + /** + * Deletes given path. If path a file, it is directly deleted. If it is a + * directory, the directory is recursively deleted. + * + * Does not try to change read-only files to read-write files + * + * Only uses Java7's nio, does not fall back to Java6. + * + * @param path the path to delete + * @throws IOException + */ + public static void forceDelete(Path path) throws IOException { + if (Files.isDirectory(path)) { + try { + Files.walkFileTree(path, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + try { + Files.delete(file); + } catch (IOException e) { + FileUtils.logger.debug("Could not delete file", e.getMessage()); + } + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc == null) { + try { + Files.delete(dir); + } catch (IOException e) { + FileUtils.logger.debug("Could not delete dir", e); + } + return CONTINUE; + } else { + FileUtils.logger.debug("Could not delete file", exc); + return CONTINUE; + } + } + }); + } catch (IOException e) { + FileUtils.logger.debug("Could not delete dir", e); + } + } else { + try { + Files.delete(path); + } catch (IOException e) { + FileUtils.logger.debug("Could not delete file", e.getMessage()); + } + } + } + + /** + * Creates the given directory including its parent directories, if they do + * not exist. + * + * @param path + * @throws IOException + */ + public static void createDirectory(Path path) throws IOException { + Path parent = path.getParent(); + if (parent == null) { + throw new IOException("No parent found"); + } + if (!Files.exists(parent)) { + FileUtils.createDirectory(parent); + } + if (!Files.exists(path)) { + Files.createDirectory(path); + } + } + + // public static Response readContentFromFile(RepositoryFileReference ref) { + // try { + // Repository.INSTANCE.readContentFromFile(ref); + // } + // } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java new file mode 100644 index 0000000..6964681 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java @@ -0,0 +1,596 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.filebased; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.nio.file.spi.FileSystemProvider; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.lang3.SystemUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.RequirementTypeId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.backend.AbstractRepository; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.IRepository; +import org.eclipse.winery.repository.backend.IRepositoryAdministration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * When it comes to a storage of plain files, we use Java 7's nio internally. + * Therefore, we intend to expose the stream types offered by java.nio.Files: + * BufferedReader/BufferedWriter + */ +public class FilebasedRepository extends AbstractRepository implements IRepository, IRepositoryAdministration { + + private static final Logger logger = LoggerFactory.getLogger(FilebasedRepository.class); + + protected final Path repositoryRoot; + + // convenience variables to have a clean code + private final FileSystem fileSystem; + private final FileSystemProvider provider; + + + private Path makeAbsolute(Path relativePath) { + return this.repositoryRoot.resolve(relativePath); + } + + @Override + public boolean flagAsExisting(GenericId id) { + Path path = this.id2AbsolutePath(id); + try { + FileUtils.createDirectory(path); + } catch (IOException e) { + FilebasedRepository.logger.debug(e.toString()); + return false; + } + return true; + } + + private Path id2AbsolutePath(GenericId id) { + Path relativePath = this.fileSystem.getPath(BackendUtils.getPathInsideRepo(id)); + return this.makeAbsolute(relativePath); + } + + /** + * Converts the given reference to an absolute path of the underlying + * FileSystem + */ + public Path ref2AbsolutePath(RepositoryFileReference ref) { + return this.id2AbsolutePath(ref.getParent()).resolve(ref.getFileName()); + } + + /** + * + * @param repositoryLocation a string pointing to a location on the file + * system. May be null. + */ + public FilebasedRepository(String repositoryLocation) { + this.repositoryRoot = this.determineRepositoryPath(repositoryLocation); + this.fileSystem = this.repositoryRoot.getFileSystem(); + this.provider = this.fileSystem.provider(); + } + + private Path determineRepositoryPath(String repositoryLocation) { + Path repositoryPath; + if (repositoryLocation == null) { + if (SystemUtils.IS_OS_WINDOWS) { + if (new File(Constants.GLOBAL_REPO_PATH_WINDOWS).exists()) { + repositoryLocation = Constants.GLOBAL_REPO_PATH_WINDOWS; + File repo = new File(repositoryLocation); + try { + org.apache.commons.io.FileUtils.forceMkdir(repo); + } catch (IOException e) { + FilebasedRepository.logger.error("Could not create repository directory", e); + } + repositoryPath = repo.toPath(); + } else { + repositoryPath = this.createDefaultRepositoryPath(); + } + } else { + repositoryPath = this.createDefaultRepositoryPath(); + } + } else { + File repo = new File(repositoryLocation); + try { + org.apache.commons.io.FileUtils.forceMkdir(repo); + } catch (IOException e) { + FilebasedRepository.logger.error("Could not create repository directory", e); + } + repositoryPath = repo.toPath(); + } + return repositoryPath; + } + + public static File getDefaultRepositoryFilePath() { + return new File(org.apache.commons.io.FileUtils.getUserDirectory(), Constants.DEFAULT_REPO_NAME); + } + + private Path createDefaultRepositoryPath() { + File repo = null; + boolean operationalFileSystemAccess; + try { + repo = FilebasedRepository.getDefaultRepositoryFilePath(); + operationalFileSystemAccess = true; + } catch (NullPointerException e) { + // it seems, we run at a system, where we do not have any filesystem + // access + operationalFileSystemAccess = false; + } + + // operationalFileSystemAccess = false; + + Path repositoryPath; + if (operationalFileSystemAccess) { + try { + org.apache.commons.io.FileUtils.forceMkdir(repo); + } catch (IOException e) { + FilebasedRepository.logger.error("Could not create directory", e); + } + repositoryPath = repo.toPath(); + } else { + assert (!operationalFileSystemAccess); + // we do not have access to the file system + throw new IllegalStateException("No write access to file system"); + } + + return repositoryPath; + } + + @Override + public void forceDelete(RepositoryFileReference ref) throws IOException { + Path relativePath = this.fileSystem.getPath(BackendUtils.getPathInsideRepo(ref)); + Path fileToDelete = this.makeAbsolute(relativePath); + try { + this.provider.delete(fileToDelete); + // Quick hack for deletion of the mime type information + // Alternative: superclass: protected void deleteMimeTypeInformation(RepositoryFileReference ref) throws IOException + // However, this would again call this method, where we would have to check for the extension, too. + // Therefore, we directly delete the information file + Path mimeTypeFile = fileToDelete.getParent().resolve(ref.getFileName() + Constants.SUFFIX_MIMETYPE); + this.provider.delete(mimeTypeFile); + } catch (IOException e) { + if (!(e instanceof NoSuchFileException)) { + // only if file did exist and something else went wrong: complain :) + // (otherwise, silently ignore the error) + FilebasedRepository.logger.debug("Could not delete file", e); + throw e; + } + } + } + + @Override + public void forceDelete(GenericId id) throws IOException { + try { + FileUtils.forceDelete(this.id2AbsolutePath(id)); + } catch (IOException e) { + FilebasedRepository.logger.debug("Could not delete id", id); + throw e; + } + } + + @Override + public boolean exists(GenericId id) { + Path absolutePath = this.id2AbsolutePath(id); + boolean result = Files.exists(absolutePath); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void putContentToFile(RepositoryFileReference ref, String content, MediaType mediaType) throws IOException { + if (mediaType == null) { + // quick hack for storing mime type called this method + assert (ref.getFileName().endsWith(Constants.SUFFIX_MIMETYPE)); + // we do not need to store the mime type of the file containing the mime type information + } else { + this.setMimeType(ref, mediaType); + } + Path path = this.ref2AbsolutePath(ref); + FileUtils.createDirectory(path.getParent()); + Files.write(path, content.getBytes()); + } + + /** + * {@inheritDoc} + */ + @Override + public void putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) throws IOException { + if (mediaType == null) { + // quick hack for storing mime type called this method + assert (ref.getFileName().endsWith(Constants.SUFFIX_MIMETYPE)); + // we do not need to store the mime type of the file containing the mime type information + } else { + this.setMimeType(ref, mediaType); + } + Path targetPath = this.ref2AbsolutePath(ref); + // ensure that parent directory exists + FileUtils.createDirectory(targetPath.getParent()); + + try { + Files.copy(inputStream, targetPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IllegalStateException e) { + FilebasedRepository.logger.debug("Guessing that stream with length 0 is to be written to a file", e); + // copy throws an "java.lang.IllegalStateException: Stream already closed" if the InputStream contains 0 bytes + // For instance, this case happens if SugarCE-6.4.2.zip.removed is tried to be uploaded + // We work around the Java7 issue and create an empty file + if (Files.exists(targetPath)) { + // semantics of putContentToFile: existing content is replaced without notification + Files.delete(targetPath); + } + Files.createFile(targetPath); + } + } + + @Override + public boolean exists(RepositoryFileReference ref) { + return Files.exists(this.ref2AbsolutePath(ref)); + } + + @Override + public <T extends TOSCAComponentId> SortedSet<T> getAllTOSCAComponentIds(Class<T> idClass) { + SortedSet<T> res = new TreeSet<T>(); + String rootPathFragment = Util.getRootPathFragment(idClass); + Path dir = this.repositoryRoot.resolve(rootPathFragment); + if (!Files.exists(dir)) { + // return empty list if no ids are available + return res; + } + assert (Files.isDirectory(dir)); + + final OnlyNonHiddenDirectories onhdf = new OnlyNonHiddenDirectories(); + + // list all directories contained in this directory + try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, onhdf)) { + for (Path nsP : ds) { + // the current path is the namespace + Namespace ns = new Namespace(nsP.getFileName().toString(), true); + try (DirectoryStream<Path> idDS = Files.newDirectoryStream(nsP, onhdf)) { + for (Path idP : idDS) { + XMLId xmlId = new XMLId(idP.getFileName().toString(), true); + Constructor<T> constructor; + try { + constructor = idClass.getConstructor(Namespace.class, XMLId.class); + } catch (Exception e) { + FilebasedRepository.logger.debug("Internal error at determining id constructor", e); + // abort everything, return invalid result + return res; + } + T id; + try { + id = constructor.newInstance(ns, xmlId); + } catch (InstantiationException + | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException e) { + FilebasedRepository.logger.debug("Internal error at invocation of id constructor", e); + // abort everything, return invalid result + return res; + } + res.add(id); + } + } + } + } catch (IOException e) { + FilebasedRepository.logger.debug("Cannot close ds", e); + } + + return res; + } + + @Override + public SortedSet<RepositoryFileReference> getContainedFiles(GenericId id) { + Path dir = this.id2AbsolutePath(id); + SortedSet<RepositoryFileReference> res = new TreeSet<RepositoryFileReference>(); + if (!Files.exists(dir)) { + return res; + } + assert (Files.isDirectory(dir)); + // list all directories contained in this directory + try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, new OnlyNonHiddenFiles())) { + for (Path p : ds) { + RepositoryFileReference ref = new RepositoryFileReference(id, p.getFileName().toString()); + res.add(ref); + } + } catch (IOException e) { + FilebasedRepository.logger.debug("Cannot close ds", e); + } + return res; + } + + @Override + public Configuration getConfiguration(RepositoryFileReference ref) { + Path path = this.ref2AbsolutePath(ref); + + PropertiesConfiguration configuration = new PropertiesConfiguration(); + if (Files.exists(path)) { + try (Reader r = Files.newBufferedReader(path, Charset.defaultCharset())) { + configuration.load(r); + } catch (ConfigurationException | IOException e) { + FilebasedRepository.logger.error("Could not read config file", e); + throw new IllegalStateException("Could not read config file", e); + } + } + + configuration.addConfigurationListener(new AutoSaveListener(path, configuration)); + + // We do NOT implement reloading as the configuration is only accessed + // in JAX-RS resources, which are created on a per-request basis + + return configuration; + } + + /** + * @return null if an error occurred + */ + @Override + public Date getLastUpdate(RepositoryFileReference ref) { + Path path = this.ref2AbsolutePath(ref); + Date res; + if (Files.exists(path)) { + FileTime lastModifiedTime; + try { + lastModifiedTime = Files.getLastModifiedTime(path); + res = new Date(lastModifiedTime.toMillis()); + } catch (IOException e) { + FilebasedRepository.logger.debug(e.getMessage(), e); + res = null; + } + } else { + // this branch is taken if the resource directory exists, but the + // configuration itself does not exist. + // For instance, this happens if icons are manually put for a node + // type, but no color configuration is made. + res = Constants.LASTMODIFIEDDATE_FOR_404; + } + return res; + } + + @Override + public <T extends TOSCAElementId> SortedSet<T> getNestedIds(GenericId ref, Class<T> idClass) { + Path dir = this.id2AbsolutePath(ref); + SortedSet<T> res = new TreeSet<T>(); + if (!Files.exists(dir)) { + // the id has been generated by the exporter without existance test. + // This test is done here. + return res; + } + assert (Files.isDirectory(dir)); + // list all directories contained in this directory + try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, new OnlyNonHiddenDirectories())) { + for (Path p : ds) { + XMLId xmlId = new XMLId(p.getFileName().toString(), true); + @SuppressWarnings("unchecked") + Constructor<T>[] constructors = (Constructor<T>[]) idClass.getConstructors(); + assert (constructors.length == 1); + Constructor<T> constructor = constructors[0]; + assert (constructor.getParameterTypes().length == 2); + T id; + try { + id = constructor.newInstance(ref, xmlId); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + FilebasedRepository.logger.debug("Internal error at invocation of id constructor", e); + // abort everything, return invalid result + return res; + } + res.add(id); + } + } catch (IOException e) { + FilebasedRepository.logger.debug("Cannot close ds", e); + } + return res; + } + + @Override + // below, toscaComponents is an array, which is used in an iterator + // As Java does not allow generic arrays, we have to suppress the warning when fetching an element out of the list + @SuppressWarnings("unchecked") + public Collection<Namespace> getUsedNamespaces() { + // @formatter:off + @SuppressWarnings("rawtypes") + Class[] toscaComponentIds = { + ArtifactTemplateId.class, + ArtifactTypeId.class, + CapabilityTypeId.class, + NodeTypeId.class, + NodeTypeImplementationId.class, + PolicyTemplateId.class, + PolicyTypeId.class, + RelationshipTypeId.class, + RelationshipTypeImplementationId.class, + RequirementTypeId.class, + ServiceTemplateId.class + }; + // @formatter:on + + // we use a HashSet to avoid reporting duplicate namespaces + Collection<Namespace> res = new HashSet<Namespace>(); + + for (Class<? extends TOSCAComponentId> id : toscaComponentIds) { + String rootPathFragment = Util.getRootPathFragment(id); + Path dir = this.repositoryRoot.resolve(rootPathFragment); + if (!Files.exists(dir)) { + continue; + } + assert (Files.isDirectory(dir)); + + final OnlyNonHiddenDirectories onhdf = new OnlyNonHiddenDirectories(); + + // list all directories contained in this directory + try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, onhdf)) { + for (Path nsP : ds) { + // the current path is the namespace + Namespace ns = new Namespace(nsP.getFileName().toString(), true); + res.add(ns); + } + } catch (IOException e) { + FilebasedRepository.logger.debug("Cannot close ds", e); + } + } + return res; + } + + @Override + public void doDump(OutputStream out) throws IOException { + final ZipOutputStream zout = new ZipOutputStream(out); + final int cutLength = this.repositoryRoot.toString().length() + 1; + + Files.walkFileTree(this.repositoryRoot, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + if (dir.endsWith(".git")) { + return FileVisitResult.SKIP_SUBTREE; + } else { + return FileVisitResult.CONTINUE; + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + String name = file.toString().substring(cutLength); + ZipEntry ze = new ZipEntry(name); + try { + ze.setTime(Files.getLastModifiedTime(file).toMillis()); + ze.setSize(Files.size(file)); + zout.putNextEntry(ze); + Files.copy(file, zout); + zout.closeEntry(); + } catch (IOException e) { + FilebasedRepository.logger.debug(e.getMessage()); + } + return FileVisitResult.CONTINUE; + } + }); + zout.close(); + } + + /** + * Removes all files and dirs except the .git directory + */ + @Override + public void doClear() { + try { + DirectoryStream.Filter<Path> noGitDirFilter = new DirectoryStream.Filter<Path>() { + + @Override + public boolean accept(Path entry) throws IOException { + return !(entry.getFileName().toString().equals(".git")); + } + }; + + DirectoryStream<Path> ds = Files.newDirectoryStream(this.repositoryRoot, noGitDirFilter); + for (Path p : ds) { + FileUtils.forceDelete(p); + } + } catch (IOException e) { + FilebasedRepository.logger.error(e.getMessage()); + e.printStackTrace(); + } + } + + @Override + public void doImport(InputStream in) { + ZipInputStream zis = new ZipInputStream(in); + ZipEntry entry; + try { + while ((entry = zis.getNextEntry()) != null) { + if (!entry.isDirectory()) { + Path path = this.repositoryRoot.resolve(entry.getName()); + FileUtils.createDirectory(path.getParent()); + Files.copy(zis, path); + } + } + } catch (IOException e) { + FilebasedRepository.logger.error(e.getMessage()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public long getSize(RepositoryFileReference ref) throws IOException { + return Files.size(this.ref2AbsolutePath(ref)); + } + + /** + * {@inheritDoc} + */ + @Override + public FileTime getLastModifiedTime(RepositoryFileReference ref) throws IOException { + Path path = this.ref2AbsolutePath(ref); + FileTime res = Files.getLastModifiedTime(path); + return res; + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream newInputStream(RepositoryFileReference ref) throws IOException { + Path path = this.ref2AbsolutePath(ref); + InputStream res = Files.newInputStream(path); + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java new file mode 100644 index 0000000..a3f3fc8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.filebased; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.eclipse.jgit.api.AddCommand; +import org.eclipse.jgit.api.CleanCommand; +import org.eclipse.jgit.api.CommitCommand; +import org.eclipse.jgit.api.FetchCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.PushCommand; +import org.eclipse.jgit.api.ResetCommand; +import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.api.errors.CheckoutConflictException; +import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.NoHeadException; +import org.eclipse.jgit.api.errors.NoMessageException; +import org.eclipse.jgit.api.errors.UnmergedPathsException; +import org.eclipse.jgit.api.errors.WrongRepositoryStateException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.eclipse.winery.repository.Prefs; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Used for testing only. + * + * Allows to reset repository to a certain commit id + */ +public class GitBasedRepository extends FilebasedRepository { + + private static final Logger logger = LoggerFactory.getLogger(GitBasedRepository.class); + + private final Repository gitRepo; + private final Git git; + private final CredentialsProvider cp; + + public static final String PREFERENCE_GIT_USERNAME = "git.username"; + public static final String PREFERENCE_GIT_PASSWORD = "git.password"; + + + /** + * @param repositoryLocation the location of the repository + * @throws IOException thrown if repository does not exist + */ + public GitBasedRepository(String repositoryLocation) throws IOException { + super(repositoryLocation); + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + this.gitRepo = builder.setWorkTree(this.repositoryRoot.toFile()).setMustExist(true).build(); + this.git = new Git(this.gitRepo); + + this.cp = this.initializeCredentialsProvider(); + } + + /** + * Reads the properties stored in ".winery" in the repository + */ + private Properties dotWineryProperties() { + Properties p = new Properties(); + File f = new File(this.repositoryRoot.toFile(), ".winery"); + InputStream is; + try { + is = new FileInputStream(f); + } catch (FileNotFoundException e1) { + // .winery does not exist in the file-based repository + return p; + } + if (is != null) { + try { + p.load(is); + } catch (IOException e) { + GitBasedRepository.logger.debug(e.getMessage(), e); + } + } + return p; + } + + /** + * Uses git.username und git.password from .winery and winery.properties + * + * Considering .winery is useful if the same war file is used on a dev + * server and a stable server. The WAR file cannot contain the credentials + * if committing is only allowed on only one of these servers + */ + private CredentialsProvider initializeCredentialsProvider() { + CredentialsProvider cp; + + Properties wp = this.dotWineryProperties(); + + String gitUserName = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME); + if (gitUserName == null) { + gitUserName = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME); + } + + String gitPassword = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD); + if (gitPassword == null) { + gitPassword = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD); + } + + if (gitUserName == null) { + cp = null; + } else if (gitPassword == null) { + cp = null; + } else { + cp = new UsernamePasswordCredentialsProvider(gitUserName, gitPassword); + } + return cp; + } + + public void addCommitPush() throws NoHeadException, NoMessageException, UnmergedPathsException, ConcurrentRefUpdateException, WrongRepositoryStateException, GitAPIException { + AddCommand add = this.git.add(); + add.addFilepattern("."); + add.call(); + + CommitCommand commit = this.git.commit(); + commit.setMessage("Commit through Winery"); + commit.call(); + + PushCommand push = this.git.push(); + if (this.cp != null) { + push.setCredentialsProvider(this.cp); + } + push.call(); + } + + private void clean() throws NoWorkTreeException, GitAPIException { + GitBasedRepository.logger.trace("git clean"); + // remove untracked files + CleanCommand clean = this.git.clean(); + clean.setCleanDirectories(true); + clean.call(); + } + + public void cleanAndResetHard() throws NoWorkTreeException, GitAPIException { + // enable updating by resetting the content of the repository + this.clean(); + + // fetch the newest thing from upstream + GitBasedRepository.logger.trace("git fetch"); + FetchCommand fetch = this.git.fetch(); + if (this.cp != null) { + fetch.setCredentialsProvider(this.cp); + } + fetch.call(); + + // after fetching, reset to the latest version + GitBasedRepository.logger.trace("git reset --hard"); + ResetCommand reset = this.git.reset(); + reset.setMode(ResetType.HARD); + reset.call(); + } + + public void setRevisionTo(String ref) throws CheckoutConflictException, GitAPIException { + this.clean(); + + // reset repository to the desired reference + ResetCommand reset = this.git.reset(); + reset.setMode(ResetType.HARD); + reset.setRef(ref); + reset.call(); + } + + /** + * Returns true if authentification information (for instance, to push to + * upstream) is available + */ + public boolean authenticationInfoAvailable() { + return this.cp != null; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java new file mode 100644 index 0000000..a5acd8e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.filebased; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; + +public class OnlyNonHiddenDirectories implements DirectoryStream.Filter<Path> { + + @Override + public boolean accept(Path entry) throws IOException { + // we return only non-hidden directories + // E.g., DS_Store of Mac OS X is a hidden directory + return Files.isDirectory(entry) && !Files.isHidden(entry); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java new file mode 100644 index 0000000..3b788b4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.backend.filebased; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.winery.repository.Constants; + +/** + * Only non-hidden files. Also excludes file names ending with + * Constants.SUFFIX_MIMETYPE + */ +public class OnlyNonHiddenFiles implements DirectoryStream.Filter<Path> { + + @Override + public boolean accept(Path entry) throws IOException { + // we return only non-hidden files + // and we do not return the file "FN.mimetype", which are used to store the mimetype of FN + return !Files.isDirectory(entry) && !Files.isHidden(entry) && (!entry.getFileName().toString().endsWith(Constants.SUFFIX_MIMETYPE)); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java new file mode 100644 index 0000000..bf25ae7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes; + +import java.io.IOException; + +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.commons.io.FilenameUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * based on + * https://github.com/blueimp/jQuery-File-Upload/wiki/Google-App-Engine-Java + * + * The getters are named according to the requirements of the template in + * jquery-file-upload-full.jsp + */ +@XmlRootElement +public class FileMeta { + + private static final Logger logger = LoggerFactory.getLogger(FileMeta.class); + + String name; + long size; + String url; + String deleteUrl; + String deleteType = "DELETE"; + String thumbnailUrl; + + + public String getName() { + return this.name; + } + + public long getSize() { + return this.size; + } + + public String getUrl() { + return this.url; + } + + public String getDeleteUrl() { + return this.deleteUrl; + } + + public String getDeleteType() { + return this.deleteType; + } + + public String getThumbnailUrl() { + return this.thumbnailUrl; + } + + public FileMeta(String filename, long size, String url, String thumbnailUrl) { + this.name = filename; + this.size = size; + this.url = url; + this.thumbnailUrl = thumbnailUrl; + this.deleteUrl = url; + } + + public FileMeta(RepositoryFileReference ref) { + this.name = ref.getFileName(); + try { + this.size = Repository.INSTANCE.getSize(ref); + } catch (IOException e) { + FileMeta.logger.error(e.getMessage(), e); + this.size = 0; + } + this.url = Utils.getAbsoluteURL(ref); + this.deleteUrl = this.url; + this.thumbnailUrl = Prefs.INSTANCE.getResourcePath() + Constants.PATH_MIMETYPEIMAGES + FilenameUtils.getExtension(this.name) + Constants.SUFFIX_MIMETYPEIMAGES; + } + + /** + * @param ref the reference to get information from + * @param URLprefix the string which should be prepended the actual URL. + * Including the "/" + */ + public FileMeta(RepositoryFileReference ref, String URLprefix) { + this(ref); + this.url = URLprefix + this.url; + } + + /** + * The constructor is used for JAX-B only. Therefore, the warning "unused" + * is suppressed + */ + @SuppressWarnings("unused") + private FileMeta() { + } + +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java new file mode 100644 index 0000000..eae201d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes; + +public class TypeWithShortName implements Comparable<TypeWithShortName> { + + private final String type; + // we could have used "URI" as type here but this seems to be unnecessary + // overhead + + // this is a kind of ID + private final String shortName; + + + public TypeWithShortName(String type, String shortName) { + this.type = type; + this.shortName = shortName; + } + + public String getType() { + return this.type; + } + + public String getShortName() { + return this.shortName; + } + + @Override + public boolean equals(Object o) { + if (o instanceof TypeWithShortName) { + return ((TypeWithShortName) o).getType().equals(this.getType()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return this.getType().hashCode(); + } + + @Override + public int compareTo(TypeWithShortName o) { + int c = this.getShortName().compareTo(o.getShortName()); + if (c == 0) { + // not sure if this will ever happen + c = this.getType().compareTo(o.getType()); + } + return c; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java new file mode 100644 index 0000000..f06c917 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids; + +/** + * This class is the brother of {@link org.eclipse.winery.common.id.IdNames} + * + * It includes all id names used additionally in the local ids + */ +public class IdNames { + + // the files belonging to one artifact template are nested in the sub + // directory "files" + public static final String ARTIFACTTEMPLATEDIRECTORY = "files"; + + public static final String CONSTRAINTTYPES = "constrainttypes"; + public static final String NAMESPACES = "namespaces"; + public static final String PLANLANGUAGES = "planlanguages"; + public static final String PLANTYPES = "plantypes"; + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java new file mode 100644 index 0000000..3a31b05 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.admin; + +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.XMLId; + +/** + * The Id for the single admin resource holding administrative things such as + * the prefixes of namespaces + */ +public abstract class AdminId extends GenericId { + + protected AdminId(XMLId xmlId) { + super(xmlId); + } + + @Override + public int compareTo(GenericId o) { + if (o instanceof AdminId) { + return this.getXmlId().compareTo(o.getXmlId()); + } else { + throw new IllegalStateException(); + } + } + + @Override + public GenericId getParent() { + return null; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AdminId) { + return this.getXmlId().equals(((AdminId) obj).getXmlId()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return this.getXmlId().hashCode(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java new file mode 100644 index 0000000..210a2c7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.admin; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.repository.datatypes.ids.IdNames; + +public class ConstraintTypesId extends TypesId { + + private final static XMLId xmlId = new XMLId(IdNames.CONSTRAINTTYPES, false); + + + public ConstraintTypesId() { + super(ConstraintTypesId.xmlId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java new file mode 100644 index 0000000..4bdb233 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.admin; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.repository.datatypes.ids.IdNames; + +public class NamespacesId extends AdminId { + + private final static XMLId xmlId = new XMLId(IdNames.NAMESPACES, false); + + + public NamespacesId() { + super(NamespacesId.xmlId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java new file mode 100644 index 0000000..7ebfb7d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.admin; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.repository.datatypes.ids.IdNames; + +public class PlanLanguagesId extends TypesId { + + private final static XMLId xmlId = new XMLId(IdNames.PLANLANGUAGES, false); + + + public PlanLanguagesId() { + super(PlanLanguagesId.xmlId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java new file mode 100644 index 0000000..e44cd2b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.admin; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.repository.datatypes.ids.IdNames; + +public class PlanTypesId extends TypesId { + + private final static XMLId xmlId = new XMLId(IdNames.PLANTYPES, false); + + + public PlanTypesId() { + super(PlanTypesId.xmlId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java new file mode 100644 index 0000000..db40780 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.admin; + +import org.eclipse.winery.common.ids.XMLId; + +public abstract class TypesId extends AdminId { + + protected TypesId(XMLId xmlId) { + super(xmlId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java new file mode 100644 index 0000000..cce2d53 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.elements; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.repository.datatypes.ids.IdNames; + +public class ArtifactTemplateDirectoryId extends TOSCAElementId { + + private final static XMLId xmlID = new XMLId(IdNames.ARTIFACTTEMPLATEDIRECTORY, false); + + + public ArtifactTemplateDirectoryId(ArtifactTemplateId parent) { + super(parent, ArtifactTemplateDirectoryId.xmlID); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java new file mode 100644 index 0000000..6bd5db8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.elements; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; + +public class SelfServiceMetaDataId extends TOSCAElementId { + + public SelfServiceMetaDataId(ServiceTemplateId parent) { + super(parent, new XMLId("SELFSERVICE-Metadata", true)); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java new file mode 100644 index 0000000..9b7784f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.ids.elements; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; + +/** + * ID for a pseudo-TOSCA-Element holding the data for the visual appearance + * (e.g., icons for node types) + */ +public class VisualAppearanceId extends TOSCAElementId { + + public VisualAppearanceId(TopologyGraphElementEntityTypeId parent) { + super(parent, new XMLId("appearance", true)); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java new file mode 100644 index 0000000..1b8fb9a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.select2; + +/** + * Models a data item for select2. In case optgroups have to be returned, use + * this element in a TreeMap + */ +public class Select2DataItem implements Comparable<Select2DataItem> { + + private final String id; + private final String text; + + + public Select2DataItem(String id, String text) { + this.id = id; + this.text = text; + } + + public String getId() { + return this.id; + } + + public String getText() { + return this.text; + } + + /** + * Sort order is based on text + */ + @Override + public int compareTo(Select2DataItem o) { + return this.getText().compareTo(o.getText()); + } + + /** + * Equality is checked at id level + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Select2DataItem)) { + return false; + } + return this.getId().equals(((Select2DataItem) o).getId()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java new file mode 100644 index 0000000..50e5ecd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.select2; + +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +public class Select2DataWithOptGroups { + + Map<String, Select2OptGroup> idx = new HashMap<>(); + + + /** + * Add an item to a group + * + * @param group the group + * @param id the id of the item + * @param text the text of the item {@inheritDoc} + */ + public void add(String group, String id, String text) { + Select2OptGroup optGroup = this.idx.get(group); + if (optGroup == null) { + optGroup = new Select2OptGroup(group); + this.idx.put(group, optGroup); + } + + Select2DataItem item = new Select2DataItem(id, text); + optGroup.addItem(item); + } + + public SortedSet<Select2OptGroup> asSortedSet() { + // convert the index to the real result + SortedSet<Select2OptGroup> res = new TreeSet<>(); + for (Select2OptGroup optGroup : this.idx.values()) { + res.add(optGroup); + } + + return res; + + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java new file mode 100644 index 0000000..7a7a88b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.datatypes.select2; + +import java.util.SortedSet; +import java.util.TreeSet; + +public class Select2OptGroup implements Comparable<Select2OptGroup> { + + private final String text; + private final SortedSet<Select2DataItem> children; + + + public Select2OptGroup(String text) { + this.text = text; + this.children = new TreeSet<Select2DataItem>(); + } + + public String getText() { + return this.text; + } + + /** + * Returns the internal SortedSet for data items. + */ + public SortedSet<Select2DataItem> getChildren() { + return this.children; + } + + public void addItem(Select2DataItem item) { + this.children.add(item); + } + + /** + * Quick hack to test Select2OptGroups for equality. Only the text is + * tested, not the contained children. This might cause issues later, but + * currently not. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Select2OptGroup)) { + return false; + } + return this.text.equals(((Select2OptGroup) o).text); + } + + /** + * Quick hack to compare Select2OptGroups. Only the text is compared, not + * the contained children. This might cause issues later, but currently not. + */ + @Override + public int compareTo(Select2OptGroup o) { + return this.getText().compareTo(o.getText()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java new file mode 100644 index 0000000..ee1fbaf --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +/** + * This package collects all datatypes required to generate valid select2 data objects + * {@see http://ivaynberg.github.io/select2/}: Example Hierarchical Data + */ +package org.eclipse.winery.repository.datatypes.select2;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java new file mode 100644 index 0000000..ac27478 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java @@ -0,0 +1,299 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Kálmán Képes - initial API and implementation and/or initial documentation + * Oliver Kopp - adapted to new storage model and to TOSCA v1.0 + *******************************************************************************/ +package org.eclipse.winery.repository.export; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.JAXBException; +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.ArchiveStreamFactory; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.io.IOUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.selfservice.Application; +import org.eclipse.winery.model.selfservice.Application.Options; +import org.eclipse.winery.model.selfservice.ApplicationOption; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.admin.NamespacesId; +import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources.admin.NamespacesResource; +import org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal.SelfServicePortalResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +/** + * This class exports a CSAR crawling from the the given GenericId<br/> + * Currently, only ServiceTemplates are supported<br /> + * commons-compress is used as an output stream should be provided. An + * alternative implementation is to use Java7's Zip File System Provider + */ +public class CSARExporter { + + public static final String PATH_TO_NAMESPACES_PROPERTIES = "winery/Namespaces.properties"; + + private static final Logger logger = LoggerFactory.getLogger(CSARExporter.class); + + private static final String DEFINITONS_PATH_PREFIX = "Definitions/"; + + + /** + * Returns a unique name for the given definitions to be used as filename + */ + private static String getDefinitionsName(TOSCAComponentId id) { + // the prefix is globally unique and the id locally in a namespace + // therefore a concatenation of both is also unique + String res = NamespacesResource.getPrefix(id.getNamespace()) + "__" + id.getXmlId().getEncoded(); + return res; + } + + public static String getDefinitionsFileName(TOSCAComponentId id) { + return CSARExporter.getDefinitionsName(id) + Constants.SUFFIX_TOSCA_DEFINITIONS; + } + + public static String getDefinitionsPathInsideCSAR(TOSCAComponentId id) { + return CSARExporter.DEFINITONS_PATH_PREFIX + CSARExporter.getDefinitionsFileName(id); + } + + /** + * Writes a complete CSAR containing all necessary things reachable from the + * given service template + * + * @param id the id of the service template to export + * @param out the outputstream to write to + * @throws JAXBException + */ + public void writeCSAR(TOSCAComponentId entryId, OutputStream out) throws ArchiveException, IOException, XMLStreamException, JAXBException { + CSARExporter.logger.trace("Starting CSAR export with {}", entryId.toString()); + + Map<RepositoryFileReference, String> refMap = new HashMap<RepositoryFileReference, String>(); + Collection<String> definitionNames = new ArrayList<>(); + + final ArchiveOutputStream zos = new ArchiveStreamFactory().createArchiveOutputStream("zip", out); + + TOSCAExportUtil exporter = new TOSCAExportUtil(); + Map<String, Object> conf = new HashMap<>(); + + ExportedState exportedState = new ExportedState(); + + TOSCAComponentId currentId = entryId; + do { + String defName = CSARExporter.getDefinitionsPathInsideCSAR(currentId); + definitionNames.add(defName); + + zos.putArchiveEntry(new ZipArchiveEntry(defName)); + Collection<TOSCAComponentId> referencedIds; + try { + referencedIds = exporter.exportTOSCA(currentId, zos, refMap, conf); + } catch (IllegalStateException e) { + // thrown if something went wrong inside the repo + out.close(); + // we just rethrow as there currently is no error stream. + throw e; + } + zos.closeArchiveEntry(); + + exportedState.flagAsExported(currentId); + exportedState.flagAsExportRequired(referencedIds); + + currentId = exportedState.pop(); + } while (currentId != null); + + // if we export a ServiceTemplate, data for the self-service portal might exist + if (entryId instanceof ServiceTemplateId) { + this.addSelfServiceMetaData((ServiceTemplateId) entryId, refMap); + } + + // now, refMap contains all files to be added to the CSAR + + // write manifest directly after the definitions to have it more at the beginning of the ZIP rather than having it at the very end + this.addManifest(entryId, definitionNames, refMap, zos); + + // used for generated XSD schemas + TransformerFactory tFactory = TransformerFactory.newInstance(); + Transformer transformer; + try { + transformer = tFactory.newTransformer(); + } catch (TransformerConfigurationException e1) { + CSARExporter.logger.debug(e1.getMessage(), e1); + throw new IllegalStateException("Could not instantiate transformer", e1); + } + + // write all referenced files + for (RepositoryFileReference ref : refMap.keySet()) { + String archivePath = refMap.get(ref); + CSARExporter.logger.trace("Creating {}", archivePath); + ArchiveEntry archiveEntry = new ZipArchiveEntry(archivePath); + zos.putArchiveEntry(archiveEntry); + if (ref instanceof DummyRepositoryFileReferenceForGeneratedXSD) { + CSARExporter.logger.trace("Special treatment for generated XSDs"); + Document document = ((DummyRepositoryFileReferenceForGeneratedXSD) ref).getDocument(); + DOMSource source = new DOMSource(document); + StreamResult result = new StreamResult(zos); + try { + transformer.transform(source, result); + } catch (TransformerException e) { + CSARExporter.logger.debug("Could not serialize generated xsd", e); + } + } else { + try (InputStream is = Repository.INSTANCE.newInputStream(ref)) { + IOUtils.copy(is, zos); + } catch (Exception e) { + CSARExporter.logger.error("Could not copy file content to ZIP outputstream", e); + } + } + zos.closeArchiveEntry(); + } + + this.addNamespacePrefixes(zos); + + zos.finish(); + zos.close(); + } + + /** + * Writes the configured mapping namespaceprefix -> namespace to the archive + * + * This is kind of a quick hack. TODO: during the import, the prefixes + * should be extracted using JAXB and stored in the NamespacesResource + * + * @throws IOException + */ + private void addNamespacePrefixes(ArchiveOutputStream zos) throws IOException { + Configuration configuration = Repository.INSTANCE.getConfiguration(new NamespacesId()); + if (configuration instanceof PropertiesConfiguration) { + // Quick hack: direct serialization only works for PropertiesConfiguration + PropertiesConfiguration pconf = (PropertiesConfiguration) configuration; + ArchiveEntry archiveEntry = new ZipArchiveEntry(CSARExporter.PATH_TO_NAMESPACES_PROPERTIES); + zos.putArchiveEntry(archiveEntry); + try { + pconf.save(zos); + } catch (ConfigurationException e) { + CSARExporter.logger.debug(e.getMessage(), e); + zos.write("#Could not export properties".getBytes()); + zos.write(("#" + e.getMessage()).getBytes()); + } + zos.closeArchiveEntry(); + } + } + + private void addSelfServiceMetaData(ServiceTemplateId entryId, Map<RepositoryFileReference, String> refMap) { + SelfServiceMetaDataId id = new SelfServiceMetaDataId(entryId); + if (Repository.INSTANCE.exists(id)) { + SelfServicePortalResource res = new SelfServicePortalResource(entryId); + + refMap.put(res.data_xml_ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + "data.xml"); + + // The schema says that the images have to exist + // However, at a quick modeling, there might be no images + // Therefore, we check for existence + if (Repository.INSTANCE.exists(res.icon_jpg_ref)) { + refMap.put(res.icon_jpg_ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + "icon.jpg"); + } + if (Repository.INSTANCE.exists(res.image_jpg_ref)) { + refMap.put(res.image_jpg_ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + "image.jpg"); + } + + Application application = res.getApplication(); + Options options = application.getOptions(); + if (options != null) { + for (ApplicationOption option : options.getOption()) { + String url = option.getIconUrl(); + if (Util.isRelativeURI(url)) { + RepositoryFileReference ref = new RepositoryFileReference(id, url); + if (Repository.INSTANCE.exists(ref)) { + refMap.put(ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + url); + } else { + CSARExporter.logger.error("Data corrupt: pointing to non-existent file " + ref); + } + } + + url = option.getPlanInputMessageUrl(); + if (Util.isRelativeURI(url)) { + RepositoryFileReference ref = new RepositoryFileReference(id, url); + if (Repository.INSTANCE.exists(ref)) { + refMap.put(ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + url); + } else { + CSARExporter.logger.error("Data corrupt: pointing to non-existent file " + ref); + } + } + } + } + } + } + + private void addManifest(TOSCAComponentId id, Collection<String> definitionNames, Map<RepositoryFileReference, String> refMap, ArchiveOutputStream out) throws IOException { + String entryDefinitionsReference = CSARExporter.getDefinitionsPathInsideCSAR(id); + + out.putArchiveEntry(new ZipArchiveEntry("TOSCA-Metadata/TOSCA.meta")); + PrintWriter pw = new PrintWriter(out); + // Setting Versions + pw.println("TOSCA-Meta-Version: 1.0"); + pw.println("CSAR-Version: 1.0"); + String versionString = "Created-By: Winery " + Prefs.INSTANCE.getVersion(); + pw.println(versionString); + // Winery currently is unaware of tDefinitions, therefore, we use the + // name of the service template + pw.println("Entry-Definitions: " + entryDefinitionsReference); + pw.println(); + + assert (definitionNames.contains(entryDefinitionsReference)); + for (String name : definitionNames) { + pw.println("Name: " + name); + pw.println("Content-Type: " + org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_TOSCA_DEFINITIONS); + pw.println(); + } + + // Setting other files, mainly files belonging to artifacts + for (RepositoryFileReference ref : refMap.keySet()) { + String archivePath = refMap.get(ref); + pw.println("Name: " + archivePath); + String mimeType; + if (ref instanceof DummyRepositoryFileReferenceForGeneratedXSD) { + mimeType = MimeTypes.MIMETYPE_XSD; + } else { + mimeType = Repository.INSTANCE.getMimeType(ref); + } + pw.println("Content-Type: " + mimeType); + pw.println(); + } + pw.flush(); + out.closeArchiveEntry(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java new file mode 100644 index 0000000..05c7ce1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.export; + +import org.eclipse.winery.common.ids.GenericId; +import org.eclipse.winery.common.ids.XMLId; + +public class DummyParentForGeneratedXSDRef extends GenericId { + + protected DummyParentForGeneratedXSDRef() { + super(new XMLId("dummy", false)); + } + + @Override + public int compareTo(GenericId o) { + throw new IllegalStateException("Should never be called."); + } + + @Override + public GenericId getParent() { + throw new IllegalStateException("Should never be called."); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof DummyParentForGeneratedXSDRef); + } + + @Override + public int hashCode() { + return 0; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java new file mode 100644 index 0000000..ab8386f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.export; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.w3c.dom.Document; + +/** + * Class used to indicate reference to a generated XSD + */ +public class DummyRepositoryFileReferenceForGeneratedXSD extends RepositoryFileReference { + + private final Document document; + + + /** + * @param document the W3C DOM Document holding the generated XSD + */ + public DummyRepositoryFileReferenceForGeneratedXSD(Document document) { + // we have to create a unique filename in the case two different XSDs are exported + // document.hashCode should be unique enough for us + super(new DummyParentForGeneratedXSDRef(), Integer.toString(document.hashCode())); + this.document = document; + } + + public Document getDocument() { + return this.document; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java new file mode 100644 index 0000000..609d4d6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.export; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.HashSet; +import java.util.Queue; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; + +/** + * Holds the state of ids regarding the export <br /> + * + * Required as we do not know at the entry point (usually a service template), + * which other components are linked <br /> + * + * Users can call flagAsExportRequired more than once for the same id. If an id + * is already exported, it is not flagged as exported again + */ +public class ExportedState { + + private final Collection<TOSCAComponentId> exported = new HashSet<>(); + private final Queue<TOSCAComponentId> exportRequired = new ArrayDeque<>(); + + + /** + * @return the first tosca component id to be exported, null if no more + * elements are in the queue + */ + public TOSCAComponentId pop() { + return this.exportRequired.poll(); + } + + public void flagAsExported(TOSCAComponentId id) { + this.exportRequired.remove(id); + this.exported.add(id); + } + + /** + * Flags the given id as required for export, if not already exported + * + * @param id the id to flag + */ + public void flagAsExportRequired(TOSCAComponentId id) { + if (!this.exported.contains(id)) { + this.exportRequired.add(id); + } + } + + public void flagAsExportRequired(Collection<TOSCAComponentId> ids) { + for (TOSCAComponentId id : ids) { + if ((!this.exported.contains(id)) && (!this.exportRequired.contains(id))) { + this.exportRequired.add(id); + } + } + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java new file mode 100644 index 0000000..765b07a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java @@ -0,0 +1,802 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Kálmán Képes - initial API and implementation and/or initial documentation + * Oliver Kopp - adapted to new storage model and to TOSCA v1.0 + *******************************************************************************/ +package org.eclipse.winery.repository.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.constants.QNames; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.common.ids.definitions.EntityTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.RequirementTypeId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId; +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.common.ids.elements.PlansId; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Policies; +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition; +import org.eclipse.winery.model.tosca.TImplementationArtifact; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate.Capabilities; +import org.eclipse.winery.model.tosca.TNodeTemplate.Requirements; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TNodeType.CapabilityDefinitions; +import org.eclipse.winery.model.tosca.TNodeType.RequirementDefinitions; +import org.eclipse.winery.model.tosca.TPolicy; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRelationshipType.ValidSource; +import org.eclipse.winery.model.tosca.TRelationshipType.ValidTarget; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.JAXBSupport; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource; +import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplateResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.requirementtypes.RequirementTypeResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; +import org.w3c.dom.Document; + +public class TOSCAExportUtil { + + private static final XLogger logger = XLoggerFactory.getXLogger(TOSCAExportUtil.class); + + /* + * these two are GLOBAL VARIABLES leading to the fact that this class has to + * be constructed for each export + */ + + // collects the references to be put in the CSAR and the assigned path in + // the CSAR MANIFEST + // this allows to use other paths in the CSAR than on the local storage + private Map<RepositoryFileReference, String> referencesToPathInCSARMap = null; + + /** + * Currently a very simple approach to configure the export + */ + private Map<String, Object> exportConfiguration; + + + public enum ExportProperties { + INCLUDEXYCOORDINATES, REPOSITORY_URI + }; + + + /** + * Writes the <em>complete</em> tosca xml into the given outputstream + * + * @param id the id of the TOSCA component instance to export + * @param out outputstream to write to + * @param addRelatedComponents true: all referenced components + * (artifactTemplates, artifactTypes, ...) are added, false: only + * the XML belonging to the id is exported. If XML types are + * generated by Winery (e.g., the properties XSD for node types), + * these XML types are also exported + * @param exportConfiguration the configuration map for the export. Uses + * @param exportedState exportedState object to modify. ExportProperties + * provides the possible keys + * @return a collection of TOSCAcomponentIds referenced by the given + * component + * @throws JAXBException + */ + public Collection<TOSCAComponentId> exportTOSCA(TOSCAComponentId id, OutputStream out, Map<String, Object> exportConfiguration) throws IOException, JAXBException { + this.exportConfiguration = exportConfiguration; + this.initializeExport(); + return this.writeDefinitionsElement(id, out); + } + + private void initializeExport() { + this.setDefaultExportConfiguration(); + // quick hack to avoid NPE + if (this.referencesToPathInCSARMap == null) { + this.referencesToPathInCSARMap = new HashMap<>(); + } + } + + /** + * Quick hack to set defaults. Typically, a configuration builder or similar + * is used + */ + private void setDefaultExportConfiguration() { + this.checkConfig(ExportProperties.INCLUDEXYCOORDINATES, Boolean.FALSE); + } + + private void checkConfig(ExportProperties propKey, Boolean bo) { + if (!this.exportConfiguration.containsKey(propKey.toString())) { + this.exportConfiguration.put(propKey.toString(), bo); + } + } + + /** + * Writes the <em>complete</em> TOSCA XML into the given outputstream. + * Additionally, a the artifactMap is filled to enable the CSAR exporter to + * create necessary entries in TOSCA-Meta and to add them to the CSAR itself + * + * @param id the component instance to export + * @param out outputstream to write to + * @param exportConfiguration Configures the exporter + * @param referencesToPathInCSARMap collects the references to export. It is + * updated during the export + * @return a collection of TOSCAcomponentIds referenced by the given + * component + * @throws JAXBException + */ + protected Collection<TOSCAComponentId> exportTOSCA(TOSCAComponentId id, OutputStream out, Map<RepositoryFileReference, String> referencesToPathInCSARMap, Map<String, Object> exportConfiguration) throws IOException, JAXBException { + this.referencesToPathInCSARMap = referencesToPathInCSARMap; + return this.exportTOSCA(id, out, exportConfiguration); + } + + /** + * Called when the entry resource is definitions backed + * + * @throws JAXBException + */ + private void writeDefinitionsElement(Definitions entryDefinitions, OutputStream out) throws JAXBException { + Marshaller m = JAXBSupport.createMarshaller(true); + m.marshal(entryDefinitions, out); + } + + /** + * Writes the Definitions belonging to the given TOSCA component to the + * outputstream + * + * @return a collection of TOSCAcomponentIds referenced by the given + * component + * + * @throws IOException + * @throws JAXBException + * @throws IllegalStateException if tcId does not exist + */ + private Collection<TOSCAComponentId> writeDefinitionsElement(TOSCAComponentId tcId, OutputStream out) throws IOException, JAXBException { + if (!Repository.INSTANCE.exists(tcId)) { + String error = "Component instance " + tcId.toString() + " does not exist."; + TOSCAExportUtil.logger.error(error); + throw new IllegalStateException(error); + } + + AbstractComponentInstanceResource res = AbstractComponentsResource.getComponentInstaceResource(tcId); + Definitions entryDefinitions = res.getDefinitions(); + + // BEGIN: Definitions modification + // the "imports" collection contains the imports of Definitions, not of other definitions + // the other definitions are stored in entryDefinitions.getImport() + // we modify the internal definitions object directly. It is not written back to the storage. Therefore, we do not need to clone it + + // the imports (pointing to not-definitions (xsd, wsdl, ...)) already have a correct relative URL. (quick hack) + URI uri = (URI) this.exportConfiguration.get(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString()); + if (uri != null) { + // we are in the plain-XML mode, the URLs of the imports have to be adjusted + for (TImport i : entryDefinitions.getImport()) { + String loc = i.getLocation(); + assert (loc.startsWith("../")); + loc = loc.substring(3); + loc = uri + loc; + // now the location is an absolute URL + i.setLocation(loc); + } + } + + // files of imports have to be added to the CSAR, too + for (TImport i : entryDefinitions.getImport()) { + String loc = i.getLocation(); + if (Util.isRelativeURI(loc)) { + // locally stored, add to CSAR + GenericImportId iid = new GenericImportId(i); + String fileName = Util.getLastURIPart(loc); + fileName = Util.URLdecode(fileName); + RepositoryFileReference ref = new RepositoryFileReference(iid, fileName); + this.putRefAsReferencedItemInCSAR(ref); + } + } + + // adjust imports: add imports of definitions to it + Collection<TOSCAComponentId> referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds(tcId); + Collection<TImport> imports = new ArrayList<>(); + for (TOSCAComponentId id : referencedTOSCAComponentIds) { + this.addToImports(id, imports); + } + entryDefinitions.getImport().addAll(imports); + + if (res.getElement() instanceof TEntityType) { + // we have an entity type with a possible properties definition + EntityTypeResource entityTypeRes = (EntityTypeResource) res; + WinerysPropertiesDefinition wpd = ModelUtilities.getWinerysPropertiesDefinition(entityTypeRes.getEntityType()); + if (wpd != null) { + if (wpd.getIsDerivedFromXSD() == null) { + // Write WPD only to file if it exists and is NOT derived from an XSD (which may happen during import) + + String wrapperElementNamespace = wpd.getNamespace(); + String wrapperElementLocalName = wpd.getElementName(); + + // BEGIN: add import and put into CSAR + + TImport imp = new TImport(); + entryDefinitions.getImport().add(imp); + + // fill known import values + imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI); + imp.setNamespace(wrapperElementNamespace); + // add "winerysPropertiesDefinition" flag to import tag to support + Map<QName, String> otherAttributes = imp.getOtherAttributes(); + otherAttributes.put(QNames.QNAME_WINERYS_PROPERTIES_DEFINITION_ATTRIBUTE, "true"); + + // Determine location + String loc = BackendUtils.getImportLocationForWinerysPropertiesDefinitionXSD((EntityTypeId) tcId, uri, wrapperElementLocalName); + if (uri == null) { + TOSCAExportUtil.logger.trace("CSAR Export mode. Putting XSD into CSAR"); + // CSAR Export mode + // XSD has to be put into the CSAR + Document document = ModelUtilities.getWinerysPropertiesDefinitionXSDAsDocument(wpd); + + // loc in import is URLencoded, loc on filesystem isn't + String locInCSAR = Util.URLdecode(loc); + // furthermore, the path has to start from the root of the CSAR; currently, it starts from Definitions/ + locInCSAR = locInCSAR.substring(3); + TOSCAExportUtil.logger.trace("Location in CSAR: {}", locInCSAR); + this.referencesToPathInCSARMap.put(new DummyRepositoryFileReferenceForGeneratedXSD(document), locInCSAR); + } + imp.setLocation(loc); + + // END: add import and put into CSAR + + // BEGIN: generate TOSCA conforming PropertiesDefinition + + TEntityType entityType = entityTypeRes.getEntityType(); + PropertiesDefinition propertiesDefinition = new PropertiesDefinition(); + propertiesDefinition.setType(new QName(wrapperElementNamespace, wrapperElementLocalName)); + entityType.setPropertiesDefinition(propertiesDefinition); + + // END: generate TOSCA conforming PropertiesDefinition + } else { + // otherwise WPD exists, but is derived from XSD + // we DO NOT have to remove the winery properties definition from the output to allow "debugging" of the CSAR + } + } + } + + // END: Definitions modification + + this.writeDefinitionsElement(entryDefinitions, out); + + return referencedTOSCAComponentIds; + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(EntityTypeId id) { + return this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id); + } + + /** + * There is now equivalent id class for + * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal, + * therefore we take the super type and hope that the caller knows what he + * does. + */ + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(TOSCAComponentId id) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal res = (AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal) AbstractComponentsResource.getComponentInstaceResource(id); + String derivedFrom = res.getInheritanceManagement().getDerivedFrom(); + if (StringUtils.isEmpty(derivedFrom)) { + return Collections.emptySet(); + } else { + // Instantiate an id with the same class as the current id + TOSCAComponentId parentId; + QName qname = QName.valueOf(derivedFrom); + + Constructor<? extends TOSCAComponentId> constructor; + try { + constructor = id.getClass().getConstructor(QName.class); + } catch (NoSuchMethodException | SecurityException e1) { + throw new IllegalStateException("Could get constructor to instantiate parent id", e1); + } + try { + parentId = constructor.newInstance(qname); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + throw new IllegalStateException("Could not instantiate id for parent", e); + } + + Collection<TOSCAComponentId> result = new ArrayList<>(1); + result.add(parentId); + return result; + } + } + + /** + * This method is intended to be used by exportTOSCA. However, + * org.eclipse.winery.repository.client requires an XML representation of a + * component instances without a surrounding definitions element. + * + * We name this method differently to prevent wrong calling due to + * inheritance + * + * @param definitionsElement the parent XML element + */ + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(TOSCAComponentId id) { + Collection<TOSCAComponentId> referencedTOSCAComponentIds; + + // first of all, handle the concrete elements + if (id instanceof ServiceTemplateId) { + referencedTOSCAComponentIds = this.prepareForExport((ServiceTemplateId) id); + } else if (id instanceof NodeTypeId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((NodeTypeId) id); + } else if (id instanceof NodeTypeImplementationId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((NodeTypeImplementationId) id); + } else if (id instanceof RelationshipTypeId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RelationshipTypeId) id); + } else if (id instanceof RelationshipTypeImplementationId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RelationshipTypeImplementationId) id); + } else if (id instanceof RequirementTypeId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RequirementTypeId) id); + } else if (id instanceof CapabilityTypeId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((CapabilityTypeId) id); + } else if (id instanceof ArtifactTypeId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((ArtifactTypeId) id); + } else if (id instanceof ArtifactTemplateId) { + referencedTOSCAComponentIds = this.prepareForExport((ArtifactTemplateId) id); + } else if (id instanceof PolicyTypeId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((PolicyTypeId) id); + } else if (id instanceof PolicyTemplateId) { + referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((PolicyTemplateId) id); + } else if (id instanceof GenericImportId) { + // in case of imports, there are no other ids referenced + referencedTOSCAComponentIds = Collections.emptyList(); + } else { + throw new IllegalStateException("Unhandled id class " + id.getClass()); + } + + // Then, handle the super classes, which support inheritance + // Currently, it is EntityType and EntityTypeImplementation only + // Since the latter does not exist in the TOSCA MetaModel, we just handle EntityType here + if (id instanceof EntityTypeId) { + Collection<TOSCAComponentId> additionalRefs = this.getReferencedTOSCAComponentIds((EntityTypeId) id); + // the original referenceTOSCAComponentIds could be unmodifiable + // we just create a new one... + referencedTOSCAComponentIds = new ArrayList<>(referencedTOSCAComponentIds); + // ...and add the new reference + referencedTOSCAComponentIds.addAll(additionalRefs); + } + + return referencedTOSCAComponentIds; + } + + /** + * Adds the given id as import to the given imports collection + */ + private void addToImports(TOSCAComponentId id, Collection<TImport> imports) { + TImport imp = new TImport(); + imp.setImportType(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE); + imp.setNamespace(id.getNamespace().getDecoded()); + URI uri = (URI) this.exportConfiguration.get(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString()); + if (uri == null) { + // self-contained mode + // all Definitions are contained in "Definitions" directory, therefore, we provide the filename only + // references are resolved relatively from a definitions element (COS01, line 425) + String fn = CSARExporter.getDefinitionsFileName(id); + fn = Util.URLencode(fn); + imp.setLocation(fn); + } else { + String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id)); + path = path + "?definitions"; + URI absoluteURI = uri.resolve(path); + imp.setLocation(absoluteURI.toString()); + } + imports.add(imp); + + // FIXME: Currently the depended elements (such as the artifact templates linked to a node type implementation) are gathered by the corresponding "addXY" method. + // Reason: the corresponding TDefinitions element is *not* updated if a related element is added/removed. + // That means: The imports are not changed. + // The current issue is that TOSCA allows imports of Definitions only and the repository has the concrete elements as main structure + // Although during save the import can be updated (by fetching the associated resource and get the definitions of it), + // The concrete definitions cannot be determined without + // a) having a complete index of all definitions in the repository + // b) crawling through the *complete* repository + // Possibly the current solution, just lazily adding all dependent elements is the better solution. + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(NodeTypeImplementationId id) { + // We have to use a HashSet to ensure that no duplicate ids are added + // There may be multiple DAs/IAs referencing the same type + Collection<TOSCAComponentId> ids = new HashSet<>(); + + NodeTypeImplementationResource res = new NodeTypeImplementationResource(id); + + // DAs + TDeploymentArtifacts deploymentArtifacts = res.getNTI().getDeploymentArtifacts(); + if (deploymentArtifacts != null) { + for (TDeploymentArtifact da : deploymentArtifacts.getDeploymentArtifact()) { + QName qname; + if ((qname = da.getArtifactRef()) != null) { + ids.add(new ArtifactTemplateId(qname)); + } + ids.add(new ArtifactTypeId(da.getArtifactType())); + } + } + + // IAs + TImplementationArtifacts implementationArtifacts = res.getNTI().getImplementationArtifacts(); + if (implementationArtifacts != null) { + for (TImplementationArtifact ia : implementationArtifacts.getImplementationArtifact()) { + QName qname; + if ((qname = ia.getArtifactRef()) != null) { + ids.add(new ArtifactTemplateId(qname)); + } + ids.add(new ArtifactTypeId(ia.getArtifactType())); + } + } + + // inheritance + ids.addAll(this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id)); + + return ids; + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RelationshipTypeImplementationId id) { + // We have to use a HashSet to ensure that no duplicate ids are added + // There may be multiple IAs referencing the same type + Collection<TOSCAComponentId> ids = new HashSet<>(); + + RelationshipTypeImplementationResource res = new RelationshipTypeImplementationResource(id); + + // IAs + for (TImplementationArtifact ia : res.getRTI().getImplementationArtifacts().getImplementationArtifact()) { + QName qname; + if ((qname = ia.getArtifactRef()) != null) { + ids.add(new ArtifactTemplateId(qname)); + } + ids.add(new ArtifactTypeId(ia.getArtifactType())); + } + + // inheritance + ids.addAll(this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id)); + + return ids; + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RequirementTypeId id) { + Collection<TOSCAComponentId> ids = new ArrayList<>(1); + + RequirementTypeResource res = new RequirementTypeResource(id); + QName requiredCapabilityType = res.getRequirementType().getRequiredCapabilityType(); + if (requiredCapabilityType != null) { + CapabilityTypeId capId = new CapabilityTypeId(requiredCapabilityType); + ids.add(capId); + } + return ids; + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(CapabilityTypeId id) { + return Collections.emptyList(); + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(PolicyTypeId id) { + return Collections.emptyList(); + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(PolicyTemplateId id) { + Collection<TOSCAComponentId> ids = new ArrayList<>(); + PolicyTemplateResource res = new PolicyTemplateResource(id); + ids.add(new PolicyTypeId(res.getType())); + return ids; + } + + /** + * Synchronizes the plan model references and returns the referenced TOSCA + * Component Ids. + */ + private Collection<TOSCAComponentId> prepareForExport(ServiceTemplateId id) { + // We have to use a HashSet to ensure that no duplicate ids are added + // E.g., there may be multiple relationship templates having the same type + Collection<TOSCAComponentId> ids = new HashSet<>(); + ServiceTemplateResource res = new ServiceTemplateResource(id); + + // ensure that the plans stored locally are the same ones as stored in the definitions + res.synchronizeReferences(); + + // add all plans as reference in the CSAR + // the data model is consistent with the repository + // we crawl through the repository to as putRefAsReferencedItemInCSAR expects a repository file reference + PlansId plansContainerId = new PlansId(id); + SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class); + for (PlanId planId : nestedPlans) { + SortedSet<RepositoryFileReference> containedFiles = Repository.INSTANCE.getContainedFiles(planId); + // even if we currently support only one file in the directory, we just add everything + for (RepositoryFileReference ref : containedFiles) { + this.putRefAsReferencedItemInCSAR(ref); + } + } + + // add included things to export queue + + TBoundaryDefinitions boundaryDefs; + if ((boundaryDefs = res.getServiceTemplate().getBoundaryDefinitions()) != null) { + Policies policies = boundaryDefs.getPolicies(); + if (policies != null) { + for (TPolicy policy : policies.getPolicy()) { + PolicyTypeId policyTypeId = new PolicyTypeId(policy.getPolicyType()); + ids.add(policyTypeId); + } + } + + // reqs and caps don't have to be exported here as they are references to existing reqs/caps (of nested node templates) + } + + if (res.getServiceTemplate().getTopologyTemplate() != null) { + for (TEntityTemplate entityTemplate : res.getServiceTemplate().getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) { + QName qname = entityTemplate.getType(); + if (entityTemplate instanceof TNodeTemplate) { + ids.add(new NodeTypeId(qname)); + TNodeTemplate n = (TNodeTemplate) entityTemplate; + + // crawl through deployment artifacts + TDeploymentArtifacts deploymentArtifacts = n.getDeploymentArtifacts(); + if (deploymentArtifacts != null) { + List<TDeploymentArtifact> das = deploymentArtifacts.getDeploymentArtifact(); + for (TDeploymentArtifact da : das) { + ids.add(new ArtifactTypeId(da.getArtifactType())); + if ((qname = da.getArtifactRef()) != null) { + ids.add(new ArtifactTemplateId(qname)); + } + } + } + + // crawl through reqs/caps + Requirements requirements = n.getRequirements(); + if (requirements != null) { + for (TRequirement req : requirements.getRequirement()) { + QName type = req.getType(); + RequirementTypeId rtId = new RequirementTypeId(type); + ids.add(rtId); + } + } + Capabilities capabilities = n.getCapabilities(); + if (capabilities != null) { + for (TCapability cap : capabilities.getCapability()) { + QName type = cap.getType(); + CapabilityTypeId ctId = new CapabilityTypeId(type); + ids.add(ctId); + } + } + + // crawl through policies + org.eclipse.winery.model.tosca.TNodeTemplate.Policies policies = n.getPolicies(); + if (policies != null) { + for (TPolicy pol : policies.getPolicy()) { + QName type = pol.getPolicyType(); + PolicyTypeId ctId = new PolicyTypeId(type); + ids.add(ctId); + } + } + } else { + assert (entityTemplate instanceof TRelationshipTemplate); + ids.add(new RelationshipTypeId(qname)); + } + } + } + + return ids; + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(ArtifactTypeId id) { + // no recursive crawling needed + return Collections.emptyList(); + } + + /** + * Determines the referenced TOSCA Component Ids and also updates the + * references in the Artifact Template + * + * @return a collection of referenced TOCSA Component Ids + */ + private Collection<TOSCAComponentId> prepareForExport(ArtifactTemplateId id) { + Collection<TOSCAComponentId> ids = new ArrayList<>(); + + ArtifactTemplateResource res = new ArtifactTemplateResource(id); + + // "Export" type + QName type = res.getType(); + if (type == null) { + throw new IllegalStateException("Type is null for " + id.toString()); + } + ids.add(new ArtifactTypeId(type)); + + // Export files + + // This method is called BEFORE the concrete definitions element is written. + // Therefore, we adapt the content of the attached files to the really existing files + res.synchronizeReferences(); + + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(id); + SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(fileDir); + for (RepositoryFileReference ref : files) { + // Even if writing a TOSCA only (!this.writingCSAR), + // we put the virtual path in the TOSCA + // Reason: Winery is mostly used as a service and local storage + // reference to not make sense + // The old implementation had absolutePath.toUri().toString(); + // there, but this does not work when using a cloud blob store. + + this.putRefAsReferencedItemInCSAR(ref); + } + + return ids; + } + + /** + * Puts the given reference as item in the CSAR + * + * Thereby, it uses the global variable referencesToPathInCSARMap + */ + private void putRefAsReferencedItemInCSAR(RepositoryFileReference ref) { + // Determine path + String path = BackendUtils.getPathInsideRepo(ref); + + // put mapping reference to path into global map + // the path is the same as put in "synchronizeReferences" + this.referencesToPathInCSARMap.put(ref, path); + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RelationshipTypeId id) { + Collection<TOSCAComponentId> ids = new ArrayList<>(); + + // add all implementations + Collection<RelationshipTypeImplementationId> allTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, id.getQName()); + for (RelationshipTypeImplementationId ntiId : allTypeImplementations) { + ids.add(ntiId); + } + + RelationshipTypeResource res = new RelationshipTypeResource(id); + TRelationshipType relationshipType = (TRelationshipType) res.getElement(); + + ValidSource validSource = relationshipType.getValidSource(); + if (validSource != null) { + QName typeRef = validSource.getTypeRef(); + // can be a node type or a requirement type + + // similar code as for valid target (difference: req/cap) + NodeTypeId ntId = new NodeTypeId(typeRef); + if (Repository.INSTANCE.exists(ntId)) { + ids.add(ntId); + } else { + RequirementTypeId rtId = new RequirementTypeId(typeRef); + ids.add(rtId); + } + } + + ValidTarget validTarget = relationshipType.getValidTarget(); + if (validTarget != null) { + QName typeRef = validTarget.getTypeRef(); + // can be a node type or a capability type + + // similar code as for valid target (difference: req/cap) + NodeTypeId ntId = new NodeTypeId(typeRef); + if (Repository.INSTANCE.exists(ntId)) { + ids.add(ntId); + } else { + CapabilityTypeId capId = new CapabilityTypeId(typeRef); + ids.add(capId); + } + } + + this.addVisualAppearanceToCSAR(id); + + return ids; + } + + private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(NodeTypeId id) { + Collection<TOSCAComponentId> ids = new ArrayList<>(); + Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, id.getQName()); + for (NodeTypeImplementationId ntiId : allNodeTypeImplementations) { + ids.add(ntiId); + } + + NodeTypeResource res = new NodeTypeResource(id); + TNodeType nodeType = (TNodeType) res.getElement(); + + // add all referenced requirement types + RequirementDefinitions reqDefsContainer = nodeType.getRequirementDefinitions(); + if (reqDefsContainer != null) { + List<TRequirementDefinition> reqDefs = reqDefsContainer.getRequirementDefinition(); + for (TRequirementDefinition reqDef : reqDefs) { + RequirementTypeId reqTypeId = new RequirementTypeId(reqDef.getRequirementType()); + ids.add(reqTypeId); + } + } + + // add all referenced capability types + CapabilityDefinitions capDefsContainer = nodeType.getCapabilityDefinitions(); + if (capDefsContainer != null) { + List<TCapabilityDefinition> capDefs = capDefsContainer.getCapabilityDefinition(); + for (TCapabilityDefinition capDef : capDefs) { + CapabilityTypeId capTypeId = new CapabilityTypeId(capDef.getCapabilityType()); + ids.add(capTypeId); + } + } + + this.addVisualAppearanceToCSAR(id); + + return ids; + } + + private void addVisualAppearanceToCSAR(TopologyGraphElementEntityTypeId id) { + VisualAppearanceId visId = new VisualAppearanceId(id); + if (Repository.INSTANCE.exists(visId)) { + // we do NOT check for the id, but simply check for bigIcon.png (only exists in NodeType) and smallIcon.png (exists in NodeType and RelationshipType) + + RepositoryFileReference ref = new RepositoryFileReference(visId, Filename.FILENAME_BIG_ICON); + if (Repository.INSTANCE.exists(ref)) { + this.referencesToPathInCSARMap.put(ref, BackendUtils.getPathInsideRepo(ref)); + } + + ref = new RepositoryFileReference(visId, Filename.FILENAME_SMALL_ICON); + if (Repository.INSTANCE.exists(ref)) { + this.referencesToPathInCSARMap.put(ref, BackendUtils.getPathInsideRepo(ref)); + } + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java new file mode 100644 index 0000000..26963a9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java @@ -0,0 +1,1158 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Kálmán Képes - initial API and implementation and/or initial documentation + * Oliver Kopp - adapted to new storage model and to TOSCA v1.0 + *******************************************************************************/ +package org.eclipse.winery.repository.importing; + +import static java.nio.file.FileVisitResult.CONTINUE; +import static java.nio.file.FileVisitResult.SKIP_SUBTREE; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.ws.rs.core.MediaType; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.io.FilenameUtils; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.EntityTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.common.ids.elements.PlansId; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.csar.toscametafile.TOSCAMetaFile; +import org.eclipse.winery.model.csar.toscametafile.TOSCAMetaFileParser; +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.TArtifactReference; +import org.eclipse.winery.model.tosca.TArtifactReference.Exclude; +import org.eclipse.winery.model.tosca.TArtifactReference.Include; +import org.eclipse.winery.model.tosca.TArtifactTemplate; +import org.eclipse.winery.model.tosca.TArtifactTemplate.ArtifactReferences; +import org.eclipse.winery.model.tosca.TDefinitions; +import org.eclipse.winery.model.tosca.TDefinitions.Types; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.PlanModelReference; +import org.eclipse.winery.model.tosca.TPlans; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.JAXBSupport; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.backend.filebased.FileUtils; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.export.CSARExporter; +import org.eclipse.winery.repository.resources.admin.NamespacesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** + * Imports a CSAR into the storage. As the internal storage format does not have + * CSARs as the topmost artifacts, but one TDefinition, the CSAR has to be split + * up into several components. + * + * Existing components are <em>not</em> replaced, but silently skipped + * + * Minor errors are logged and not further propagated / notified. That means, a + * user cannot see minor errors. Major errors are immediately thrown. + * + * One instance for each import + */ +public class CSARImporter { + + private static final Logger logger = LoggerFactory.getLogger(CSARImporter.class); + + // ExecutorService for XSD schema initialization + // Threads set to 1 to avoid testing for parallel processing of the same XSD file + private static final ExecutorService xsdParsingService = Executors.newFixedThreadPool(1); + + private static final ExecutorService entityTypeAdjestmentService = Executors.newFixedThreadPool(10); + + + /** + * Reads the CSAR from the given inputstream + * + * @param in the inputstream to read from + * @param errorList the list of errors during the import. Has to be non-null + * @param overwrite if true: contents of the repo are overwritten + * + * @throws InvalidCSARException if the CSAR is invalid + */ + public void readCSAR(InputStream in, List<String> errors, boolean overwrite, final boolean asyncWPDParsing) throws IOException { + // we have to extract the file to a temporary directory as + // the .definitions file does not necessarily have to be the first entry in the archive + Path csarDir = Files.createTempDirectory("winery"); + + try (ZipInputStream zis = new ZipInputStream(in)) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if (!entry.isDirectory()) { + Path targetPath = csarDir.resolve(entry.getName()); + Files.createDirectories(targetPath.getParent()); + Files.copy(zis, targetPath); + } + } + this.importFromDir(csarDir, errors, overwrite, asyncWPDParsing); + } catch (Exception e) { + CSARImporter.logger.debug("Could not import CSAR", e); + throw e; + } finally { + // cleanup: delete all contents of the temporary directory + FileUtils.forceDelete(csarDir); + } + } + + /** + * Import an extracted CSAR from a directory + * + * @param path the root path of an extracted CSAR file + * @param overwrite if true: contents of the repo are overwritten + * @param asyncWPDParsing true if WPD should be parsed asynchronously to + * speed up the import. Required, because JUnit terminates the + * used ExecutorService + * @throws InvalidCSARException + * @throws IOException + */ + void importFromDir(final Path path, final List<String> errors, final boolean overwrite, final boolean asyncWPDParsing) throws IOException { + Path toscaMetaPath = path.resolve("TOSCA-Metadata/TOSCA.meta"); + if (!Files.exists(toscaMetaPath)) { + errors.add("TOSCA.meta does not exist"); + return; + } + final TOSCAMetaFileParser tmfp = new TOSCAMetaFileParser(); + final TOSCAMetaFile tmf = tmfp.parse(toscaMetaPath); + + // we do NOT do any sanity checks, of TOSAC.meta + // and just start parsing + + if (tmf.getEntryDefinitions() != null) { + // we obey the entry definitions and "just" import that + // imported definitions are added recursively + Path defsPath = path.resolve(tmf.getEntryDefinitions()); + this.importDefinitions(tmf, defsPath, errors, overwrite, asyncWPDParsing); + + this.importSelfServiceMetaData(tmf, path, defsPath, errors); + } else { + // no explicit entry definitions found + // we import all available definitions + // The specification says (cos01, Section 16.1, line 2935) that all definitions are contained in the "Definitions" directory + // The alternative is to go through all entries in the TOSCA Meta File, but there is no guarantee that this list is complete + Path definitionsDir = path.resolve("Definitions"); + if (!Files.exists(definitionsDir)) { + errors.add("No entry definitions defined and Definitions directory does not exist."); + return; + } + final List<IOException> exceptions = new ArrayList<IOException>(); + Files.walkFileTree(definitionsDir, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + if (dir.endsWith("Definitions")) { + return FileVisitResult.CONTINUE; + } else { + return FileVisitResult.SKIP_SUBTREE; + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + try { + CSARImporter.this.importDefinitions(tmf, file, errors, overwrite, asyncWPDParsing); + } catch (IOException e) { + exceptions.add(e); + return FileVisitResult.TERMINATE; + } + return FileVisitResult.CONTINUE; + } + }); + + if (!exceptions.isEmpty()) { + // something went wrong during parsing + // we rethrow the exception + throw exceptions.get(0); + } + } + + this.importNamespacePrefixes(path); + } + + + private static final Pattern GENERATED_PREFIX_PATTERN = Pattern.compile("^ns\\d+$"); + + + /** + * Import namespace prefixes. This is kind of a quick hack. TODO: during the + * import, the prefixes should be extracted using JAXB and stored in the + * NamespacesResource + * + * @param rootPath the root path of the extracted CSAR + */ + private void importNamespacePrefixes(Path rootPath) { + Path properties = rootPath.resolve(CSARExporter.PATH_TO_NAMESPACES_PROPERTIES); + if (Files.exists(properties)) { + PropertiesConfiguration pconf; + try { + pconf = new PropertiesConfiguration(properties.toFile()); + } catch (ConfigurationException e) { + CSARImporter.logger.debug(e.getMessage(), e); + return; + } + Iterator<String> namespaces = pconf.getKeys(); + while (namespaces.hasNext()) { + boolean addToStorage = false; + String namespace = namespaces.next(); + if (NamespacesResource.INSTANCE.getIsPrefixKnownForNamespace(namespace)) { + String storedPrefix = NamespacesResource.getPrefix(namespace); + // QUICK HACK to check whether the prefix is a generated one + // We assume we know the internal generation routine + Matcher m = CSARImporter.GENERATED_PREFIX_PATTERN.matcher(storedPrefix); + if (m.matches()) { + // the stored prefix is a generated one + // replace it by the one stored in the exported properties + addToStorage = true; + } + } else { + addToStorage = true; + } + if (addToStorage) { + String prefix = pconf.getString(namespace); + NamespacesResource.INSTANCE.addNamespace(namespace, prefix); + } + } + } + } + + /** + * Imports a self-service meta data description (if available) + * + * The first service template in the provided entry definitions is taken + * + * @param tmf + * + * @param errors + */ + private void importSelfServiceMetaData(final TOSCAMetaFile tmf, final Path rootPath, Path entryDefinitions, final List<String> errors) { + final Path selfServiceDir = rootPath.resolve(Constants.DIRNAME_SELF_SERVICE_METADATA); + if (!Files.exists(selfServiceDir)) { + CSARImporter.logger.debug("Self-service Portal directory does not exist in CSAR"); + return; + } + if (!Files.exists(entryDefinitions)) { + CSARImporter.logger.debug("Entry definitions does not exist."); + return; + } + + Unmarshaller um = JAXBSupport.createUnmarshaller(); + TDefinitions defs; + try { + defs = (TDefinitions) um.unmarshal(entryDefinitions.toFile()); + } catch (JAXBException e) { + errors.add("Could not unmarshal definitions " + entryDefinitions.getFileName() + " " + e.getMessage()); + return; + } catch (ClassCastException e) { + errors.add("Definitions " + entryDefinitions.getFileName() + " is not a TDefinitions " + e.getMessage()); + return; + } + + final int cutLength = selfServiceDir.toString().length() + 1; + Iterator<TExtensibleElements> iterator = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().iterator(); + boolean found = false; + TExtensibleElements next = null; + while (iterator.hasNext() && !found) { + next = iterator.next(); + if (next instanceof TServiceTemplate) { + found = true; + } + } + + if (found) { + TServiceTemplate serviceTemplate = (TServiceTemplate) next; + String namespace = serviceTemplate.getTargetNamespace(); + if (namespace == null) { + namespace = defs.getTargetNamespace(); + } + ServiceTemplateId stId = new ServiceTemplateId(namespace, serviceTemplate.getId(), false); + final SelfServiceMetaDataId id = new SelfServiceMetaDataId(stId); + + // QUICK HACK: We just import all data without any validation + // Reason: the metadata resource can deal with nearly arbitrary formats of the data, therefore we do not do any checking here + + try { + Files.walkFileTree(selfServiceDir, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + String name = file.toString().substring(cutLength); + // check: if name contains "/", this could lead to exceptions + RepositoryFileReference ref = new RepositoryFileReference(id, name); + + if (name.equals("data.xml")) { + // we have to check whether the data.xml contains + // (uri:"http://opentosca.org/self-service", local:"application") + // instead of + // (uri:"http://www.eclipse.org/winery/model/selfservice", local:"Application" + // We quickly replace it via String replacement instead of XSLT + try { + String oldContent = org.apache.commons.io.FileUtils.readFileToString(file.toFile(), "UTF-8"); + String newContent = oldContent.replace("http://opentosca.org/self-service", "http://www.eclipse.org/winery/model/selfservice"); + newContent = newContent.replace(":application", ":Application"); + if (!oldContent.equals(newContent)) { + // we replaced something -> write new content to old file + org.apache.commons.io.FileUtils.writeStringToFile(file.toFile(), newContent, "UTF-8"); + } + } catch (IOException e) { + CSARImporter.logger.debug("Could not replace content in data.xml", e); + } + } + CSARImporter.this.importFile(file, ref, tmf, rootPath, errors); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + CSARImporter.logger.debug(e.getMessage(), e); + errors.add("Self-service Meta Data: " + e.getMessage()); + } + } + + } + + /** + * Recursively imports the given definitions + * + * @param tmf the TOSCAMetaFile object holding the parsed content of a TOSCA + * meta file. If null, no files must be referenced from the given + * definitions + * @param overwrite true: existing contents are overwritten + * @param asyncWPDParsing + * @param definitions the path to the definitions to import + * + * @throws IOException + */ + public void importDefinitions(TOSCAMetaFile tmf, Path defsPath, final List<String> errors, boolean overwrite, boolean asyncWPDParsing) throws IOException { + if (defsPath == null) { + throw new IllegalStateException("path to definitions must not be null"); + } + if (!Files.exists(defsPath)) { + errors.add(String.format("Definitions %1$s does not exist", defsPath.getFileName())); + return; + } + + Unmarshaller um = JAXBSupport.createUnmarshaller(); + TDefinitions defs; + try { + defs = (TDefinitions) um.unmarshal(defsPath.toFile()); + } catch (JAXBException e) { + Throwable cause = e; + String eMsg = ""; + do { + String msg = cause.getMessage(); + if (msg != null) { + eMsg = eMsg + msg + "; "; + } + cause = cause.getCause(); + } while (cause != null); + errors.add("Could not unmarshal definitions " + defsPath.getFileName() + " " + eMsg); + CSARImporter.logger.debug("Unmarshalling error", e); + return; + } catch (ClassCastException e) { + errors.add("Definitions " + defsPath.getFileName() + " is not a TDefinitions " + e.getMessage()); + return; + } + + List<TImport> imports = defs.getImport(); + this.importImports(defsPath.getParent(), tmf, imports, errors, overwrite, asyncWPDParsing); + // imports has been modified to contain necessary imports only + + // this method adds new imports to defs which may not be imported using "importImports". + // Therefore, "importTypes" has to be called *after* importImports + this.importTypes(defs, errors); + + String defaultNamespace = defs.getTargetNamespace(); + List<TExtensibleElements> componentInstanceList = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation(); + for (final TExtensibleElements ci : componentInstanceList) { + // Determine namespace + String namespace = this.getNamespace(ci, defaultNamespace); + // Ensure that element has the namespace + this.setNamespace(ci, namespace); + + // Determine id + String id = ModelUtilities.getId(ci); + + // Determine WineryId + Class<? extends TOSCAComponentId> widClass = org.eclipse.winery.repository.Utils.getComponentIdClassForTExtensibleElements(ci.getClass()); + final TOSCAComponentId wid = BackendUtils.getTOSCAcomponentId(widClass, namespace, id, false); + + if (Repository.INSTANCE.exists(wid)) { + if (overwrite) { + Repository.INSTANCE.forceDelete(wid); + String msg = String.format("Deleted %1$s %2$s to enable replacement", ci.getClass().getName(), wid.getQName().toString()); + CSARImporter.logger.debug(msg); + } else { + String msg = String.format("Skipped %1$s %2$s, because it already exists", ci.getClass().getName(), wid.getQName().toString()); + CSARImporter.logger.debug(msg); + // this is not displayed in the UI as we currently do not distinguish between pre-existing types and types created during the import. + continue; + } + } + + // Create a fresh definitions object without the other data. + final Definitions newDefs = BackendUtils.createWrapperDefinitions(wid); + + // copy over the inputs determined by this.importImports + newDefs.getImport().addAll(imports); + + // add the current TExtensibleElements as the only content to it + newDefs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(ci); + + if (ci instanceof TArtifactTemplate) { + // convention: Definitions are stored in the "Definitions" directory, therefore going to levels up (Definitions dir -> root dir) resolves to the root dir + // COS01, line 2663 states that the path has to be resolved from the *root* of the CSAR + this.adjustArtifactTemplate(defsPath.getParent().getParent(), tmf, (ArtifactTemplateId) wid, (TArtifactTemplate) ci, errors); + } else if (ci instanceof TNodeType) { + this.adjustNodeType(defsPath.getParent().getParent(), (TNodeType) ci, (NodeTypeId) wid, tmf, errors); + } else if (ci instanceof TRelationshipType) { + this.adjustRelationshipType(defsPath.getParent().getParent(), (TRelationshipType) ci, (RelationshipTypeId) wid, tmf, errors); + } else if (ci instanceof TServiceTemplate) { + this.adjustServiceTemplate(defsPath.getParent().getParent(), tmf, (ServiceTemplateId) wid, (TServiceTemplate) ci, errors); + } + + // node types and relationship types are subclasses of TEntityType + // Therefore, we check the entity type separately here + if (ci instanceof TEntityType) { + if (asyncWPDParsing) { + // Adjusting takes a long time + // Therefore, we first save the type as is and convert to Winery-Property-Definitions in the background + CSARImporter.storeDefinitions(wid, newDefs); + CSARImporter.entityTypeAdjestmentService.submit(new Runnable() { + + @Override + public void run() { + CSARImporter.adjustEntityType((TEntityType) ci, (EntityTypeId) wid, newDefs, errors); + CSARImporter.storeDefinitions(wid, newDefs); + } + }); + } else { + CSARImporter.adjustEntityType((TEntityType) ci, (EntityTypeId) wid, newDefs, errors); + CSARImporter.storeDefinitions(wid, newDefs); + } + } else { + CSARImporter.storeDefinitions(wid, newDefs); + } + } + } + + /** + * Imports the specified types into the repository. The types are converted + * to an import statement + * + * @param errors Container for error messages + */ + private void importTypes(TDefinitions defs, final List<String> errors) { + Types typesContainer = defs.getTypes(); + if (typesContainer != null) { + List<Object> types = typesContainer.getAny(); + for (Object type : types) { + if (type instanceof Element) { + Element element = (Element) type; + + // generate id part of ImportId out of definitions' id + // we do not use the name as the name has to be URLencoded again and we have issues with the interplay with org.eclipse.winery.common.ids.definitions.imports.GenericImportId.getId(TImport) then. + String id = defs.getId(); + // try to make the id unique by hashing the "content" of the definition + id = id + "-" + Integer.toHexString(element.hashCode()); + + // set importId + TOSCAComponentId importId; + String ns; + if (element.getNamespaceURI().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) { + ns = element.getAttribute("targetNamespace"); + importId = new XSDImportId(ns, id, false); + } else { + // Quick hack for non-XML-Schema-definitions + ns = "unknown"; + importId = new GenericImportId(ns, id, false, element.getNamespaceURI()); + } + + // Following code is adapted from importOtherImports + + TDefinitions wrapperDefs = BackendUtils.createWrapperDefinitions(importId); + TImport imp = new TImport(); + String fileName = id + ".xsd"; + imp.setLocation(fileName); + imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI); + imp.setNamespace(ns); + wrapperDefs.getImport().add(imp); + CSARImporter.storeDefinitions(importId, wrapperDefs); + + // put the file itself to the repo + // ref is required to generate fileRef + RepositoryFileReference ref = BackendUtils.getRefOfDefinitions(importId); + RepositoryFileReference fileRef = new RepositoryFileReference(ref.getParent(), fileName); + // convert element to document + // QUICK HACK. Alternative: Add new method Repository.INSTANCE.getOutputStream and transform DOM node to OuptputStream + String content = Util.getXMLAsString(element); + try { + Repository.INSTANCE.putContentToFile(fileRef, content, MediaType.APPLICATION_XML_TYPE); + } catch (IOException e) { + CSARImporter.logger.debug("Could not put XML Schema definition to file " + fileRef.toString(), e); + errors.add("Could not put XML Schema definition to file " + fileRef.toString()); + } + + // add import to definitions + + // adapt path - similar to importOtherImport + String newLoc = "../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(fileRef)); + imp.setLocation(newLoc); + defs.getImport().add(imp); + } else { + // This is a known type. Otherwise JAX-B would render it as Element + errors.add("There is a Type of class " + type.getClass().toString() + " which is unknown to Winery. The type element is imported as is"); + } + } + } + } + + /** + * All EntityTypes may contain properties definition. In case a winery + * properties definition is found, the TOSCA conforming properties + * definition is removed + * + * @param ci the entity type + * @param wid the Winery id of the entitytype + * @param newDefs the definitions, the entiy type is contained in. The + * imports might be adjusted here + * @param errors + */ + private static void adjustEntityType(TEntityType ci, EntityTypeId wid, Definitions newDefs, final List<String> errors) { + PropertiesDefinition propertiesDefinition = ci.getPropertiesDefinition(); + if (propertiesDefinition != null) { + WinerysPropertiesDefinition winerysPropertiesDefinition = ModelUtilities.getWinerysPropertiesDefinition(ci); + boolean deriveWPD; + if (winerysPropertiesDefinition == null) { + deriveWPD = true; + } else { + if (winerysPropertiesDefinition.getIsDerivedFromXSD() == null) { + // if the winery's properties are defined by Winery itself, + // remove the TOSCA conforming properties definition as a Winery properties definition exists (and which takes precedence) + ci.setPropertiesDefinition(null); + + // no derivation from properties required as the properties are generated by Winery + deriveWPD = false; + + // we have to remove the import, too + // Determine the location + String elementName = winerysPropertiesDefinition.getElementName(); + String loc = BackendUtils.getImportLocationForWinerysPropertiesDefinitionXSD(wid, null, elementName); + // remove the import matching that location + List<TImport> imports = newDefs.getImport(); + boolean found = false; + if (imports != null) { + Iterator<TImport> iterator = imports.iterator(); + TImport imp; + while (iterator.hasNext()) { + imp = iterator.next(); + // TODO: add check for QNames.QNAME_WINERYS_PROPERTIES_DEFINITION_ATTRIBUTE instead of import location. The current routine, however, works, too. + if (imp.getLocation().equals(loc)) { + found = true; + break; + } + } + if (found) { + // imp with Winery's k/v location found + iterator.remove(); + // the XSD has been imported in importOtherImport + // it was too difficult to do the location check there, therefore we just remove the XSD from the repository here + XSDImportId importId = new XSDImportId(winerysPropertiesDefinition.getNamespace(), elementName, false); + try { + Repository.INSTANCE.forceDelete(importId); + } catch (IOException e) { + CSARImporter.logger.debug("Could not delete Winery's generated XSD definition", e); + errors.add("Could not delete Winery's generated XSD definition"); + } + } else { + // K/V properties definition was incomplete + } + } + } else { + // winery's properties are derived from an XSD + // The export does NOT add an imports statement: only the wpd exists + // We remove that as + ModelUtilities.removeWinerysPropertiesDefinition(ci); + // derive the WPDs again from the properties definition + deriveWPD = true; + } + } + if (deriveWPD) { + BackendUtils.deriveWPD(ci, errors); + } + } + } + + /** + * In case plans are provided, the plans are imported into Winery's storage + * + * @param rootPath the root path of the extracted csar + * @param tmf the TOSCAMetaFile object used to determine the mime type of + * the plan + * @param wid Winery's internal id of the service template + * @param st the the service template to be imported {@inheritDoc} + * + * @throws InvalidCSARException + */ + private void adjustServiceTemplate(Path rootPath, TOSCAMetaFile tmf, ServiceTemplateId wid, TServiceTemplate st, final List<String> errors) { + TPlans plans = st.getPlans(); + if (plans != null) { + for (TPlan plan : plans.getPlan()) { + PlanModelReference refContainer = plan.getPlanModelReference(); + if (refContainer != null) { + String ref = refContainer.getReference(); + if (ref != null) { + // URLs are stored encoded -> undo the encoding + ref = Util.URLdecode(ref); + URI refURI; + try { + refURI = new URI(ref); + } catch (URISyntaxException e) { + errors.add(String.format("Invalid URI %1$s", ref)); + continue; + } + if (refURI.isAbsolute()) { + // Points to somewhere external + // This is a linked plan + // We have to do nothing + continue; + } + Path path = rootPath.resolve(ref); + if (!Files.exists(path)) { + // possibly, the reference is relative to the Definitions subfolder + // COS01 does not make any explicit statement how to resolve the reference here + path = rootPath.resolve("Definitions").resolve(ref); + if (!Files.exists(path)) { + errors.add(String.format("Plan reference %1$s not found", ref)); + // we quickly remove the reference to reflect the not-found in the data + refContainer.setReference(null); + continue; + } + } + PlansId plansId = new PlansId(wid); + PlanId pid = new PlanId(plansId, new XMLId(plan.getId(), false)); + if (Files.isDirectory(path)) { + errors.add(String.format("Reference %1$s is a directory and Winery currently does not support importing directories", ref)); + continue; + } + RepositoryFileReference fref = new RepositoryFileReference(pid, path.getFileName().toString()); + this.importFile(path, fref, tmf, rootPath, errors); + + // file is imported + // Adjust the reference + refContainer.setReference("../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(fref))); + } + } + } + } + } + + /** + * Adds a color to the given relationship type + */ + private void adjustRelationshipType(Path rootPath, TRelationshipType ci, RelationshipTypeId wid, TOSCAMetaFile tmf, final List<String> errors) { + VisualAppearanceId visId = new VisualAppearanceId(wid); + this.importIcons(rootPath, visId, tmf, errors); + } + + private void adjustNodeType(Path rootPath, TNodeType ci, NodeTypeId wid, TOSCAMetaFile tmf, final List<String> errors) { + VisualAppearanceId visId = new VisualAppearanceId(wid); + this.importIcons(rootPath, visId, tmf, errors); + } + + private void importIcons(Path rootPath, VisualAppearanceId visId, TOSCAMetaFile tmf, final List<String> errors) { + String pathInsideRepo = BackendUtils.getPathInsideRepo(visId); + Path visPath = rootPath.resolve(pathInsideRepo); + this.importIcon(visId, visPath, Filename.FILENAME_BIG_ICON, tmf, rootPath, errors); + } + + private void importIcon(VisualAppearanceId visId, Path visPath, String fileName, TOSCAMetaFile tmf, Path rootPath, final List<String> errors) { + Path file = visPath.resolve(fileName); + if (Files.exists(file)) { + RepositoryFileReference ref = new RepositoryFileReference(visId, fileName); + this.importFile(file, ref, tmf, rootPath, errors); + } + } + + /** + * Adjusts the given artifact template to conform with the repository format + * + * We import the files given at the artifact references + * + * @throws InvalidCSARException + * @throws IOException + */ + private void adjustArtifactTemplate(Path rootPath, TOSCAMetaFile tmf, ArtifactTemplateId atid, TArtifactTemplate ci, final List<String> errors) throws IOException { + ArtifactReferences refs = ci.getArtifactReferences(); + if (refs == null) { + // no references stored - break + return; + } + List<TArtifactReference> refList = refs.getArtifactReference(); + Iterator<TArtifactReference> iterator = refList.iterator(); + while (iterator.hasNext()) { + TArtifactReference ref = iterator.next(); + String reference = ref.getReference(); + // URLs are stored encoded -> undo the encoding + reference = Util.URLdecode(reference); + + URI refURI; + try { + refURI = new URI(reference); + } catch (URISyntaxException e) { + errors.add(String.format("Invalid URI %1$s", ref)); + continue; + } + if (refURI.isAbsolute()) { + // Points to somewhere external + // We have to do nothing + continue; + } + + // we remove the current element as it will be handled during the export + iterator.remove(); + + Path path = rootPath.resolve(reference); + if (!Files.exists(path)) { + errors.add(String.format("Reference %1$s not found", reference)); + return; + } + Set<Path> allFiles; + if (Files.isRegularFile(path)) { + allFiles = new HashSet<Path>(); + allFiles.add(path); + } else { + assert (Files.isDirectory(path)); + Path localRoot = rootPath.resolve(path); + List<Object> includeOrExclude = ref.getIncludeOrExclude(); + + if (includeOrExclude.get(0) instanceof TArtifactReference.Exclude) { + // Implicit semantics of an exclude listed first: + // include all files and then exclude the files matched by the pattern + allFiles = this.getAllFiles(localRoot); + } else { + // semantics if include lited as first: + // same as listed at other places + allFiles = new HashSet<>(); + } + + for (Object object : includeOrExclude) { + if (object instanceof TArtifactReference.Include) { + this.handleInclude((TArtifactReference.Include) object, localRoot, allFiles); + } else { + assert (object instanceof TArtifactReference.Exclude); + this.handleExclude((TArtifactReference.Exclude) object, localRoot, allFiles); + } + } + } + this.importAllFiles(allFiles, atid, tmf, rootPath, errors); + } + + if (refList.isEmpty()) { + // everything is imported and is a file stored locally + // we don't need the references stored locally: they are generated on the fly when exporting + ci.setArtifactReferences(null); + } + } + + /** + * Imports a file from the filesystem to the repository + * + * @param p the file to read from + * @param fref the "file" to put the content to + * @param tmf the TOSCAMetaFile object used to determine the mimetype. Must + * not be null. + * @param rootPath used to relativize p to determine the mime type + * @throws InvalidCSARException + */ + private void importFile(Path p, RepositoryFileReference fref, TOSCAMetaFile tmf, Path rootPath, final List<String> errors) { + if (tmf == null) { + throw new IllegalStateException("tmf must not be null"); + } + try (InputStream is = Files.newInputStream(p); + BufferedInputStream bis = new BufferedInputStream(is)) { + String mediaType = tmf.getMimeType(p.relativize(rootPath).toString()); + if (mediaType == null) { + // Manually find out mime type + try { + mediaType = Utils.getMimeType(bis, p.getFileName().toString()); + } catch (IOException e) { + errors.add(String.format("No MimeType given for %1$s (%2$s)", p.getFileName(), e.getMessage())); + return; + } + if (mediaType == null) { + errors.add(String.format("No MimeType given for %1$s", p.getFileName())); + return; + } + } + try { + Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType)); + } catch (IllegalArgumentException | IOException e) { + throw new IllegalStateException(e); + } + } catch (IOException e1) { + throw new IllegalStateException("Could not work on generated temporary files", e1); + } + } + + private void importAllFiles(Collection<Path> allFiles, ArtifactTemplateId atid, TOSCAMetaFile tmf, Path rootPath, final List<String> errors) { + // import all files to repository + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(atid); + for (Path p : allFiles) { + if (!Files.exists(p)) { + errors.add(String.format("File %1$s does not exist", p.toString())); + return; + } + RepositoryFileReference fref = new RepositoryFileReference(fileDir, p.getFileName().toString()); + this.importFile(p, fref, tmf, rootPath, errors); + } + + } + + /** + * Modifies given allFiles object to exclude all files given by the excl + * pattern + * + * Semantics: Remove all files from the set, which match the given pattern + */ + private void handleExclude(Exclude excl, Path localRoot, Set<Path> allFiles) { + PathMatcher pathMatcher = localRoot.getFileSystem().getPathMatcher("glob:" + excl.getPattern()); + Iterator<Path> it = allFiles.iterator(); + while (it.hasNext()) { + Path curPath = it.next(); + if (pathMatcher.matches(curPath)) { + it.remove(); + } + } + } + + /** + * Modifies given allFiles object to include all files given by the incl + * pattern + * + * Semantics: Add all files from localRoot to allFiles matching the pattern + */ + private void handleInclude(final Include incl, final Path localRoot, final Set<Path> allFiles) { + final PathMatcher pathMatcher = localRoot.getFileSystem().getPathMatcher("glob:" + incl.getPattern()); + try { + Files.walkFileTree(localRoot, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Path relFile = localRoot.relativize(file); + if (pathMatcher.matches(relFile)) { + allFiles.add(file); + } + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + if (pathMatcher.matches(dir)) { + Set<Path> filesToAdd = CSARImporter.this.getAllFiles(dir); + allFiles.addAll(filesToAdd); + return SKIP_SUBTREE; + } else { + return CONTINUE; + } + } + }); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + /** + * Lists all files contained in the given path + */ + private Set<Path> getAllFiles(Path startPath) { + final Set<Path> res = new HashSet<>(); + try { + Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + res.add(file); + return CONTINUE; + } + }); + } catch (IOException e) { + throw new IllegalStateException(e); + } + return res; + } + + /** + * Sets the namespace on the CI if CI offers the method "setTargetNamespace" + * + * @param ci the component instance to set the namespace + * @param namespace the namespace to set + */ + private void setNamespace(TExtensibleElements ci, String namespace) { + Method method; + try { + method = ci.getClass().getMethod("setTargetNamespace", String.class); + method.invoke(ci, namespace); + } catch (NoSuchMethodException ne) { + // this is OK, because we do not check, whether the method really exists + // Special case for TArtifactTemplate not offering setTargetNamespace + // just ignore it + } catch (Exception e) { + throw new IllegalStateException("Could not set target namespace", e); + } + } + + /** + * @param ci the component instance to get the namespace from + * @param defaultNamespace the namespace to use if the TExtensibleElements + * has no targetNamespace + */ + private String getNamespace(TExtensibleElements ci, String defaultNamespace) { + Method method; + Object res; + try { + method = ci.getClass().getMethod("getTargetNamespace"); + res = method.invoke(ci); + } catch (Exception e) { + // we are at TArtifactTemplate, which does not offer getTargetNamespace + res = null; + } + String ns = (String) res; + if (ns == null) { + ns = defaultNamespace; + } + return ns; + } + + /** + * @param basePath the base path where to resolve files from. This is the + * directory of the Definitions + * @param imports the list of imports to import. SIDE EFFECT: this list is + * modified. After this method has run, the list contains the + * imports to be put into the wrapper element + */ + private void importImports(Path basePath, TOSCAMetaFile tmf, List<TImport> imports, final List<String> errors, boolean overwrite, final boolean asyncWPDParsing) throws IOException { + for (Iterator<TImport> iterator = imports.iterator(); iterator.hasNext();) { + TImport imp = iterator.next(); + String importType = imp.getImportType(); + String namespace = imp.getNamespace(); + String loc = imp.getLocation(); + + if (namespace == null) { + errors.add("not namespace-qualified imports are not supported."); + continue; + } + + if (loc == null) { + errors.add("Empty location imports are not supported."); + } else { + if (importType.equals(Namespaces.TOSCA_NAMESPACE)) { + if (!Util.isRelativeURI(loc)) { + errors.add("Absolute URIs for definitions import not supported."); + continue; + } + + // URIs are encoded + loc = Util.URLdecode(loc); + + Path defsPath = basePath.resolve(loc); + // fallback for older CSARs, where the location is given from the root + if (!Files.exists(defsPath)) { + defsPath = basePath.getParent().resolve(loc); + // the real existence check is done in importDefinitions + } + this.importDefinitions(tmf, defsPath, errors, overwrite, asyncWPDParsing); + // imports of definitions don't have to be kept as these are managed by Winery + iterator.remove(); + } else { + this.importOtherImport(basePath, imp, errors, importType, overwrite); + } + } + } + } + + /** + * SIDE EFFECT: modifies the location of imp to point to the correct + * relative location (when read from the exported CSAR) + * + * @param rootPath the absolute path where to resolve files from + */ + private void importOtherImport(Path rootPath, TImport imp, final List<String> errors, String type, boolean overwrite) { + assert (!type.equals(Namespaces.TOSCA_NAMESPACE)); + String loc = imp.getLocation(); + + if (!Util.isRelativeURI(loc)) { + // This is just an information message + errors.add("Absolute URIs are not resolved by Winery (" + loc + ")"); + return; + } + + // location URLs are encoded: http://www.w3.org/TR/2001/WD-charmod-20010126/#sec-URIs, RFC http://www.ietf.org/rfc/rfc2396.txt + loc = Util.URLdecode(loc); + Path path; + try { + path = rootPath.resolve(loc); + } catch (Exception e) { + // java.nio.file.InvalidPathException could be thrown which is a RuntimeException + errors.add(e.getMessage()); + return; + } + if (!Files.exists(path)) { + // fallback for older CSARs, where the location is given from the root + path = rootPath.getParent().resolve(loc); + if (!Files.exists(path)) { + errors.add(String.format("File %1$s does not exist", loc)); + return; + } + } + String namespace = imp.getNamespace(); + String fileName = path.getFileName().toString(); + String id = fileName; + id = FilenameUtils.removeExtension(id); + // Convention: id of import is filename without extension + + GenericImportId rid; + if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) { + rid = new XSDImportId(namespace, id, false); + } else { + rid = new GenericImportId(namespace, id, false, type); + } + + boolean importDataExistsInRepo = Repository.INSTANCE.exists(rid); + + if (!importDataExistsInRepo) { + // We have to + // a) create a .definitions file + // b) put the file itself in the repo + + // Create the definitions file + TDefinitions defs = BackendUtils.createWrapperDefinitions(rid); + defs.getImport().add(imp); + // QUICK HACK: We change the imp object's location here and below again + // This is "OK" as "storeDefinitions" serializes the current state and not the future state of the imp object + // change the location to point to the file in the folder of the .definitions file + imp.setLocation(fileName); + + // put the definitions file to the repository + CSARImporter.storeDefinitions(rid, defs); + } + + // put the file itself to the repo + // ref is required to generate fileRef + RepositoryFileReference ref = BackendUtils.getRefOfDefinitions(rid); + RepositoryFileReference fileRef = new RepositoryFileReference(ref.getParent(), fileName); + + // location is relative to Definitions/ + // even if the import already exists, we have to adapt the path + // URIs are encoded + String newLoc = "../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(fileRef)); + imp.setLocation(newLoc); + + if (!importDataExistsInRepo || overwrite) { + // finally write the file to the storage + try (InputStream is = Files.newInputStream(path); + BufferedInputStream bis = new BufferedInputStream(is)) { + MediaType mediaType; + if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) { + mediaType = MediaType.valueOf(MimeTypes.MIMETYPE_XSD); + } else { + String mimeType = Utils.getMimeType(bis, path.getFileName().toString()); + mediaType = MediaType.valueOf(mimeType); + } + Repository.INSTANCE.putContentToFile(fileRef, bis, mediaType); + } catch (IllegalArgumentException | IOException e) { + throw new IllegalStateException(e); + } + + // we have to update the cache in case of a new XSD to speedup usage of winery + if (rid instanceof XSDImportId) { + // We do the initialization asynchronously + // We do not check whether the XSD has already been checked + // We cannot just checck whether an XSD already has been handled since the XSD could change over time + // Synchronization at org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportResource.getAllDefinedLocalNames(short) also isn't feasible as the backend doesn't support locks + CSARImporter.xsdParsingService.submit(new Runnable() { + + @Override + public void run() { + CSARImporter.logger.debug("Updating XSD import cache data"); + // We call the queries without storing the result: + // We use the SIDEEFFECT that a cache is created + Utils.getAllXSDElementDefinitionsForTypeAheadSelection(); + Utils.getAllXSDTypeDefinitionsForTypeAheadSelection(); + CSARImporter.logger.debug("Updated XSD import cache data"); + } + }); + } + } + } + + private static void storeDefinitions(TOSCAComponentId id, TDefinitions defs) { + RepositoryFileReference ref = BackendUtils.getRefOfDefinitions(id); + String s = Utils.getXMLAsString(defs, true); + try { + Repository.INSTANCE.putContentToFile(ref, s, MediaType.valueOf(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS)); + } catch (IllegalArgumentException | IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java new file mode 100644 index 0000000..72d2220 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.json; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +public class TTopologyTemplateSerializer extends JsonSerializer<TTopologyTemplate> { + + /** + * Does NOT wrap the result into an object. Assumes that the current + * position at jgen is in an object + * + * @param value the list of entity templates to serialize + */ + public void serialize(List<TEntityTemplate> value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { + List<TRelationshipTemplate> relationshipTemplates = new ArrayList<TRelationshipTemplate>(); + + jgen.writeFieldName("nodeTemplates"); + jgen.writeStartObject(); + for (TEntityTemplate template : value) { + if (template instanceof TNodeTemplate) { + // write out as <id> : <default serialization> + jgen.writeFieldName(template.getId()); + provider.defaultSerializeValue(template, jgen); + + } else { + assert (template instanceof TRelationshipTemplate); + relationshipTemplates.add((TRelationshipTemplate) template); + } + } + jgen.writeEndObject(); + + jgen.writeFieldName("relationshipTemplates"); + jgen.writeStartObject(); + for (TRelationshipTemplate template : relationshipTemplates) { + // write out as <id> : <default serialization> + jgen.writeFieldName(template.getId()); + provider.defaultSerializeValue(template, jgen); + } + jgen.writeEndObject(); + } + + @Override + public void serialize(TTopologyTemplate topologyTemplate, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { + jgen.writeStartObject(); + + // write out the other fields unmodified + jgen.writeFieldName("documentation"); + provider.defaultSerializeValue(topologyTemplate.getDocumentation(), jgen); + jgen.writeFieldName("any"); + provider.defaultSerializeValue(topologyTemplate.getAny(), jgen); + jgen.writeFieldName("otherAttributes"); + provider.defaultSerializeValue(topologyTemplate.getOtherAttributes(), jgen); + + // finally, write the topology template + this.serialize(topologyTemplate.getNodeTemplateOrRelationshipTemplate(), jgen, provider); + + jgen.writeEndObject(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java new file mode 100644 index 0000000..e5d9950 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.json; + +import org.eclipse.winery.model.tosca.TTopologyTemplate; + +import com.fasterxml.jackson.databind.module.SimpleModule; + +@SuppressWarnings("serial") +public class TopologyTemplateModule extends SimpleModule { + + public TopologyTemplateModule() { + this.addSerializer(TTopologyTemplate.class, new TTopologyTemplateSerializer()); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java new file mode 100644 index 0000000..9393b7e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.API; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.select2.Select2DataWithOptGroups; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +public class APIResource { + + @GET + @Path("getallartifacttemplatesofcontaineddeploymentartifacts") + @Produces(MediaType.APPLICATION_JSON) + public Response getAllArtifactTemplatesOfContainedDeploymentArtifacts(@QueryParam("servicetemplate") String serviceTemplateQNameString, @QueryParam("nodetemplateid") String nodeTemplateId) { + if (StringUtils.isEmpty(serviceTemplateQNameString)) { + return Response.status(Status.BAD_REQUEST).entity("servicetemplate has be given as query parameter").build(); + } + + QName serviceTemplateQName = QName.valueOf(serviceTemplateQNameString); + + ServiceTemplateId serviceTemplateId = new ServiceTemplateId(serviceTemplateQName); + if (!Repository.INSTANCE.exists(serviceTemplateId)) { + return Response.status(Status.BAD_REQUEST).entity("service template does not exist").build(); + } + ServiceTemplateResource serviceTemplateResource = new ServiceTemplateResource(serviceTemplateId); + + Collection<QName> artifactTemplates = new ArrayList<>(); + List<TNodeTemplate> allNestedNodeTemplates = BackendUtils.getAllNestedNodeTemplates(serviceTemplateResource.getServiceTemplate()); + for (TNodeTemplate nodeTemplate : allNestedNodeTemplates) { + if (StringUtils.isEmpty(nodeTemplateId) || nodeTemplate.getId().equals(nodeTemplateId)) { + Collection<QName> ats = BackendUtils.getArtifactTemplatesOfReferencedDeploymentArtifacts(nodeTemplate); + artifactTemplates.addAll(ats); + } + } + + // convert QName list to select2 data + Select2DataWithOptGroups res = new Select2DataWithOptGroups(); + for (QName qName : artifactTemplates) { + res.add(qName.getNamespaceURI(), qName.toString(), qName.getLocalPart()); + } + return Response.ok().entity(res.asSortedSet()).build(); + } + + /** + * Implementation similar to + * getAllArtifactTemplatesOfContainedDeploymentArtifacts. Only difference is + * "getArtifactTemplatesOfReferencedImplementationArtifacts" instead of + * "getArtifactTemplatesOfReferencedDeploymentArtifacts". + */ + @GET + @Path("getallartifacttemplatesofcontainedimplementationartifacts") + @Produces(MediaType.APPLICATION_JSON) + public Response getAllArtifactTemplatesOfContainedImplementationArtifacts(@QueryParam("servicetemplate") String serviceTemplateQNameString, @QueryParam("nodetemplateid") String nodeTemplateId) { + if (StringUtils.isEmpty(serviceTemplateQNameString)) { + return Response.status(Status.BAD_REQUEST).entity("servicetemplate has be given as query parameter").build(); + } + QName serviceTemplateQName = QName.valueOf(serviceTemplateQNameString); + + ServiceTemplateId serviceTemplateId = new ServiceTemplateId(serviceTemplateQName); + if (!Repository.INSTANCE.exists(serviceTemplateId)) { + return Response.status(Status.BAD_REQUEST).entity("service template does not exist").build(); + } + ServiceTemplateResource serviceTemplateResource = new ServiceTemplateResource(serviceTemplateId); + + Collection<QName> artifactTemplates = new ArrayList<>(); + List<TNodeTemplate> allNestedNodeTemplates = BackendUtils.getAllNestedNodeTemplates(serviceTemplateResource.getServiceTemplate()); + for (TNodeTemplate nodeTemplate : allNestedNodeTemplates) { + if (StringUtils.isEmpty(nodeTemplateId) || nodeTemplate.getId().equals(nodeTemplateId)) { + Collection<QName> ats = BackendUtils.getArtifactTemplatesOfReferencedImplementationArtifacts(nodeTemplate); + artifactTemplates.addAll(ats); + } + } + + // convert QName list to select2 data + Select2DataWithOptGroups res = new Select2DataWithOptGroups(); + for (QName qName : artifactTemplates) { + res.add(qName.getNamespaceURI(), qName.toString(), qName.getLocalPart()); + } + return Response.ok().entity(res.asSortedSet()).build(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java new file mode 100644 index 0000000..6eda321 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +/** + * This package contains all packages providing extended access to the stored models + * + * The idea is that the resources provide information stored in the respective definition file. + * With this API, the stored data is interpreted more abstractly. As a long-term goal, things + * such as inherticance should be supported here + */ +package org.eclipse.winery.repository.resources.API;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java new file mode 100644 index 0000000..d4cc201 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java @@ -0,0 +1,516 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.StreamingOutput; +import javax.ws.rs.core.UriInfo; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.TOSCADocumentBuilderFactory; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.repository.JAXBSupport; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.constants.MediaTypes; +import org.eclipse.winery.repository.export.TOSCAExportUtil; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.documentation.DocumentationsResource; +import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportResource; +import org.eclipse.winery.repository.resources.tags.TagsResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import com.sun.jersey.api.view.Viewable; + +/** + * Resource for a component ( + * <ul> + * <li>ServiceTemplates,</li> + * <li>EntityTypes,</li> + * <li>EntityTypeImplementations,</li> + * <li>EntityTemplates</li> + * </ul> + * ). A component is directly nested in a TDefinitions element. See also + * {@link org.eclipse.winery.common.ids.definitions.TOSCAComponentId} + * + * Bundles all operations required for all components. e.g., namespace+XMLid, + * object comparison, import, export, tags + * + * Uses a TDefinitions document as storage. + * + * Additional setters and getters are added if it comes to Winery's extensions + * such as the color of a relationship type + */ +public abstract class AbstractComponentInstanceResource implements Comparable<AbstractComponentInstanceResource>, IPersistable { + + private static final Logger logger = LoggerFactory.getLogger(AbstractComponentInstanceResource.class); + + protected final TOSCAComponentId id; + + private final RepositoryFileReference ref; + + // the object representing the data of this resource + private Definitions definitions = null; + + // shortcut for this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + protected TExtensibleElements element = null; + + + /** + * Instantiates the resource. Assumes that the resource should exist + * (assured by the caller) + * + * The caller should <em>not</em> create the resource by other ways. E.g., + * by instantiating this resource and then adding data. + */ + public AbstractComponentInstanceResource(TOSCAComponentId id) { + this.id = id; + + // the resource itself exists + assert (Repository.INSTANCE.exists(id)); + + // the data file might not exist + this.ref = BackendUtils.getRefOfDefinitions(id); + if (Repository.INSTANCE.exists(this.ref)) { + this.load(); + } else { + this.createNew(); + } + } + + /** + * Convenience method for getId().getNamespace() + */ + public final Namespace getNamespace() { + return this.id.getNamespace(); + } + + /** + * Convenience method for getId().getXmlId() + */ + public final XMLId getXmlId() { + return this.id.getXmlId(); + } + + /** + * Convenience method for getId().getQName(); + * + * @return the QName associated with this resource + */ + public final QName getQName() { + return this.getId().getQName(); + } + + /** + * Returns the id associated with this resource + */ + public final TOSCAComponentId getId() { + return this.id; + } + + /** + * called from AbstractComponentResource + */ + @DELETE + public final Response onDelete() { + Response res = BackendUtils.delete(this.id); + return res; + } + + @Override + public final int compareTo(AbstractComponentInstanceResource o) { + return this.id.compareTo(o.id); + } + + @Override + public final boolean equals(Object o) { + if (o instanceof String) { + throw new IllegalStateException(); + } else if (o instanceof AbstractComponentInstanceResource) { + if (o.getClass().equals(this.getClass())) { + // only compare if the two objects are from the same class + return ((AbstractComponentInstanceResource) o).getId().equals(this.getId()); + } else { + throw new IllegalStateException(); + } + } else { + throw new IllegalStateException(); + } + } + + @Override + public final int hashCode() { + return this.getId().hashCode(); + } + + @GET + @Path("id") + public String getTOSCAId() { + return this.id.getXmlId().getDecoded(); + } + + @PUT + @Path("id") + public Response putId(@FormParam("id") String id) { + // this renames the entity type resource + // TODO: implement rename functionality + return Response.serverError().entity("not yet implemented").build(); + } + + /** + * Main page + */ + // @Produces(MediaType.TEXT_HTML) // not true because of ?csar leads to send + // a csar. We nevertheless have to annotate that to be able to get a JSON + // representation required for the file upload (in {@link + // ArtifactTemplateResource}) + // + // we cannot issue a request expecting content-type application/zip as it is + // not possible to offer the result in a "save-as"-dialog: + // http://stackoverflow.com/questions/7464665/ajax-response-content-disposition-attachment + @GET + @Produces(MediaType.TEXT_HTML) + public final Response getHTML(@QueryParam(value = "definitions") String definitions, @QueryParam(value = "csar") String csar, @Context UriInfo uriInfo) { + if (!Repository.INSTANCE.exists(this.id)) { + return Response.status(Status.NOT_FOUND).build(); + } + if (definitions != null) { + return Utils.getDefinitionsOfSelectedResource(this, uriInfo.getBaseUri()); + } else if (csar != null) { + return this.getCSAR(); + } else { + String type = Utils.getTypeForInstance(this.getClass()); + String viewableName = "/jsp/" + Utils.getIntermediateLocationStringForType(type, "/") + "/" + type.toLowerCase() + ".jsp"; + Viewable viewable = new Viewable(viewableName, this); + + return Response.ok().entity(viewable).build(); + + // we can't do the following as the GET request from the browser + // cannot set the accept header properly + // "vary: accept" header has to be set as we may also return a THOR + // on the same URL + // return Response.ok().header(HttpHeaders.VARY, + // HttpHeaders.ACCEPT).entity(viewable).build(); + } + } + + @GET + @Produces(MimeTypes.MIMETYPE_ZIP) + public final Response getCSAR() { + if (!Repository.INSTANCE.exists(this.id)) { + return Response.status(Status.NOT_FOUND).build(); + } + return Utils.getCSARofSelectedResource(this); + } + + /** + * Returns the definitions of this resource. Includes required imports of + * other definitions + * + * @param csar used because plan generator's GET request lands here + */ + @GET + @Produces({MimeTypes.MIMETYPE_TOSCA_DEFINITIONS, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public Response getDefinitionsAsResponse(@QueryParam(value = "csar") String csar) { + if (!Repository.INSTANCE.exists(this.id)) { + return Response.status(Status.NOT_FOUND).build(); + } + + if (csar != null) { + return Utils.getCSARofSelectedResource(this); + } + + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + TOSCAExportUtil exporter = new TOSCAExportUtil(); + // we include everything related + Map<String, Object> conf = new HashMap<>(); + try { + exporter.exportTOSCA(AbstractComponentInstanceResource.this.id, output, conf); + } catch (JAXBException e) { + throw new WebApplicationException(e); + } + } + }; + return Response.ok().type(MediaType.TEXT_XML).entity(so).build(); + } + + /** + * @throws IllegalStateException if an IOException occurred. We opted not to + * propagate the IOException directly as this exception occurs + * seldom and is a not an exception to be treated by all callers + * in the prototype. + */ + private void load() { + try { + InputStream is = Repository.INSTANCE.newInputStream(this.ref); + Unmarshaller u = JAXBSupport.createUnmarshaller(); + this.definitions = (Definitions) u.unmarshal(is); + } catch (Exception e) { + AbstractComponentInstanceResource.logger.error("Could not read content from file " + this.ref, e); + throw new IllegalStateException(e); + } + try { + this.element = this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + } catch (IndexOutOfBoundsException e) { + if (this instanceof GenericImportResource) { + // everything allright: + // ImportResource is a quick hack using 99% of the functionality offered here + // As only 1% has to be "quick hacked", we do that instead of a clean design + // Clean design: Introduce a class between this and AbstractComponentInstanceResource, where this class and ImportResource inhertis from + // A clean design introducing a super class AbstractDefinitionsBackedResource does not work, as we currently also support PropertiesBackedResources and such a super class would required multi-inheritance + } else { + throw new IllegalStateException("Wrong storage format: No ServiceTemplateOrNodeTypeOrNodeTypeImplementation found."); + } + } + } + + @Override + public void persist() throws IOException { + BackendUtils.persist(this.definitions, this.ref, MediaTypes.MEDIATYPE_TOSCA_DEFINITIONS); + } + + /** + * Creates a new instance of the object represented by this resource + */ + private void createNew() { + this.definitions = BackendUtils.createWrapperDefinitions(this.getId()); + + // create empty element + this.element = this.createNewElement(); + + // add the element to the definitions + this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(this.element); + + // copy ns + id + this.copyIdToFields(); + + // ensure that the definitions is persisted. Ensures that export works. + BackendUtils.persist(this); + } + + /** + * Creates an empty instance of an Element. + * + * The implementors do <em>not</em>have to copy the ns and the id to the + * appropriate fields. + * + * we have two implementation possibilities: + * <ul> + * <li>a) each subclass implements this method and returns the appropriate + * object</li> + * <li>b) we use java reflection to invoke the right constructor as done in + * the resources</li> + * </ul> + * We opted for a) to increase readability of the code + */ + protected abstract TExtensibleElements createNewElement(); + + /** + * Copies the current id of the resource to the appropriate fields in the + * element. + * + * For instance, the id is put in the "name" field for EntityTypes + * + * We opted for a separate method from createNewElement to enable renaming + * of the object + */ + protected abstract void copyIdToFields(); + + /** + * Returns the Element belonging to this resource. As Java does not allow + * overriding returned classes, we expect the caller to either cast right or + * to use "getXY" defined by each subclass, where XY is the concrete type + * + * Shortcut for + * getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation + * ().get(0); + * + * @return TCapabilityType|... + */ + public TExtensibleElements getElement() { + return this.element; + } + + /** + * @return the reference to the internal list of imports. Can be changed if + * some imports are required or should be removed + * @throws IllegalStateException if definitions was not loaded or not + * initialized + */ + protected List<TImport> getImport() { + if (this.definitions == null) { + throw new IllegalStateException("Trying to access uninitalized definitions object"); + } + return this.definitions.getImport(); + } + + /** + * Returns an XML representation of the definitions + * + * We return the complete definitions to allow the user changes to it, such + * as adding imports, etc. + */ + public String getDefinitionsAsXMLString() { + StringWriter w = new StringWriter(); + Marshaller m = JAXBSupport.createMarshaller(true); + try { + m.marshal(this.definitions, w); + } catch (JAXBException e) { + AbstractComponentInstanceResource.logger.error("Could not marshal definitions", e); + throw new IllegalStateException(e); + } + String res = w.toString(); + return res; + } + + /** + * @return the reference to the internal Definitions object + */ + public Definitions getDefinitions() { + return this.definitions; + } + + @PUT + @Consumes({MimeTypes.MIMETYPE_TOSCA_DEFINITIONS, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public Response updateDefinitions(InputStream requestBodyStream) { + Unmarshaller u; + Definitions defs; + Document doc; + final StringBuilder sb = new StringBuilder(); + try { + DocumentBuilder db = TOSCADocumentBuilderFactory.INSTANCE.getTOSCADocumentBuilder(); + db.setErrorHandler(new ErrorHandler() { + + @Override + public void warning(SAXParseException exception) throws SAXException { + // we don't care + } + + @Override + public void fatalError(SAXParseException exception) throws SAXException { + sb.append("Fatal Error: "); + sb.append(exception.getMessage()); + sb.append("\n"); + } + + @Override + public void error(SAXParseException exception) throws SAXException { + sb.append("Fatal Error: "); + sb.append(exception.getMessage()); + sb.append("\n"); + } + }); + doc = db.parse(requestBodyStream); + if (sb.length() > 0) { + // some error happened + // doc is not null, because the parser parses even if it is not XSD conforming + return Response.status(Status.BAD_REQUEST).entity(sb.toString()).build(); + } + } catch (SAXException | IOException e) { + AbstractComponentInstanceResource.logger.debug("Could not parse XML", e); + return Utils.getResponseForException(e); + } + try { + u = JAXBSupport.createUnmarshaller(); + defs = (Definitions) u.unmarshal(doc); + } catch (JAXBException e) { + AbstractComponentInstanceResource.logger.debug("Could not unmarshal from request body stream", e); + return Utils.getResponseForException(e); + } + + // initial validity check + + // we allow changing the target namespace and the id + // This allows for inserting arbitrary definitions XML + // if (!this.definitions.getTargetNamespace().equals(this.id.getNamespace().getDecoded())) { + // return Response.status(Status.BAD_REQUEST).entity("Changing of the namespace is not supported").build(); + // } + // this.definitions.setTargetNamespace(this.id.getNamespace().getDecoded()); + + // TODO: check the provided definitions for validity + + TExtensibleElements tExtensibleElements = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + if (!tExtensibleElements.getClass().equals(this.createNewElement().getClass())) { + return Response.status(Status.BAD_REQUEST).entity("First type in Definitions is not matching the type modeled by this resource").build(); + } + + this.definitions = defs; + + // replace existing element by retrieved data + this.element = this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + + // ensure that ids did not change + // TODO: future work: raise error if user changed id or namespace + this.copyIdToFields(); + + return BackendUtils.persist(this); + } + + @GET + @Path("xml/") + @Produces(MediaType.TEXT_HTML) + public Response getXML() { + Viewable viewable = new Viewable("/jsp/xmlSource.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @Path("documentation/") + public DocumentationsResource getDocumentationsResource() { + return new DocumentationsResource(this, this.getElement().getDocumentation()); + } + + @Path("tags/") + public final TagsResource getTags() { + return new TagsResource(this.id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java new file mode 100644 index 0000000..7bc7c73 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.lang.reflect.Method; + +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TEntityType.DerivedFrom; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Models a component instance with name, derived from, abstract, and final <br /> + * Tags are provided by AbstractComponentInstanceResource + * + * This class mirrors + * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinalConfigurationBacked + * . We did not include interfaces as the getters are currently only called at + * the jsp + */ +public abstract class AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal extends AbstractComponentInstanceResource { + + private static final Logger logger = LoggerFactory.getLogger(AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.class); + + + protected AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal(TOSCAComponentId id) { + super(id); + } + + /** + * @return The associated name of this resource. CSDPR01 foresees a NCName + * name and no ID for an entity type. Therefore, we use the ID as + * unique identification and convert it to a name when a read + * request is put. + */ + @GET + @Path("name") + public String getName() { + return ModelUtilities.getName(this.getElement()); + } + + @PUT + @Path("name") + public Response putName(String name) { + ModelUtilities.setName(this.getElement(), name); + return BackendUtils.persist(this); + } + + @GET + @Path("derivedFrom") + public String getDerivedFrom() { + // TOSCA does not introduce a type like WithNameDerivedFromAbstractFinal + // We could enumerate all possible implementing classes + // Or use java reflection, what we're doing now. + Method method; + // We have three different "DerivedFrom", for NodeTypeImplementation and RelationshipTypeImplementation, we have to assign to a different "DerivedFrom" + // This has to be done in the derived resources + DerivedFrom derivedFrom; + try { + method = this.getElement().getClass().getMethod("getDerivedFrom"); + derivedFrom = (DerivedFrom) method.invoke(this.getElement()); + } catch (ClassCastException e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Seems that *Implementation is now Definitions backed, but not yet fully implented", e); + throw new IllegalStateException(e); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not get derivedFrom", e); + throw new IllegalStateException(e); + } + if (derivedFrom == null) { + return null; + } + QName typeRef = derivedFrom.getTypeRef(); + if (typeRef == null) { + return null; + } else { + return typeRef.toString(); + } + } + + @PUT + @Path("derivedFrom") + public Response putDerivedFrom(String type) { + QName qname = QName.valueOf(type); + + // see getDerivedFrom for verbose comments + Method method; + DerivedFrom derivedFrom = new DerivedFrom(); + derivedFrom.setTypeRef(qname); + try { + method = this.getElement().getClass().getMethod("setDerivedFrom", DerivedFrom.class); + method.invoke(this.getElement(), derivedFrom); + } catch (ClassCastException e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Seems that *Implementation is now Definitions backed, but not yet fully implemented", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not set derivedFrom", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } + + return BackendUtils.persist(this); + } + + /** + * @param methodName the method to call: getAbstract|getFinal + * @return {@inheritDoc} + */ + private String getTBoolean(String methodName) { + // see getDerivedFrom for verbose comments + Method method; + TBoolean tBoolean; + try { + method = this.getElement().getClass().getMethod(methodName); + tBoolean = (TBoolean) method.invoke(this.getElement()); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not get boolean " + methodName, e); + throw new IllegalStateException(e); + } + if (tBoolean == null) { + return null; + } else { + return tBoolean.value(); + } + } + + /** + * @param methodName the method to call: setAbstract|setFinal + * @return {@inheritDoc} + */ + private Response putTBoolean(String tBooleanStr, String methodName) { + // see getDerivedFrom for verbose comments + + Method method; + TBoolean tBoolean = TBoolean.fromValue(tBooleanStr); + try { + method = this.getElement().getClass().getMethod(methodName, TBoolean.class); + method.invoke(this.getElement(), tBoolean); + } catch (Exception e) { + AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not set tBoolean " + methodName, e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } + + return BackendUtils.persist(this); + } + + /** + * Method name is not "getAbstract" as ${it.abstract} does not work as + * "abstract" is not allowed at that place + */ + @GET + @Path("abstract") + public String getIsAbstract() { + return this.getTBoolean("getAbstract"); + } + + @PUT + @Path("abstract") + public Response putIsAbstract(String isAbstract) { + return this.putTBoolean(isAbstract, "setAbstract"); + } + + @GET + @Path("final") + public String getIsFinal() { + return this.getTBoolean("getFinal"); + } + + @PUT + @Path("final") + public Response putIsFinal(String isFinal) { + return this.putTBoolean(isFinal, "setFinal"); + } + + /** + * @return resource managing abstract, final, derivedFrom + */ + @Path("inheritance/") + public InheritanceResource getInheritanceManagement() { + return new InheritanceResource(this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java new file mode 100644 index 0000000..3b63b0f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; + +public abstract class AbstractComponentInstanceWithReferencesResource extends AbstractComponentInstanceResource { + + public AbstractComponentInstanceWithReferencesResource(TOSCAComponentId id) { + super(id); + } + + /** + * Ensures that the presented XML is in line with the stored files + */ + @Override + public Response getXML() { + this.synchronizeReferences(); + return super.getXML(); + } + + @Override + public String getDefinitionsAsXMLString() { + this.synchronizeReferences(); + return super.getDefinitionsAsXMLString(); + } + + @Override + public Definitions getDefinitions() { + this.synchronizeReferences(); + return super.getDefinitions(); + } + + /** + * Synchronizes the artifact references with the files stored in the + * repository + */ + public abstract void synchronizeReferences(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java new file mode 100644 index 0000000..5702376 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java @@ -0,0 +1,279 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.io.StringWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.ResourceCreationResult; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.sun.jersey.api.NotFoundException; +import com.sun.jersey.api.view.Viewable; + +/** + * Resource handling of a set of components. Each component has to provide a + * class to handle the set. This is required to provide the correct instances of + * TOSCAcomponentIds. + * + * TODO: Add generics here! + * {@link Utils.getComponentIdClassForComponentContainer} is then obsolete + */ +public abstract class AbstractComponentsResource<R extends AbstractComponentInstanceResource> { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractComponentsResource.class); + + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + return Response.ok().entity(new Viewable("/jsp/genericcomponentpage.jsp", new GenericComponentPageData(this.getClass()))).build(); + } + + /** + * Creates a new component instance in the given namespace + * + * @param namespace plain namespace + * @param id plain id + */ + protected ResourceCreationResult onPost(String namespace, String name) { + ResourceCreationResult res; + if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(name)) { + res = new ResourceCreationResult(Status.BAD_REQUEST); + } else { + String id = Utils.createXMLidAsString(name); + TOSCAComponentId tcId; + try { + tcId = this.getTOSCAcomponentId(namespace, id, false); + res = this.createComponentInstance(tcId); + // in case the resource additionally supports a name attribute, we set the original name + if (res.getStatus().equals(Status.CREATED)) { + if ((tcId instanceof ServiceTemplateId) || (tcId instanceof ArtifactTemplateId) || (tcId instanceof PolicyTemplateId)) { + // these three types have an additional name (instead of a pure id) + // we store the name + IHasName resource = (IHasName) AbstractComponentsResource.getComponentInstaceResource(tcId); + resource.setName(name); + } + } + } catch (Exception e) { + AbstractComponentsResource.logger.debug("Could not create id instance", e); + res = new ResourceCreationResult(Status.INTERNAL_SERVER_ERROR); + } + } + return res; + } + + /** + * Creates a new component instance in the given namespace + * + * @param namespace plain namespace + * @param id plain id + * @param ignored this parameter is ignored, but necessary for + * {@link ArtifactTemplatesResource} to be able to accept the + * artifact type at a post + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response onPost(@FormParam("namespace") String namespace, @FormParam("name") String name, String ignored) { + ResourceCreationResult res = this.onPost(namespace, name); + return res.getResponse(); + } + + /** + * Creates a TOSCAcomponentId for the given namespace / id combination + * + * Uses reflection to create a new instance + */ + protected TOSCAComponentId getTOSCAcomponentId(String namespace, String id, boolean URLencoded) throws Exception { + Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass()); + return BackendUtils.getTOSCAcomponentId(idClass, namespace, id, URLencoded); + } + + /** + * Creates a new instance of the current component + * + * @return <ul> + * <li>Status.CREATED (201) if the resource has been created,</li> + * <li>Status.CONFLICT if the resource already exists,</li> + * <li>Status.INTERNAL_SERVER_ERROR (500) if something went wrong</li> + * </ul> + */ + protected ResourceCreationResult createComponentInstance(TOSCAComponentId tcId) { + return BackendUtils.create(tcId); + } + + @SuppressWarnings("unchecked") + private static Class<? extends AbstractComponentInstanceResource> getComponentInstanceResourceClassForType(String type) { + // Guess the package + String pkg = "org.eclipse.winery.repository.resources."; + + pkg += Utils.getIntermediateLocationStringForType(type, "."); + + // naming convention: Instance is named after container, but without the + // plural s + String className = pkg + "." + type + "Resource"; + try { + return (Class<? extends AbstractComponentInstanceResource>) Class.forName(className); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not find id class for component instance", e); + } + } + + /** + * + * @param namespace encoded namespace + * @param id encoded id + * @return an instance of the requested resource + */ + @Path("{namespace}/{id}/") + public R getComponentInstaceResource(@PathParam("namespace") String namespace, @PathParam("id") String id) { + return this.getComponentInstaceResource(namespace, id, true); + } + + /** + * @param encoded specifies whether namespace and id are encoded + * @return an instance of the requested resource + */ + @SuppressWarnings("unchecked") + public R getComponentInstaceResource(String namespace, String id, boolean encoded) { + TOSCAComponentId tcId; + try { + tcId = this.getTOSCAcomponentId(namespace, id, encoded); + } catch (Exception e) { + throw new IllegalStateException("Could not create id instance", e); + } + return (R) AbstractComponentsResource.getComponentInstaceResource(tcId); + } + + /** + * @return an instance of the requested resource + */ + public AbstractComponentInstanceResource getComponentInstaceResource(QName qname) { + return this.getComponentInstaceResource(qname.getNamespaceURI(), qname.getLocalPart(), false); + } + + /** + * @return an instance of the requested resource + * @throws NotFoundException if resource doesn't exist. + */ + public static AbstractComponentInstanceResource getComponentInstaceResource(TOSCAComponentId tcId) { + String type = Util.getTypeForComponentId(tcId.getClass()); + if (!Repository.INSTANCE.exists(tcId)) { + AbstractComponentsResource.logger.debug("TOSCA component id " + tcId.toString() + " not found"); + throw new NotFoundException("TOSCA component id " + tcId.toString() + " not found"); + } + Class<? extends AbstractComponentInstanceResource> newResource = AbstractComponentsResource.getComponentInstanceResourceClassForType(type); + Constructor<?>[] constructors = newResource.getConstructors(); + assert (constructors.length == 1); + AbstractComponentInstanceResource newInstance; + try { + newInstance = (AbstractComponentInstanceResource) constructors[0].newInstance(tcId); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + AbstractComponentsResource.logger.error("Could not instantiate sub resource " + tcId); + throw new IllegalStateException("Could not instantiate sub resource", e); + } + return newInstance; + } + + /** + * Returns resources for all known component instances + * + * Required by topologytemplateedit.jsp + */ + public Collection<AbstractComponentInstanceResource> getAll() { + Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass()); + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(idClass); + ArrayList<AbstractComponentInstanceResource> res = new ArrayList<AbstractComponentInstanceResource>(allTOSCAcomponentIds.size()); + for (TOSCAComponentId id : allTOSCAcomponentIds) { + AbstractComponentInstanceResource r = AbstractComponentsResource.getComponentInstaceResource(id); + res.add(r); + } + return res; + } + + /** + * Used by org.eclipse.winery.repository.repository.client and by the + * artifactcreationdialog.tag. Especially the "name" field is used there at + * the UI + * + * @return A list of all ids of all instances of this component type. If the + * "name" attribute is required, that name is used as id <br /> + * Format: + * <code>[({"namespace": "<namespace>", "id": "<id>"},)* ]</code>. A + * <code>name<code> field is added if the model allows an additional name attribute + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getListOfAllIds() { + Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass()); + boolean supportsNameAttribute = Util.instanceSupportsNameAttribute(idClass); + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(idClass); + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + + try { + JsonGenerator jg = jsonFactory.createGenerator(sw); + // We produce org.eclipse.winery.repository.client.WineryRepositoryClient.NamespaceAndId by hand here + // Refactoring could move this class to common and fill it here + jg.writeStartArray(); + for (TOSCAComponentId id : allTOSCAcomponentIds) { + jg.writeStartObject(); + jg.writeStringField("namespace", id.getNamespace().getDecoded()); + jg.writeStringField("id", id.getXmlId().getDecoded()); + if (supportsNameAttribute) { + AbstractComponentInstanceResource componentInstaceResource = AbstractComponentsResource.getComponentInstaceResource(id); + String name = ((IHasName) componentInstaceResource).getName(); + jg.writeStringField("name", name); + } + jg.writeEndObject(); + } + jg.writeEndArray(); + jg.close(); + } catch (Exception e) { + AbstractComponentsResource.logger.error(e.getMessage(), e); + return "[]"; + } + return sw.toString(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java new file mode 100644 index 0000000..33bc1d4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.backend.ResourceCreationResult; +import org.restdoc.annotations.RestDocParam; + +/** + * This class does NOT inherit from TEntityTemplatesResource<ArtifactTemplate> + * as these templates are directly nested in a TDefinitionsElement + */ +public abstract class AbstractComponentsWithTypeReferenceResource<T extends AbstractComponentInstanceResource> extends AbstractComponentsResource<T> { + + /** + * Creates the resource and sets the specified type + * + * In contrast to the other component instances in this package, we + * additionally need the parameter "type" to set the type of the artifact + * template. + * + * @param namespace Namespace of the template + * @param name name attribute of the template + * @param type: QName of the type, format: {namespace}localname is retrieved + * from namespace manager + * + * @return URI of the created Resource, null if resource already exists, + * URI_internalServerError if an internal server error occurred + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + @Override + public Response onPost(@RestDocParam(description = "Namespace of the component") @FormParam("namespace") String namespace, @RestDocParam(description = "name attribute of the component") @FormParam("name") String name, @RestDocParam(description = "QName of the type, format: {namespace}localname") @FormParam("type") String type) { + // only check for type parameter as namespace and name are checked in super.onPost + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).build(); + } + ResourceCreationResult creationResult = super.onPost(namespace, name); + if (!creationResult.isSuccess()) { + return creationResult.getResponse(); + } + if (creationResult.getStatus().equals(Status.CREATED)) { + IHasTypeReference resource = (IHasTypeReference) AbstractComponentsResource.getComponentInstaceResource((TOSCAComponentId) creationResult.getId()); + resource.setType(type); + // we assume that setType succeeded and just return the result of the + // creation of the artifact template resource + // Thus, we do NOT change res + } + return creationResult.getResponse(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java new file mode 100644 index 0000000..b9eb345 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +public class ConstraintResource extends EntityWithoutIdResource<TConstraint> { + + /** + * + * @param constraint the current constraint value + * @param list the list this constraint belongs to + * @param res the node type resource this constraint belongs to. Required + * for saving + */ + public ConstraintResource(TConstraint constraint, int idx, List<TConstraint> list, NodeTypeResource res) { + super(constraint, idx, list, res); + } + + /** + * Required for collectionResource + * + * @throws ClassCastException of !(res instanceof NodeTypeResource) + */ + public ConstraintResource(TConstraint constraint, int idx, List<TConstraint> list, AbstractComponentInstanceResource res) { + this(constraint, idx, list, (NodeTypeResource) res); + } + + private TConstraint getConstraint() { + return this.o; + } + + @GET + @Path("type") + @Produces(MediaType.TEXT_PLAIN) + public String getConstraintType() { + return this.getConstraint().getConstraintType(); + } + + @PUT + @Path("type") + @Consumes(MediaType.TEXT_PLAIN) + public Response putConstraintType(String constraintType) { + this.getConstraint().setConstraintType(constraintType); + return BackendUtils.persist(this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java new file mode 100644 index 0000000..8aea92f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class ConstraintsResource extends EntityWithoutIdCollectionResource<ConstraintResource, TConstraint> { + + private static final Logger logger = LoggerFactory.getLogger(ConstraintsResource.class); + + + public ConstraintsResource(List<TConstraint> constraints, NodeTypeResource res) { + super(ConstraintResource.class, TConstraint.class, constraints, res); + } + + @Override + public Viewable getHTML() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java new file mode 100644 index 0000000..1b70d56 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.datatypes.select2.Select2DataWithOptGroups; +import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup; +import org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource; + +public abstract class EntityTypeResource extends AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal { + + protected EntityTypeResource(TOSCAComponentId id) { + super(id); + } + + @Override + protected void copyIdToFields() { + TEntityType entityType = this.getEntityType(); + entityType.setTargetNamespace(this.getId().getNamespace().getDecoded()); + entityType.setName(this.getId().getXmlId().getDecoded()); + } + + /** + * Convenience method to avoid casting. Required by + * PropertiesDefinitionResource's jsp + */ + public TEntityType getEntityType() { + return (TEntityType) this.element; + } + + /** + * Models PropertiesDefinition + */ + @Path("propertiesdefinition/") + public PropertiesDefinitionResource getPropertiesDefinitionResource() { + return new PropertiesDefinitionResource(this); + } + + /** + * Used by children to implement getListOfAllInstances() + */ + protected SortedSet<Select2OptGroup> getListOfAllInstances(Class<? extends TOSCAComponentId> clazz) { + Select2DataWithOptGroups data = new Select2DataWithOptGroups(); + + Collection<? extends TOSCAComponentId> instanceIds = BackendUtils.getAllElementsRelatedWithATypeAttribute(clazz, this.id.getQName()); + + for (TOSCAComponentId instanceId : instanceIds) { + String groupText = instanceId.getNamespace().getDecoded(); + String text = BackendUtils.getName(instanceId); + data.add(groupText, instanceId.getQName().toString(), text); + } + + return data.asSortedSet(); + } + + /** + * Returns an array suitable for processing in a {@code select2} field See + * {@link http://ivaynberg.github.io/select2} + * + * Each element: {id: "{ns}localname", text: "name/id"} + */ + @Path("instances/") + @GET + @Produces(MediaType.APPLICATION_JSON) + public SortedSet<Select2OptGroup> getListOfAllInstances() { + Response res = Response.status(Status.INTERNAL_SERVER_ERROR).entity("not yet implemented").build(); + throw new WebApplicationException(res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java new file mode 100644 index 0000000..a2a8533 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.util.Collection; +import java.util.Collections; +import java.util.SortedSet; + +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; +import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplatesResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationsResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class GenericComponentPageData { + + private static final Logger logger = LoggerFactory.getLogger(GenericComponentPageData.class); + + private final SortedSet<? extends TOSCAComponentId> componentInstanceIds; + + private final Class<? extends AbstractComponentsResource> resourceClass; + + + public GenericComponentPageData(Class<? extends AbstractComponentsResource> resourceClass) { + this.resourceClass = resourceClass; + Class<? extends TOSCAComponentId> cIdClass = Utils.getComponentIdClassForComponentContainer(resourceClass); + this.componentInstanceIds = Repository.INSTANCE.getAllTOSCAComponentIds(cIdClass); + } + + /** + * Outputs the data for GenericComponentPage (Name / Id / Namespace) needed + * for the genericcomponentpage.jsp + */ + public SortedSet<? extends TOSCAComponentId> getComponentInstanceIds() { + return this.componentInstanceIds; + } + + public String getType() { + return Utils.getTypeForComponentContainer(this.resourceClass); + } + + public String getCSSclass() { + // The resources do NOT know their CSS class + // Layout is far away from a resource + // Instead of a huge if/else-cascade, we derive the CSS name from the + // class name + String type = this.getType(); + // convention: first letter in small letters + String res = type.substring(0, 1).toLowerCase() + type.substring(1); + // this generated "xSDImport" as CSS class for XSDImport + return res; + } + + public String getLabel() { + String type = this.getType(); + // E.g., convert ArtifactTemplate to Artifact Template + String res = type.replaceAll("(\\p{Lower})(\\p{Upper})", "$1 $2"); + return res; + } + + /** + * Required for genericcomponentpage.jsp -> addComponentInstance.jsp + * + * May only be used if the component supports the type (e.g., artifact + * templates) + * + * @return the list of all known <em>types</em> + */ + public Collection<? extends TOSCAComponentId> getTypeSelectorData() { + Class<? extends TOSCAComponentId> typeIdClass; + if (this.resourceClass.equals(ArtifactTemplatesResource.class)) { + typeIdClass = ArtifactTypeId.class; + } else if (this.resourceClass.equals(NodeTypeImplementationsResource.class)) { + typeIdClass = NodeTypeId.class; + } else if (this.resourceClass.equals(RelationshipTypeImplementationsResource.class)) { + typeIdClass = RelationshipTypeId.class; + } else if (this.resourceClass.equals(PolicyTemplatesResource.class)) { + typeIdClass = PolicyTypeId.class; + } else { + return Collections.emptyList(); + } + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(typeIdClass); + return allTOSCAcomponentIds; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java new file mode 100644 index 0000000..51bbcf1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.io.InputStream; +import java.net.URI; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.elements.TOSCAElementId; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; + +//import com.fasterxml.jackson.annotation.JsonIgnore; // currently not required +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +/** + * Contains methods for both visual appearance for + * <ul> + * <li>node types</li> + * <li>relationship types</li> + * </ul> + */ +public abstract class GenericVisualAppearanceResource { + + protected final Map<QName, String> otherAttributes; + protected final TopologyGraphElementEntityTypeResource res; + protected final TOSCAElementId id; + + + @DELETE + public Response onDelete() { + return BackendUtils.delete(this.id); + } + + /** + * Used for GUI when accessing the resource as data E.g., for topology + * template + */ + //@JsonIgnore + public URI getAbsoluteURL() { + String URI = Prefs.INSTANCE.getResourcePath(); + URI = URI + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(this.id)); + return Utils.createURI(URI); + } + + //@JsonIgnore + public TOSCAElementId getId() { + return this.id; + } + + /** + * @param res + * @param otherAttributes the other attributes of the node/relationship type + * @param id the id of this subresource required for storing the images + */ + public GenericVisualAppearanceResource(TopologyGraphElementEntityTypeResource res, Map<QName, String> otherAttributes, VisualAppearanceId id) { + this.id = id; + this.res = res; + this.otherAttributes = otherAttributes; + } + + /** + * Determines repository reference to file in repo + */ + protected RepositoryFileReference getRepoFileRef(String name) { + return new RepositoryFileReference(this.id, name); + } + + protected Response getImage(String name, String modified) { + RepositoryFileReference target = this.getRepoFileRef(name); + return BackendUtils.returnRepoPath(target, modified); + } + + /** + * Arbitrary images are supported. There currently is no check for valid + * image media types + */ + protected Response putImage(String name, InputStream uploadedInputStream, MediaType mediaType) { + RepositoryFileReference target = this.getRepoFileRef(name); + return BackendUtils.putContentToFile(target, uploadedInputStream, mediaType); + } + + @GET + @Path("16x16") + public Response get16x16Image(@HeaderParam("If-Modified-Since") String modified) { + // Even if the extension is "png", it might contain a jpg, too + // We keep the file extension as the windows explorer can display previews even if the content is not a png + return this.getImage(Filename.FILENAME_SMALL_ICON, modified); + } + + @PUT + @Path("16x16") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response post16x16Image(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + return this.putImage(Filename.FILENAME_SMALL_ICON, uploadedInputStream, body.getMediaType()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java new file mode 100644 index 0000000..08a3696 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.restdoc.annotations.RestDoc; + +/** + * Ensures that the AbstractComponentInstance has a getName method + */ +public interface IHasName { + + @GET + @Path("name") + // @formatter:off + @RestDoc(methodDescription = "Returns the name of the element. " + + "Defaults to the ID of the element. " + + "Some other ComponentInstances either carry a name or an ID. ") + // @formatter:on + @Produces(MediaType.TEXT_PLAIN) + public String getName(); + + @PUT + @Path("name") + public Response setName(@FormParam("value") String name); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java new file mode 100644 index 0000000..cb42158 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +public interface IHasTypeReference { + + /** + * @return the QName of the type with full namespace, never null (according + * to spec) + */ + public QName getType(); + + /** + * Sets the type and directly persists the resource + */ + public Response setType(QName type); + + /** + * Calls setType(QName) with QName.valueOf(typeStr) + * + * Directly persists the resource + * + * @param typeStr a textual representation of a QName + */ + public Response setType(String typeStr); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java new file mode 100644 index 0000000..c8438ef --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +/** + * Implementors can have DAs attached + */ +public interface INodeTemplateResourceOrNodeTypeImplementationResource extends INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java new file mode 100644 index 0000000..7bd178e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import org.eclipse.winery.common.ids.Namespace; + +/** + * Implementors can have IAs or DAs attached + */ +public interface INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + + Namespace getNamespace(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java new file mode 100644 index 0000000..892a7cb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +/** + * Implementors can have IAs attached + */ +public interface INodeTypeImplementationResourceOrRelationshipTypeImplementationResource extends INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java new file mode 100644 index 0000000..7cc878a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.backend.Repository; + +import com.sun.jersey.api.view.Viewable; + +/** + * Class for managing inheritance properties: abstract, final, derivedFromn + * + * The linking in the resources tree is different than the others. Here, there + * is no additional Id generated. + * + * We separated the code here to have the collection of valid super types in a + * separate class. We think, this is less confusing than including this + * functionality in + * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinalDefinitionsBacked + */ +public class InheritanceResource { + + private AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal managedResource; + + + public InheritanceResource(AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal res) { + this.managedResource = res; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/inheritance.jsp", this); + } + + public String getIsAbstract() { + return this.managedResource.getIsAbstract(); + } + + public String getIsFinal() { + return this.managedResource.getIsAbstract(); + } + + public String getDerivedFrom() { + return this.managedResource.getDerivedFrom(); + } + + /** JSP Data **/ + + public SortedSet<? extends TOSCAComponentId> getPossibleSuperTypes() { + // sorted by Name, not by namespace + SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(this.managedResource.getId().getClass()); + SortedSet<? extends TOSCAComponentId> res = new TreeSet<>(allTOSCAcomponentIds); + res.remove(this.managedResource.getId()); + // FEATURE: Possibly exclude all subtypes to avoid circles. However, this could be disappointing for users who know what they are doing + return res; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java new file mode 100644 index 0000000..87b5275 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2012-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.io.FileUtils; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.importing.CSARImporter; +import org.eclipse.winery.repository.resources.API.APIResource; +import org.eclipse.winery.repository.resources.admin.AdminTopResource; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource; +import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplatesResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationsResource; +import org.eclipse.winery.repository.resources.entitytypes.artifacttypes.ArtifactTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.capabilitytypes.CapabilityTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.policytypes.PolicyTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.requirementtypes.RequirementTypesResource; +import org.eclipse.winery.repository.resources.imports.ImportsResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplatesResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.restdoc.annotations.RestDocReturnCode; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataParam; + +/** + * All paths listed here have to be listed in Jersey's filter configuration + */ +@Path("/") +public class MainResource { + + @Path("API/") + public APIResource api() { + return new APIResource(); + } + + @Path("artifacttemplates/") + public ArtifactTemplatesResource artifacttemplates() { + return new ArtifactTemplatesResource(); + } + + @Path("artifacttypes/") + public ArtifactTypesResource artifactypes() { + return new ArtifactTypesResource(); + } + + @Path("admin/") + public AdminTopResource admin() { + return new AdminTopResource(); + } + + @Path("capabilitytypes/") + public CapabilityTypesResource capabilitytypes() { + return new CapabilityTypesResource(); + } + + @Path("imports/") + public ImportsResource imports() { + return new ImportsResource(); + } + + @Path("nodetypes/") + public NodeTypesResource nodetypes() { + return new NodeTypesResource(); + } + + @Path("nodetypeimplementations/") + public NodeTypeImplementationsResource nodetypeimplementations() { + return new NodeTypeImplementationsResource(); + } + + @Path("other/") + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getOtherElements() { + return new Viewable("/jsp/otherElements.jsp"); + } + + @Path("policytemplates/") + public PolicyTemplatesResource policytemplates() { + return new PolicyTemplatesResource(); + } + + @Path("policytypes/") + public PolicyTypesResource policytypes() { + return new PolicyTypesResource(); + } + + @Path("relationshiptypes/") + public RelationshipTypesResource relationshiptypes() { + return new RelationshipTypesResource(); + } + + @Path("requirementtypes/") + public RequirementTypesResource requirementtypes() { + return new RequirementTypesResource(); + } + + @Path("relationshiptypeimplementations/") + public RelationshipTypeImplementationsResource relationshiptypeimplementations() { + return new RelationshipTypeImplementationsResource(); + } + + @Path("servicetemplates/") + public ServiceTemplatesResource servicetemplates() { + return new ServiceTemplatesResource(); + } + + /** + * Returns the main page of winery. + */ + @GET + @Produces(MediaType.TEXT_HTML) + public Response onGet() { + return Response.temporaryRedirect(Utils.createURI("servicetemplates/")).build(); + } + + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + @RestDoc(methodDescription = "Imports the given CSAR (sent by simplesinglefileupload.jsp)") + @RestDocReturnCode(code = "200", description = "If the CSAR could be partially imported, the points where it failed are returned in the body") + // @formatter:off + public Response importCSAR( + @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail, + @FormDataParam("overwrite") @RestDocParam(description = "true: content of CSAR overwrites existing content. false (default): existing content is kept") Boolean overwrite) { + // @formatter:on + CSARImporter importer = new CSARImporter(); + List<String> errors = new ArrayList<String>(); + boolean ow; + ow = (overwrite != null) && overwrite; + try { + importer.readCSAR(uploadedInputStream, errors, ow, true); + } catch (Exception e) { + return Response.serverError().entity("Could not import CSAR").entity(e.getMessage()).build(); + } + if (errors.isEmpty()) { + return Response.noContent().build(); + } else { + // In case there are errors, we send them as "bad request" + return Response.status(Status.BAD_REQUEST).entity(errors).build(); + } + } + + @POST + @Consumes(MediaType.APPLICATION_XML) + @Produces(MediaType.APPLICATION_JSON) + public Response importDefinitions(InputStream is) throws IOException { + File toscaFile; + toscaFile = File.createTempFile("TOSCA", ".tosca"); + FileUtils.copyInputStreamToFile(is, toscaFile); + CSARImporter importer = new CSARImporter(); + List<String> errors = new ArrayList<>(); + importer.importDefinitions(null, toscaFile.toPath(), errors, false, true); + if (errors.isEmpty()) { + return Response.noContent().build(); + } else { + return Response.status(Status.BAD_REQUEST).entity(errors).build(); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java new file mode 100644 index 0000000..3f79c87 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +/** + * Data used to render a submenu item + */ +public class SubMenuData { + + private final String href; + private final String text; + + public static final SubMenuData SUBMENU_DOCUMENTATION = new SubMenuData("#documentation", "Documentation"); + public static final SubMenuData SUBMENU_XML = new SubMenuData("#xml", "XML"); + + + public SubMenuData(String href, String text) { + this.href = href; + this.text = text; + } + + public String getHref() { + return this.href; + } + + public String getText() { + return this.text; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java new file mode 100644 index 0000000..85f565c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support; + +import java.io.IOException; + +public interface IPersistable { + + /** + * @throws IOException if content could not be updated in the repository + * @throws IllegalStateException if an JAXBException occurred. This should + * never happen. + */ + public void persist() throws IOException; +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java new file mode 100644 index 0000000..f150855 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections; + +import javax.ws.rs.core.Response; + +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; + +public class CollectionsHelper { + + private CollectionsHelper() { + } + + /** + * + * @param <X> + * @param resource the resource to be persisted + * @param idDetermination the object to use to determine the id of the + * entity + * @param entity the entity that was persisted. Used to determine the id + * @return the new id id of the resource + */ + public static <X> Response persist(IPersistable resource, IIdDetermination<X> idDetermination, X entity) { + Response res = BackendUtils.persist(resource); + if (res.getStatus() == 204) { + String id = idDetermination.getId(entity); + res = Response.ok(id).build(); + } + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java new file mode 100644 index 0000000..64d0fbe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections; + +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.datatypes.select2.Select2DataItem; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.NotFoundException; +import com.sun.jersey.api.view.Viewable; + +/** + * Class managing a list of entities. It is intended to manage subresources, + * which are stored in a list. Either all entities have a unique key given by + * the TOSCA specification (subclass EntityWithIdCollectionResource) or a unique + * key is generated (subclass EntityWithoutIdCollectionResource) + * + * @param <EntityResourceT> the resource modeling the entity + * @param <EntityT> the entity type of single items in the list + */ +public abstract class EntityCollectionResource<EntityResourceT extends EntityResource<EntityT>, EntityT> implements IIdDetermination<EntityT> { + + private static final Logger logger = LoggerFactory.getLogger(EntityCollectionResource.class); + + protected final List<EntityT> list; + + protected final IPersistable res; + + protected final Class<EntityT> entityTClazz; + + protected final Class<EntityResourceT> entityResourceTClazz; + + + /** + * @param clazz the class of EntityT. Required as it is not possible to call + * new EntityT (see http://stackoverflow.com/a/1090488/873282) + * @param list the list of entities contained in this resource. Has to be + * typed <Object> as not all TOSCA elements in the specification + * inherit from TExtensibleElements + * @param res the main resource the list is belonging to. Required for + * persistence. + */ + public EntityCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) { + this.entityResourceTClazz = entityResourceTClazz; + this.entityTClazz = entityTClazz; + this.list = list; + this.res = res; + } + + /** + * Returns a list of ids of all entities nested here + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Object getListOfAllEntityIds(@QueryParam("select2") String select2) { + if (select2 == null) { + return this.getListOfAllEntityIdsAsList(); + } else { + // return data ready for consumption by select2 + List<Select2DataItem> res = new ArrayList<Select2DataItem>(this.list.size()); + for (EntityT o : this.list) { + String id = this.getId(o); + Select2DataItem di = new Select2DataItem(id, id); + res.add(di); + } + return res; + } + } + + public List<String> getListOfAllEntityIdsAsList() { + List<String> res = new ArrayList<String>(this.list.size()); + for (EntityT o : this.list) { + // We assume that different Object serializations *always* have different hashCodes + res.add(this.getId(o)); + } + return res; + } + + /** + * Required by reqandcapdefs.jsp + */ + public List<EntityResourceT> getAllEntityResources() { + List<String> listOfAllSubResources = this.getListOfAllEntityIdsAsList(); + List<EntityResourceT> res = new ArrayList<EntityResourceT>(listOfAllSubResources.size()); + for (String id : listOfAllSubResources) { + res.add(this.getEntityResourceFromDecodedId(id)); + } + return res; + } + + public EntityResourceT getEntityResourceFromDecodedId(String id) { + EntityT entity = null; + int idx = -1; + for (EntityT c : this.list) { + idx++; + String cId = this.getId(c); + if (cId.equals(id)) { + entity = c; + break; + } + } + if (entity == null) { + throw new NotFoundException(); + } else { + return this.getEntityResourceInstance(entity, idx); + } + } + + @Path("{id}/") + public EntityResourceT getEntityResource(@PathParam("id") String id) { + if (id == null) { + throw new IllegalArgumentException("id has to be given"); + } + id = Util.URLdecode(id); + return this.getEntityResourceFromDecodedId(id); + } + + /** + * @param entity the entity to create a resource for + * @param idx the index in the list + * @return the resource managing the given entity + */ + protected abstract EntityResourceT getEntityResourceInstance(EntityT entity, int idx); + + @GET + @Produces(MediaType.TEXT_HTML) + @RestDoc(methodDescription = "@return the HTML fragment (DIV-container) to be embedded in the 'Interface' part of nodetype.js ") + public Response getHTMLAsResponse() { + Viewable viewable = this.getHTML(); + return Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build(); + } + + /** + * called by getHTMLAsResponse + */ + public abstract Viewable getHTML(); + + /** + * Adds a new entity + * + * In case the element already exists, we return "CONFLICT" + */ + @POST + @Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + public Response addNewElement(EntityT entity) { + if (entity == null) { + return Response.status(Status.BAD_REQUEST).entity("a valid XML/JSON element has to be posted").build(); + } + if (this.alreadyContains(entity)) { + // we do not replace the element, but replace it + return Response.status(Status.CONFLICT).build(); + } + this.list.add(entity); + return CollectionsHelper.persist(this.res, this, entity); + } + + @Override + public abstract String getId(EntityT entity); + + /** + * Checks for containment of e in the list. <code>equals</code> is not used + * as most EntityT do not offer a valid implementation + * + * @return true if list already contains e. + */ + public boolean alreadyContains(EntityT e) { + String id = this.getId(e); + for (EntityT el : this.list) { + if (this.getId(el).equals(id)) { + // break loop + // we found an equal list item + return true; + } + } + // all items checked: nothing equal contained + return false; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java new file mode 100644 index 0000000..361fcfb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; + +/** + * Class to hold a single entity residing in a list of entities + * + * @param <EntityT> the entity type contained in the list + */ +public abstract class EntityResource<EntityT> { + + // This is non-final as a "PUT" may update the object + // it might be unnecessary to update this object as the resource is created at each request + // We update the reference nevertheless to be safe if the resource is used in another context + protected EntityT o; + + protected final int idx; + + protected final List<EntityT> list; + + protected final IPersistable res; + + protected IIdDetermination<EntityT> idDetermination; + + + /** + * + * @param idDetermination the object offering determination of an id of + * EntityT. May be null. If null, then setIdDetermination(obj) + * has to be called to enable this class functioning properly + * @param o the object this resource is representing + * @param idx the index of the object in the list + * @param list the list, where the object is stored in + * @param res the resource the object/list belongs to + */ + public EntityResource(IIdDetermination<EntityT> idDetermination, EntityT o, int idx, List<EntityT> list, IPersistable res) { + this.idDetermination = idDetermination; + this.o = o; + this.idx = idx; + this.list = list; + this.res = res; + } + + /** + * Quick hack for AbstractReqOrCapDefResource which is itself an + * IIdDetermination + */ + protected final void setIdDetermination(IIdDetermination<EntityT> idDetermination) { + this.idDetermination = idDetermination; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getJSON() { + assert (this.o != null); + return Response.ok().entity(this.o).build(); + } + + @GET + @Produces(MediaType.TEXT_XML) + @SuppressWarnings("unchecked") + public Response getXML() { + assert (this.o != null); + // Utils.getXML has to be used as Jersey can only serialize XMLRootElements + return Utils.getXML((Class<EntityT>) this.o.getClass(), this.o); + } + + /** + * Replaces the whole entity by the given entity + * + * As we use the hash code as index, the index changes when the resource is + * updated. This is not in line with REST. The alternative implementation is + * to use the index in the list as resource identification. That changes at + * each modification of the list itself (if elements are deleted / inserted + * before the current entry). When using the hash value, users may + * concurrently edit items and the list may also be updated + * + * @return the new id. + */ + @PUT + @Consumes(MediaType.TEXT_XML) + @Produces(MediaType.TEXT_PLAIN) + public Response setValue(EntityT o) { + this.list.set(this.idx, o); + this.o = o; + return CollectionsHelper.persist(this.res, this.idDetermination, o); + } + + @DELETE + public Response onDelete() { + try { + this.list.remove(this.idx); + } catch (IndexOutOfBoundsException e) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not delete entity, even if it should exist").build(); + } + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java new file mode 100644 index 0000000..e479e70 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections; + +public interface IIdDetermination<EntityT> { + + /** + * @return the id of the given entity + */ + public String getId(EntityT e); +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java new file mode 100644 index 0000000..f428752 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections.withid; + +import java.lang.reflect.Constructor; +import java.util.List; + +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class EntityWithIdCollectionResource<EntityResourceT extends EntityWithIdResource<EntityT>, EntityT> extends EntityCollectionResource<EntityResourceT, EntityT> { + + private static final Logger logger = LoggerFactory.getLogger(EntityWithIdCollectionResource.class); + + + /** + * {@inheritDoc} + */ + public EntityWithIdCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) { + super(entityResourceTClazz, entityTClazz, list, res); + } + + /** + * Each CollectionResource has to implement the id getting by itself as + * TOSCA XSD does not provide a general purpose id fetching mechanism + */ + @Override + public abstract String getId(EntityT entity); + + @Override + protected EntityResourceT getEntityResourceInstance(EntityT entity, int idx) { + Constructor<EntityResourceT> constructor; + try { + constructor = this.entityResourceTClazz.getConstructor(IIdDetermination.class, this.entityTClazz, int.class, List.class, this.res.getClass()); + } catch (Exception e) { + try { + constructor = this.entityResourceTClazz.getConstructor(IIdDetermination.class, this.entityTClazz, int.class, List.class, IPersistable.class); + } catch (Exception e2) { + EntityWithIdCollectionResource.logger.debug("Could not get constructor", e); + EntityWithIdCollectionResource.logger.debug("res.getClass() was {}", this.res.getClass()); + throw new IllegalStateException(e2); + } + } + EntityResourceT newInstance; + try { + newInstance = constructor.newInstance(this, entity, idx, this.list, this.res); + } catch (Exception e) { + EntityWithIdCollectionResource.logger.debug("Could not instantiate class", e); + throw new IllegalStateException(e); + } + return newInstance; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java new file mode 100644 index 0000000..1ac6775 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections.withid; + +import java.util.List; + +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class EntityWithIdResource<EntityT> extends EntityResource<EntityT> { + + /** + * {@inheritDoc} + */ + public EntityWithIdResource(IIdDetermination<EntityT> idDetermination, EntityT o, int idx, List<EntityT> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java new file mode 100644 index 0000000..8255f5d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections.withoutid; + +import java.lang.reflect.Constructor; +import java.util.List; + +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.NotFoundException; + +/** + * Class managing a list of entities. It is intended to manage subresources, + * where the TOSCA specification did not specify a unique key. Currently, the + * hashCode of the XML String representation is used. If other representation + * should be used, the method {@code getEntityResource} has to be overriden. + * + * @param <EntityResourceT> the resource modeling the entity + * @param <EntityT> the entity type of single items in the list + */ +public abstract class EntityWithoutIdCollectionResource<EntityResourceT extends EntityWithoutIdResource<EntityT>, EntityT> extends EntityCollectionResource<EntityResourceT, EntityT> { + + private static final Logger logger = LoggerFactory.getLogger(EntityWithoutIdCollectionResource.class); + + + /** + * {@inheritDoc} + */ + public EntityWithoutIdCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) { + super(entityResourceTClazz, entityTClazz, list, res); + } + + /** + * Method searching the list for an id with the hashcode instead of + * getId(EntityT) + */ + @Override + @Path("{id}/") + public EntityResourceT getEntityResource(@PathParam("id") String id) { + id = Util.URLdecode(id); + int idInt; + try { + idInt = Integer.parseInt(id); + } catch (java.lang.NumberFormatException e) { + throw new NotFoundException(id + " is not a valid id"); + } + EntityT entity = null; + int idx = -1; + for (EntityT c : this.list) { + idx++; + // speed optimization - instead of using getId() we directly use the hash code + int hash = Utils.getXMLAsString(c).hashCode(); + if (hash == idInt) { + entity = c; + break; + } + } + if (entity == null) { + throw new NotFoundException(); + } else { + return this.getEntityResourceInstance(entity, idx); + } + } + + @Override + public String getId(EntityT entity) { + return IdDeterminationWithHashCode.INSTANCE.getId(entity); + } + + /** + * {@inheritDoc} + */ + @Override + protected EntityResourceT getEntityResourceInstance(EntityT entity, int idx) { + Constructor<EntityResourceT> constructor; + try { + constructor = this.entityResourceTClazz.getConstructor(this.entityTClazz, int.class, List.class, AbstractComponentInstanceResource.class); + } catch (Exception e) { + try { + constructor = this.entityResourceTClazz.getConstructor(this.entityTClazz, int.class, List.class, IPersistable.class); + } catch (NoSuchMethodException | SecurityException e1) { + EntityWithoutIdCollectionResource.logger.debug("Could not get constructor", e); + throw new IllegalStateException(e); + } + } + EntityResourceT newInstance; + try { + newInstance = constructor.newInstance(entity, idx, this.list, this.res); + } catch (Exception e) { + EntityWithoutIdCollectionResource.logger.debug("Could not instantiate class", e); + throw new IllegalStateException(e); + } + return newInstance; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java new file mode 100644 index 0000000..0cf2766 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections.withoutid; + +import java.util.List; + +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.EntityResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +/** + * {@inheritDoc} + */ +public abstract class EntityWithoutIdResource<EntityT> extends EntityResource<EntityT> { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + public EntityWithoutIdResource(EntityT o, int idx, List<EntityT> list, IPersistable res) { + super((IIdDetermination<EntityT>) IdDeterminationWithHashCode.INSTANCE, o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java new file mode 100644 index 0000000..6b4e247 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources._support.collections.withoutid; + +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class IdDeterminationWithHashCode implements IIdDetermination<Object> { + + public static final IdDeterminationWithHashCode INSTANCE = new IdDeterminationWithHashCode(); + + + @Override + public String getId(Object entity) { + // We assume that different Object serializations *always* have different hashCodes + int hash = Utils.getXMLAsString(entity).hashCode(); + return Integer.toString(hash); + } + + /** + * Static wrapper method for functions.tld + */ + public static String getIdStatically(Object entity) { + return IdDeterminationWithHashCode.INSTANCE.getId(entity); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java new file mode 100644 index 0000000..c62b344 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * This package contains abstract resources implementing common functionality to + * support collections of entities, where the data model does not provide a + * unique id + */ +package org.eclipse.winery.repository.resources._support.collections.withoutid;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java new file mode 100644 index 0000000..cd4e20e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin; + +import javax.ws.rs.DELETE; +import javax.ws.rs.core.Response; + +import org.apache.commons.configuration.Configuration; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.admin.AdminId; + +/** + * Instance of one admin resource + * + * Offers a configuration object to store data + */ +public abstract class AbstractAdminResource { + + protected final AdminId id; + protected Configuration configuration; + + + /** + * @param id the id of the element rendered by this resource + */ + public AbstractAdminResource(AdminId id) { + this.id = id; + this.configuration = Repository.INSTANCE.getConfiguration(id); + } + + @DELETE + public Response onDelete() { + return BackendUtils.delete(this.id); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java new file mode 100644 index 0000000..7e4a662 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager; + +import com.sun.jersey.api.view.Viewable; + +public class AdminTopResource { + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/admin/adminindex.jsp", this); + } + + @Path("namespaces/") + public NamespacesResource getNamespacesResource() { + return NamespacesResource.INSTANCE; + } + + @Path("repository/") + public RepositoryAdminResource getRepositoryAdminResource() { + return new RepositoryAdminResource(); + } + + @Path("planlanguages/") + public PlanLanguagesManager getPlanLanguagesResource() { + return PlanLanguagesManager.INSTANCE; + } + + @Path("plantypes/") + public PlanTypesManager getPlanTypesResource() { + return PlanTypesManager.INSTANCE; + } + + @Path("constrainttypes/") + public ConstraintTypesManager getConstraintTypesManager() { + return ConstraintTypesManager.INSTANCE; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java new file mode 100644 index 0000000..f8fb9f1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.TreeSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.admin.NamespacesId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.sun.jersey.api.view.Viewable; + +/** + * Manages prefixes for the namespaces + */ +public class NamespacesResource extends AbstractAdminResource { + + private static final Logger logger = LoggerFactory.getLogger(NamespacesResource.class); + + public final static NamespacesResource INSTANCE = new NamespacesResource(); + + private Integer nsCount = 0; + + + private NamespacesResource() { + super(new NamespacesId()); + + // globally set prefixes + // if that behavior is not desired, the code has to be moved to "generatePrefix" which checks for existence, ... + this.configuration.setProperty("http://www.w3.org/2001/XMLSchema", "xsd"); + this.configuration.setProperty("http://www.w3.org/XML/1998/namespace", "xmlns"); + this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE, "tosca"); + this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "winery"); + } + + private Collection<String> getAllPrefixes() { + Iterator<String> keys = this.configuration.getKeys(); + HashSet<String> res = new HashSet<String>(); + while (keys.hasNext()) { + String key = keys.next(); + String prefix = this.configuration.getString(key); + res.add(prefix); + } + return res; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/admin/namespaces.jsp", this); + return Response.ok().entity(viewable).build(); + } + + /** + * Sets / overwrites prefix/namespace mapping + * + * In case the prefix is already bound to another namespace, BAD_REQUEST is + * returned. + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addNamespace(@FormParam("namespace") String namespace, @FormParam("nsPrefix") String prefix) { + if (StringUtils.isEmpty(namespace)) { + return Response.status(Status.BAD_REQUEST).entity("namespace must be given.").build(); + } + if (StringUtils.isEmpty(prefix)) { + return Response.status(Status.BAD_REQUEST).entity("prefix must be given.").build(); + } + namespace = Util.URLdecode(namespace); + prefix = Util.URLdecode(prefix); + Collection<String> allPrefixes = this.getAllPrefixes(); + if (allPrefixes.contains(prefix)) { + if (NamespacesResource.getPrefix(namespace).equals(prefix)) { + return Response.notModified().build(); + } else { + // the requested prefix is already bound to a different namespace + return Response.status(Status.BAD_REQUEST).entity("prefix already bound to a different namespace.").build(); + } + } + this.configuration.setProperty(namespace, prefix); + return Response.noContent().build(); + } + + /** + * Deletes given namespace from the repository + * + * @param URI to delete. The namespace is URLencoded. + * @return + */ + @DELETE + @Path("{namespace}") + public Response onDelete(@PathParam("namespace") String URI) { + Response res; + URI = Util.URLdecode(URI); + if (this.configuration.containsKey(URI)) { + this.configuration.clearProperty(URI); + res = Response.noContent().build(); + } else { + res = Response.status(Status.NOT_FOUND).build(); + } + return res; + } + + /** + * SIDEFFECT: URI is added to list of known namespaces if it did not exist + * before + */ + public static String getPrefix(Namespace namespace) { + String ns = namespace.getDecoded(); + return NamespacesResource.getPrefix(ns); + } + + @Path("{namespace}") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getPrefixForEncodedNamespace(@PathParam("namespace") String URI) { + URI = Util.URLdecode(URI); + return NamespacesResource.getPrefix(URI); + } + + /** + * SIDEFFECT: URI is added to list of known namespaces if it did not exist + * before + */ + public static String getPrefix(String namespace) { + if (namespace == null) { + throw new IllegalArgumentException("Namespace must not be null"); + } + String prefix = NamespacesResource.INSTANCE.configuration.getString(namespace); + if (prefix == null) { + prefix = NamespacesResource.generatePrefix(namespace); + NamespacesResource.INSTANCE.configuration.setProperty(namespace, prefix); + } + return prefix; + } + + private static String generatePrefix(String namespace) { + String prefix = null; + Collection<String> allPrefixes = NamespacesResource.INSTANCE.getAllPrefixes(); + + // TODO: generate prefix using URI (and not "arbitrary" prefix) + do { + prefix = String.format("ns%d", NamespacesResource.INSTANCE.nsCount); + NamespacesResource.INSTANCE.nsCount++; + } while (allPrefixes.contains(prefix)); + return prefix; + } + + /** + * Returns the list of all namespaces registered with his manager. It could + * be incomplete, if entries have been added manually to the repository + * + * @return all namespaces registered with this manager. + */ + private HashSet<Namespace> getRegisteredNamespaces() { + HashSet<Namespace> res = new HashSet<Namespace>(); + Iterator<String> keys = this.configuration.getKeys(); + while (keys.hasNext()) { + String key = keys.next(); + Namespace ns = new Namespace(key, false); + res.add(ns); + } + return res; + } + + /** + * Returns the list of all namespaces registered with his manager and used + * at component instances. + */ + public static Collection<Namespace> getNamespaces() { + HashSet<Namespace> res = NamespacesResource.INSTANCE.getRegisteredNamespaces(); + res.addAll(Repository.INSTANCE.getUsedNamespaces()); + return res; + } + + /** + * This method is required because static methods cannot be accessed by EL + * + * @return see getNamespaces() + */ + public Collection<Namespace> getNamespacesForJSP() { + return NamespacesResource.getNamespaces(); + } + + /** + * Returns the list of all namespaces registered with his manager and used + * at component instances. + * + * @return a JSON list containing the non-encoded URIs of each known + * namespace + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getNamespacesAsJSONlist() { + Collection<Namespace> namespaces = NamespacesResource.getNamespaces(); + + // We now have all namespaces + // We need to convert from Namespace to String + + TreeSet<String> stringNamespaces = new TreeSet<String>(); + for (Namespace ns : namespaces) { + stringNamespaces.add(ns.getDecoded()); + } + + String res; + try { + res = Utils.mapper.writeValueAsString(stringNamespaces); + } catch (JsonProcessingException e) { + NamespacesResource.logger.error(e.getMessage(), e); + res = "[]"; + } + return res; + } + + /** + * Checks whether a prefix is registered for a namespace + * + * Used at CSARImporter + */ + public boolean getIsPrefixKnownForNamespace(String namespace) { + return this.configuration.containsKey(namespace); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java new file mode 100644 index 0000000..408704d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; + +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.backend.IRepositoryAdministration; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataParam; + +public class RepositoryAdminResource { + + private static final Logger logger = LoggerFactory.getLogger(RepositoryAdminResource.class); + + + // @formatter:off + @GET + @Produces(MediaType.TEXT_HTML) // we cannot add MimeTypes.MIMETYPE_ZIP as dumpRepository also produces that mimetype + @RestDoc(methodDescription = "Returns the repository admin page and implements administration utility") + public Response onGet( + @QueryParam(value = "dump") @RestDocParam(description = "If given, a dump of the repository is sent") String dump, + @QueryParam(value = "reset") @RestDocParam(description = "Resets the repository to the last “official” known state") String reset, + @QueryParam(value = "commit") @RestDocParam(description = "Commits the current state to the repository and pushes it upstream") String commit + ) { + // @formatter:on + if (dump != null) { + return this.dumpRepository(); + } else if (reset != null) { + try { + ((GitBasedRepository) Prefs.INSTANCE.getRepository()).cleanAndResetHard(); + } catch (Exception e) { + Response res; + res = Response.serverError().entity(e.getMessage()).build(); + return res; + } + return Response.noContent().build(); + } else if (commit != null) { + try { + ((GitBasedRepository) Prefs.INSTANCE.getRepository()).addCommitPush(); + } catch (Exception e) { + Response res; + res = Response.serverError().entity(e.getMessage()).build(); + return res; + } + return Response.noContent().build(); + } else { + Viewable viewable = new Viewable("/jsp/admin/repository.jsp", this); + return Response.ok().entity(viewable).build(); + } + } + + /** + * Imports the given ZIP + */ + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response importRepositoryDump(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) { + ((IRepositoryAdministration) Repository.INSTANCE).doImport(uploadedInputStream); + return Response.noContent().build(); + } + + @DELETE + public void deleteRepositoryData() { + ((IRepositoryAdministration) Repository.INSTANCE).doClear(); + } + + @GET + @Produces(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP) + public Response dumpRepository() { + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + ((IRepositoryAdministration) Repository.INSTANCE).doDump(output); + } + }; + StringBuilder sb = new StringBuilder(); + sb.append("attachment;filename=\"repository.zip\""); + return Response.ok().header("Content-Disposition", sb.toString()).type(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP).entity(so).build(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java new file mode 100644 index 0000000..bf3c024 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin.types; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.datatypes.TypeWithShortName; +import org.eclipse.winery.repository.datatypes.ids.admin.TypesId; +import org.eclipse.winery.repository.datatypes.select2.Select2DataItem; +import org.eclipse.winery.repository.resources.admin.AbstractAdminResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +/** + * Handles longname/shortname by using properties + * + * FIXME: This class does NOT support dynamic reloading of the underlying + * Configuration instance + * + */ +public abstract class AbstractTypesManager extends AbstractAdminResource { + + @Context + private UriInfo uriInfo; + + protected static final Logger logger = LoggerFactory.getLogger(AbstractTypesManager.class); + + // hashes from a long type string to the type object holding complete type data + private final HashMap<String, TypeWithShortName> hashTypeStringToType; + + + public AbstractTypesManager(TypesId id) { + super(id); + // now, this.configuration is filled with stored data + + // copy over information from configuration to internal data structure + this.hashTypeStringToType = new HashMap<String, TypeWithShortName>(); + Iterator<String> keys = this.configuration.getKeys(); + while (keys.hasNext()) { + String key = keys.next(); + String value = this.configuration.getString(key); + TypeWithShortName typeInfo = new TypeWithShortName(key, value); + this.hashTypeStringToType.put(key, typeInfo); + } + } + + protected void addData(String longName, String shortName) { + TypeWithShortName t = new TypeWithShortName(longName, shortName); + this.addData(t); + } + + /** + * Adds data to the internal data structure WITHOUT persisting it + * + * More or less a quick hack to enable adding default types without + * persisting them in the storage + * + * @param t the type to add + */ + private void addData(TypeWithShortName t) { + this.hashTypeStringToType.put(t.getType(), t); + } + + public synchronized void addTypeWithShortName(TypeWithShortName type) { + this.addData(type); + this.configuration.setProperty(type.getType(), type.getShortName()); + } + + /** + * Removes a type. Will not remove a type added by "addData" + */ + @DELETE + @Path("{type}") + public Response removeTypeWithResponse(@PathParam("type") String type) { + type = Util.URLdecode(type); + if (this.configuration.containsKey(type)) { + this.hashTypeStringToType.remove(type); + this.configuration.clearProperty(type); + return Response.noContent().build(); + } else if (this.hashTypeStringToType.containsKey(type)) { + // predefined types may not be deleted + // this branch is hit at types added via addData (e.g., predefined plantypes) + return Response.status(Status.FORBIDDEN).build(); + } else { + return Response.status(Status.NOT_FOUND).build(); + } + } + + /** + * Returns a sorted list of all available types + */ + public Collection<TypeWithShortName> getTypes() { + Collection<TypeWithShortName> res = new TreeSet<TypeWithShortName>(this.hashTypeStringToType.values()); + return res; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Object getTypesAsJSONArrayList(@QueryParam("select2") String select2) { + if (select2 == null) { + return this.getTypes(); + } else { + // select2 mode + SortedSet<Select2DataItem> res = new TreeSet<>(); + for (TypeWithShortName t : this.getTypes()) { + Select2DataItem item = new Select2DataItem(t.getType(), t.getShortName()); + res.add(item); + } + return res; + } + } + + /** + * <b>SIDEEFFECT:</b> If there currently isn't any short type name, it is + * created + */ + public TypeWithShortName getTypeWithShortName(String typeString) { + TypeWithShortName t = this.hashTypeStringToType.get(typeString); + if (t == null) { + String shortName = this.getShortName(typeString); + t = new TypeWithShortName(typeString, shortName); + this.addTypeWithShortName(t); + } + return t; + } + + /** + * <b>SIDEEFFECT:</b> If there currently isn't any short type name, it is + * created + */ + public String getShortName(String typeString) { + TypeWithShortName type = this.hashTypeStringToType.get(typeString); + String res; + if (type == null) { + // happens if artifact type is not registered in artifacttypes.list + // (DATAFILENAME) + res = typeString; + } else { + res = type.getShortName(); + } + return res; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML(@Context UriInfo uriInfo) { + this.uriInfo = uriInfo; + return new Viewable("/jsp/admin/types/types.jsp", this); + } + + @POST + public Response updateTypeMapping(@FormParam("shortname") String shortName, @FormParam("type") String type) { + if (StringUtils.isEmpty(shortName)) { + return Response.status(Status.BAD_REQUEST).entity("shortName has to be given").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("type has to be given").build(); + } + shortName = Util.URLdecode(shortName); + type = Util.URLdecode(type); + TypeWithShortName tws = new TypeWithShortName(type, shortName); + this.addTypeWithShortName(tws); + return Response.noContent().build(); + } + + /** + * Required by types.jsp + */ + public String getURL() { + return this.uriInfo.getAbsolutePath().toString(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java new file mode 100644 index 0000000..d8a9c0e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin.types; + +import org.eclipse.winery.repository.datatypes.ids.admin.ConstraintTypesId; + +public class ConstraintTypesManager extends AbstractTypesManager { + + public final static ConstraintTypesManager INSTANCE = new ConstraintTypesManager(); + + + private ConstraintTypesManager() { + super(new ConstraintTypesId()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java new file mode 100644 index 0000000..e5b35b9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin.types; + +import org.eclipse.winery.repository.datatypes.ids.admin.PlanLanguagesId; + +public class PlanLanguagesManager extends AbstractTypesManager { + + public final static PlanLanguagesManager INSTANCE = new PlanLanguagesManager(); + + + private PlanLanguagesManager() { + super(new PlanLanguagesId()); + // add data without rendering in the plan languages file + this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE, "BPEL 2.0 (executable)"); + this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPMN20_MODEL, "BPMN 2.0"); + this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20, "BPMN4TOSCA 2.0"); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java new file mode 100644 index 0000000..de6e7ba --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.admin.types; + +import org.eclipse.winery.repository.datatypes.ids.admin.PlanTypesId; + +public class PlanTypesManager extends AbstractTypesManager { + + public final static PlanTypesManager INSTANCE = new PlanTypesManager(); + + + private PlanTypesManager() { + super(new PlanTypesId()); + // add data without rendering in the plan types file + this.addData(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN, "Build Plan"); + this.addData(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_TERMINATION_PLAN, "Termination Plan"); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java new file mode 100644 index 0000000..ec7a86b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.artifacts; + +import java.util.List; + +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class DeploymentArtifactResource extends GenericArtifactResource<TDeploymentArtifact> { + + private final TDeploymentArtifact a; + + + /** + * Converts the given artifactId to an DeploymentArtifact. + * + * <em>SIDE EFFECT</em> Adds it to the DeploymentArtifacts list if it does + * not yet exist. + */ + private static TDeploymentArtifact getDeploymentArtifact(String artifactId, List<TDeploymentArtifact> deploymentArtifacts) { + for (TDeploymentArtifact ia : deploymentArtifacts) { + if (ia.getName().equals(artifactId)) { + return ia; + } + } + // DA does not exist in list + TDeploymentArtifact ia = new TDeploymentArtifact(); + ia.setName(artifactId); + deploymentArtifacts.add(ia); + return ia; + } + + public DeploymentArtifactResource(String artifactId, List<TDeploymentArtifact> deploymentArtifacts, IPersistable res) { + this(DeploymentArtifactResource.getDeploymentArtifact(artifactId, deploymentArtifacts), deploymentArtifacts, res); + } + + public DeploymentArtifactResource(IIdDetermination<TDeploymentArtifact> idDetermination, TDeploymentArtifact o, int idx, List<TDeploymentArtifact> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + this.a = o; + } + + public DeploymentArtifactResource(TDeploymentArtifact deploymentArtifact, List<TDeploymentArtifact> deploymentArtifacts, IPersistable res) { + this(new IIdDetermination<TDeploymentArtifact>() { + + @Override + public String getId(TDeploymentArtifact e) { + return e.getName(); + } + }, deploymentArtifact, deploymentArtifacts.indexOf(deploymentArtifact), deploymentArtifacts, res); + } + + public TDeploymentArtifact getDeploymentArtifact() { + return this.a; + } + + @Override + public void setArtifactType(ArtifactTypeId artifactTypeId) { + this.getDeploymentArtifact().setArtifactType(artifactTypeId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public void setArtifactTemplate(ArtifactTemplateId artifactTemplateId) { + this.getDeploymentArtifact().setArtifactRef(artifactTemplateId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public TDeploymentArtifact getA() { + return this.a; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java new file mode 100644 index 0000000..dcb5ca7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.artifacts; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DeploymentArtifactsResource extends GenericArtifactsResource<DeploymentArtifactResource, TDeploymentArtifact> { + + private static final Logger logger = LoggerFactory.getLogger(DeploymentArtifactsResource.class); + + private List<TDeploymentArtifact> deploymentArtifacts; + + + public DeploymentArtifactsResource(List<TDeploymentArtifact> deploymentArtifact, INodeTemplateResourceOrNodeTypeImplementationResource res) { + super(DeploymentArtifactResource.class, TDeploymentArtifact.class, deploymentArtifact, res); + this.deploymentArtifacts = deploymentArtifact; + } + + /** + * Determines the list of DAs belonging to the given node template. + * + * If no DAs are existing, an empty list is created in the model for the + * node template + */ + private static List<TDeploymentArtifact> getDeploymentArtifacts(TNodeTemplate nodeTemplate) { + TDeploymentArtifacts deploymentArtifacts = nodeTemplate.getDeploymentArtifacts(); + final List<TDeploymentArtifact> res; + if (deploymentArtifacts == null) { + deploymentArtifacts = new TDeploymentArtifacts(); + nodeTemplate.setDeploymentArtifacts(deploymentArtifacts); + } + res = deploymentArtifacts.getDeploymentArtifact(); + return res; + } + + public DeploymentArtifactsResource(TNodeTemplate nodeTemplate, INodeTemplateResourceOrNodeTypeImplementationResource res) { + this(DeploymentArtifactsResource.getDeploymentArtifacts(nodeTemplate), res); + } + + @Override + public Collection<DeploymentArtifactResource> getAllArtifactResources() { + Collection<DeploymentArtifactResource> res = new ArrayList<DeploymentArtifactResource>(this.deploymentArtifacts.size()); + for (TDeploymentArtifact da : this.deploymentArtifacts) { + DeploymentArtifactResource r = new DeploymentArtifactResource(da, this.deploymentArtifacts, this.res); + res.add(r); + } + return res; + } + + @Override + public String getId(TDeploymentArtifact entity) { + return entity.getName(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java new file mode 100644 index 0000000..9295082 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.artifacts; + +import java.util.List; + +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +/** + * Currently no common things for deployment artifacts and implementation + * artifacts as the data model also has no common ancestor (besides + * TExensibleElement) + */ +public abstract class GenericArtifactResource<ArtifactT> extends EntityWithIdResource<ArtifactT> { + + public GenericArtifactResource(IIdDetermination<ArtifactT> idDetermination, ArtifactT o, int idx, List<ArtifactT> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + public abstract void setArtifactType(ArtifactTypeId artifactTypeId); + + public abstract void setArtifactTemplate(ArtifactTemplateId artifactTemplateId); + + /** + * required by artifacts.jsp + */ + public abstract ArtifactT getA(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java new file mode 100644 index 0000000..0cef56e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java @@ -0,0 +1,572 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.artifacts; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.generators.ia.Generator; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TEntityTemplate.Properties; +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.ResourceCreationResult; +import org.eclipse.winery.repository.backend.filebased.FileUtils; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource; +import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; + +import com.sun.jersey.api.view.Viewable; + +/** + * Resource handling both deployment and implementation artifacts + * + */ +public abstract class GenericArtifactsResource<ArtifactResource extends GenericArtifactResource<ArtifactT>, ArtifactT> extends EntityWithIdCollectionResource<ArtifactResource, ArtifactT> { + + private static final Logger logger = LoggerFactory.getLogger(GenericArtifactsResource.class); + + protected final INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource resWithNamespace; + + + public GenericArtifactsResource(Class<ArtifactResource> entityResourceTClazz, Class<ArtifactT> entityTClazz, List<ArtifactT> list, INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) { + super(entityResourceTClazz, entityTClazz, list, GenericArtifactsResource.getAbstractComponentInstanceResource(res)); + this.resWithNamespace = res; + } + + // @formatter:off + + /** + * @return TImplementationArtifact | TDeploymentArtifact (XML) | URL of generated IA zip (in case of autoGenerateIA) + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_XML) + @RestDoc(methodDescription = "Creates a new implementation/deployment artifact. " + + "If an implementation artifact with the same name already exists, it is <em>overridden</em>.") + @SuppressWarnings("unchecked") + public Response onPost( + @FormParam("artifactName") + @RestDocParam(description = "This is the name of the implementation/deployment artifact. " + + "Is <em>also</em>used as prefix of the name of the corresponding artifact template if no specific template is provided. " + + "In contrast to CS01, we require a artifactName also for the implementationArtifact to be able to properly referencing it.") + String artifactNameStr, + + @FormParam("artifactTemplate") + @RestDocParam(description = "QName of the artifact Template - used by Winery Backend instead of artifactTemplateName + artifactTemplateNS") + String artifactTemplate, + + @FormParam("artifactTemplateName") + @RestDocParam(description = "if provided and autoCreateArtifactTemplate, a template of this id localname and artifactTemplateNS generated. " + + "Winery always sends this string if auto creation is desired.") + String artifactTemplateName, + + @FormParam("artifactTemplateNS") + String artifactTemplateNS, + + @FormParam("autoCreateArtifactTemplate") + @RestDocParam(description = "if empty, no, or false, no artifact template is created. " + + "An artifact type has to be given in that case. " + + "Furthermore, an artifact template name + artifact template namespace has to be provided. " + + "Otherwise, the artifactNameStr is used as name for the artifact and a <em>new</em> artifact template is created having {@code <artifactNameString>Template} as name") + String autoCreateArtifactTemplate, + + @FormParam("artifactType") + @RestDocParam(description = "QName of the type, format: {namespace}localname. " + + "Optional if artifactTemplateName + artifactTempalteNS is provided") + String artifactTypeStr, + + @FormParam("artifactSpecificContent") + @RestDocParam(description = "<em>XML</em> snippet that should be put inside the artifact XML in the TOSCA serialization. " + + "This feature will be removed soon. " + + "TODO: This only works if there is a single child element expected and not several elements. " + + "Future versions of the Winery will support arbitrary content there.") + String artifactSpecificContent, + + @FormParam("interfaceName") + String interfaceNameStr, + + @FormParam("operationName") + String operationNameStr, + + @FormParam("autoGenerateIA") + @RestDocParam(description = "If not empty, the IA generator will be called") + String autoGenerateIA, + + @FormParam("javapackage") + @RestDocParam(description = "The Java package to use for IA generation") + String javapackage, + + @Context UriInfo uriInfo + ){ + // we assume that the parent ComponentInstance container exists + + // @formatter:on + + if (StringUtils.isEmpty(artifactNameStr)) { + return Response.status(Status.BAD_REQUEST).entity("Empty artifactName").build(); + } + if (StringUtils.isEmpty(artifactTypeStr)) { + if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) { + if (StringUtils.isEmpty(artifactTemplate)) { + return Response.status(Status.BAD_REQUEST).entity("No artifact type given and no template given. Cannot guess artifact type").build(); + } + } + } + + if (!StringUtils.isEmpty(autoGenerateIA)) { + if (StringUtils.isEmpty(javapackage)) { + return Response.status(Status.BAD_REQUEST).entity("no java package name supplied for IA auto generation.").build(); + } + if (StringUtils.isEmpty(interfaceNameStr)) { + return Response.status(Status.BAD_REQUEST).entity("no interface name supplied for IA auto generation.").build(); + } + } + + // convert second calling form to first calling form + if (!StringUtils.isEmpty(artifactTemplate)) { + QName qname = QName.valueOf(artifactTemplate); + artifactTemplateName = qname.getLocalPart(); + artifactTemplateNS = qname.getNamespaceURI(); + } + + Document doc = null; + + // check artifact specific content for validity + // if invalid, abort and do not create anything + if (!StringUtils.isEmpty(artifactSpecificContent)) { + try { + DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + InputSource is = new InputSource(); + StringReader sr = new StringReader(artifactSpecificContent); + is.setCharacterStream(sr); + doc = db.parse(is); + } catch (Exception e) { + // FIXME: currently we allow a single element only. However, the content should be internally wrapped by an (arbitrary) XML element as the content will be nested in the artifact element, too + GenericArtifactsResource.logger.debug("Invalid content", e); + return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); + } + } + + // determine artifactTemplate and artifactType + + ArtifactTypeId artifactTypeId; + ArtifactTemplateId artifactTemplateId = null; + ArtifactTemplateResource artifactTemplateResource = null; + + boolean doAutoCreateArtifactTemplate = !(StringUtils.isEmpty(autoCreateArtifactTemplate) || autoCreateArtifactTemplate.equalsIgnoreCase("no") || autoCreateArtifactTemplate.equalsIgnoreCase("false")); + if (!doAutoCreateArtifactTemplate) { + // no auto creation + if (!StringUtils.isEmpty(artifactTemplateName) && !StringUtils.isEmpty(artifactTemplateNS)) { + QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName); + artifactTemplateId = BackendUtils.getTOSCAcomponentId(ArtifactTemplateId.class, artifactTemplateQName); + } + if (StringUtils.isEmpty(artifactTypeStr)) { + // derive the type from the artifact template + if (artifactTemplateId == null) { + return Response.status(Status.NOT_ACCEPTABLE).entity("No artifactTemplate and no artifactType provided. Deriving the artifactType is not possible.").build(); + } + artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId); + artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTemplateResource.getType()); + } else { + // artifactTypeStr is directly given, use that + artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr); + } + } else { + // do the artifact template auto creation magic + + if (StringUtils.isEmpty(artifactTypeStr)) { + return Response.status(Status.BAD_REQUEST).entity("Artifact template auto creation requested, but no artifact type supplied.").build(); + } + + // we assume that the type points to a valid artifact type + artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr); + + if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) { + // no explicit name provided + // we use the artifactNameStr as prefix for the + // artifact template name + + // we create a new artifact template in the namespace of the parent + // element + Namespace namespace = this.resWithNamespace.getNamespace(); + + artifactTemplateId = new ArtifactTemplateId(namespace, new XMLId(artifactNameStr + "artifactTemplate", false)); + } else { + QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName); + artifactTemplateId = new ArtifactTemplateId(artifactTemplateQName); + } + ResourceCreationResult creationResult = BackendUtils.create(artifactTemplateId); + if (!creationResult.isSuccess()) { + // something went wrong. skip + return creationResult.getResponse(); + } + + // associate the type to the created artifact template + artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId); + // set the type. The resource is automatically persisted inside + artifactTemplateResource.setType(artifactTypeStr); + } + + // variable artifactTypeId is set + // variable artifactTemplateId is not null if artifactTemplate has been generated + + // we have to generate the DA/IA resource now + // Doing it here instead of doing it at the subclasses is dirty on the + // one hand, but quicker to implement on the other hand + + // Create the artifact itself + + ArtifactT resultingArtifact; + + if (this instanceof ImplementationArtifactsResource) { + ImplementationArtifact a = new ImplementationArtifact(); + // Winery internal id is the name of the artifact: + // store the name + a.setName(artifactNameStr); + a.setInterfaceName(interfaceNameStr); + a.setOperationName(operationNameStr); + assert (artifactTypeId != null); + a.setArtifactType(artifactTypeId.getQName()); + if (artifactTemplateId != null) { + a.setArtifactRef(artifactTemplateId.getQName()); + } + if (doc != null) { + // the content has been checked for validity at the beginning of the method. + // If this point in the code is reached, the XML has been parsed into doc + // just copy over the dom node. Hopefully, that works... + a.getAny().add(doc.getDocumentElement()); + } + + this.list.add((ArtifactT) a); + resultingArtifact = (ArtifactT) a; + } else { + // for comments see other branch + + TDeploymentArtifact a = new TDeploymentArtifact(); + a.setName(artifactNameStr); + assert (artifactTypeId != null); + a.setArtifactType(artifactTypeId.getQName()); + if (artifactTemplateId != null) { + a.setArtifactRef(artifactTemplateId.getQName()); + } + if (doc != null) { + a.getAny().add(doc.getDocumentElement()); + } + + this.list.add((ArtifactT) a); + resultingArtifact = (ArtifactT) a; + } + + Response persistResponse = BackendUtils.persist(super.res); + // TODO: check for error and in case one found return that + + if (StringUtils.isEmpty(autoGenerateIA)) { + // no IA generation + // we include an XML for the data table + + String implOrDeplArtifactXML = Utils.getXMLAsString(resultingArtifact); + + return Response.created(Utils.createURI(Util.URLencode(artifactNameStr))).entity(implOrDeplArtifactXML).build(); + } else { + // after everything was created, we fire up the artifact generation + return this.generateImplementationArtifact(interfaceNameStr, javapackage, uriInfo, artifactTemplateId, artifactTemplateResource); + } + } + + /** + * Generates a unique and valid name to be used for the generated maven + * project name, java project name, class name, port type name. + */ + private String generateName(NodeTypeId nodeTypeId, String interfaceName) { + String name = Util.namespaceToJavaPackage(nodeTypeId.getNamespace().getDecoded()); + name += Util.FORBIDDEN_CHARACTER_REPLACEMENT; + + // Winery already ensures that this is a valid NCName + // getName() returns the id of the nodeType: A nodeType carries the "id" attribute only (and no name attribute) + name += nodeTypeId.getXmlId().getDecoded(); + + // Two separators to distinguish node type and interface part + name += Util.FORBIDDEN_CHARACTER_REPLACEMENT; + name += Util.FORBIDDEN_CHARACTER_REPLACEMENT; + name += Util.namespaceToJavaPackage(interfaceName); + + // In addition we must replace '.', because Java class names must not + // contain dots, but for Winery they are fine. + return name.replace(".", Util.FORBIDDEN_CHARACTER_REPLACEMENT); + } + + /** + * Generates the implementation artifact using the implementation artifact + * generator. Also sets the proeprties according to the requirements of + * OpenTOSCA. + * + * @param interfaceNameStr + * @param javapackage + * @param uriInfo + * @param artifactTemplateId + * @param artifactTemplateResource the resource associated with the + * artifactTempalteId. If null, the object is created in this + * method + * + * @return {@inheritDoc} + */ + private Response generateImplementationArtifact(String interfaceNameStr, String javapackage, UriInfo uriInfo, ArtifactTemplateId artifactTemplateId, ArtifactTemplateResource artifactTemplateResource) { + TInterface iface; + + assert (this instanceof ImplementationArtifactsResource); + IHasTypeReference typeRes = (EntityTypeImplementationResource) this.res; + QName type = typeRes.getType(); + TOSCAComponentId typeId; + TNodeType nodeType = null; + if (typeRes instanceof NodeTypeImplementationResource) { + // TODO: refactor: This is more a model/repo utilities thing than something which should happen here... + + typeId = new NodeTypeId(type); + NodeTypeResource ntRes = (NodeTypeResource) AbstractComponentsResource.getComponentInstaceResource(typeId); + + // required for IA Generation + nodeType = ntRes.getNodeType(); + + List<TInterface> interfaces = nodeType.getInterfaces().getInterface(); + Iterator<TInterface> it = interfaces.iterator(); + do { + iface = it.next(); + if (iface.getName().equals(interfaceNameStr)) { + break; + } + } while (it.hasNext()); + // iface now contains the right interface + } else { + assert (typeRes instanceof RelationshipTypeImplementationResource); + return Response.serverError().entity("IA creation for relation ship type implementations not yet possible").build(); + } + + Path workingDir; + try { + workingDir = Files.createTempDirectory("winery"); + } catch (IOException e2) { + GenericArtifactsResource.logger.debug("Could not create temporary directory", e2); + return Response.serverError().entity("Could not create temporary directory").build(); + } + + URI artifactTemplateFilesUri = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(artifactTemplateId)).resolve("files/"); + URL artifactTemplateFilesUrl; + try { + artifactTemplateFilesUrl = artifactTemplateFilesUri.toURL(); + } catch (MalformedURLException e2) { + GenericArtifactsResource.logger.debug("Could not convert URI to URL", e2); + return Response.serverError().entity("Could not convert URI to URL").build(); + } + + String name = this.generateName((NodeTypeId) typeId, interfaceNameStr); + Generator gen = new Generator(iface, javapackage, artifactTemplateFilesUrl, name, workingDir.toFile()); + File zipFile = gen.generateProject(); + if (zipFile == null) { + return Response.serverError().entity("IA generator failed").build(); + } + + // store it + // TODO: refactor: this is more a RepositoryUtils thing than a special thing here; see also importFile at CSARImporter + + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(artifactTemplateId); + RepositoryFileReference fref = new RepositoryFileReference(fileDir, zipFile.getName().toString()); + try (InputStream is = Files.newInputStream(zipFile.toPath()); + BufferedInputStream bis = new BufferedInputStream(is)) { + String mediaType = Utils.getMimeType(bis, zipFile.getName()); + // TODO: do the catch thing as in CSARImporter + + Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType)); + } catch (IOException e1) { + throw new IllegalStateException("Could not import generated files", e1); + } + + // cleanup dir + try { + FileUtils.forceDelete(workingDir); + } catch (IOException e) { + GenericArtifactsResource.logger.debug("Could not delete working directory", e); + } + + // store the properties in the artifact template + if (artifactTemplateResource == null) { + artifactTemplateResource = (ArtifactTemplateResource) AbstractComponentsResource.getComponentInstaceResource(artifactTemplateId); + } + this.storeProperties(artifactTemplateResource, typeId, name); + + URI url = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(fref)); + return Response.created(url).build(); + } + + + private final String NS_OPENTOSCA_WAR_TYPE = "http://www.uni-stuttgart.de/opentosca"; + + + private void storeProperties(ArtifactTemplateResource artifactTemplateResource, TOSCAComponentId typeId, String name) { + // We generate the properties by hand instead of using JAX-B as using JAX-B causes issues at org.eclipse.winery.common.ModelUtilities.getPropertiesKV(TEntityTemplate): + // getAny() does not always return "w3c.dom.element" anymore + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + try { + builder = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + GenericArtifactsResource.logger.error(e.getMessage(), e); + return; + } + Document doc = builder.newDocument(); + Element root = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "WSProperties"); + doc.appendChild(root); + + Element element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "ServiceEndpoint"); + Text text = doc.createTextNode("/services/" + name + "Port"); + element.appendChild(text); + root.appendChild(element); + + element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "PortType"); + text = doc.createTextNode("{" + typeId.getNamespace().getDecoded() + "}" + name); + element.appendChild(text); + root.appendChild(element); + + element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "InvocationType"); + text = doc.createTextNode("SOAP/HTTP"); + element.appendChild(text); + root.appendChild(element); + + Properties properties = new Properties(); + properties.setAny(root); + PropertiesResource propertiesResource = artifactTemplateResource.getPropertiesResource(); + propertiesResource.setProperties(properties); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/artifacts/artifacts.jsp", this); + } + + /** + * Required for artifacts.jsp + * + * @return list of known artifact types. + */ + public List<QName> getAllArtifactTypes() { + SortedSet<ArtifactTypeId> allArtifactTypes = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class); + List<QName> res = new ArrayList<QName>(allArtifactTypes.size()); + for (ArtifactTypeId id : allArtifactTypes) { + res.add(id.getQName()); + } + return res; + } + + /** + * Required for artifacts.jsp + * + * @return list of all contained artifacts. + */ + public abstract Collection<ArtifactResource> getAllArtifactResources(); + + /** + * Required by artifact.jsp to decide whether to display + * "Deployment Artifact" or "Implementation Artifact" + */ + public boolean getIsDeploymentArtifacts() { + boolean res = (this instanceof DeploymentArtifactsResource); + return res; + } + + /** + * required by artifacts.jsp + */ + public String getNamespace() { + return this.resWithNamespace.getNamespace().getDecoded(); + } + + /** + * For saving resources, an AbstractComponentInstanceResource is required. + * DAs may be attached to a node template, which is not an + * AbstractComponentInstanceResource, but its grandparent resource + * ServiceTemplate is + * + * @param res the resource to determine the the + * AbstractComponentInstanceResource for + * @return the AbstractComponentInstanceResource where the given res is + * contained in + */ + public static AbstractComponentInstanceResource getAbstractComponentInstanceResource(INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) { + final AbstractComponentInstanceResource r; + if (res instanceof NodeTemplateResource) { + r = ((NodeTemplateResource) res).getServiceTemplateResource(); + } else { + // quick hack: the resource has to be an abstract component instance + r = (AbstractComponentInstanceResource) res; + } + return r; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java new file mode 100644 index 0000000..bc5580c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.artifacts; + +import java.util.List; + +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; + +public class ImplementationArtifactResource extends GenericArtifactResource<ImplementationArtifact> { + + private ImplementationArtifact a; + + + /** + * Converts the given artifactId to an ImplementArtifact. + * + * <em>SIDE EFFECT</em> Adds it to the implementationArtifacts list if it + * does not yet exist. + */ + private static ImplementationArtifact getImplementationArtifact(String artifactId, List<ImplementationArtifact> implementationArtifacts) { + if (artifactId == null) { + throw new IllegalArgumentException("artifactId must not be null"); + } + if (implementationArtifacts == null) { + throw new IllegalArgumentException("implementationArtifacts must not be null"); + } + for (ImplementationArtifact ia : implementationArtifacts) { + // ia.getName() might be null as TOSCA COS01 does not forsee a name on the implementation artifact + // Therefore, we begin the test with "artifactId" + if (artifactId.equals(ia.getName())) { + return ia; + } + } + // IA does not exist in list + ImplementationArtifact ia = new ImplementationArtifact(); + ia.setName(artifactId); + implementationArtifacts.add(ia); + return ia; + } + + public ImplementationArtifactResource(String artifactId, List<ImplementationArtifact> implementationArtifacts, IPersistable res) { + this(ImplementationArtifactResource.getImplementationArtifact(artifactId, implementationArtifacts), implementationArtifacts, res); + } + + public ImplementationArtifactResource(IIdDetermination<ImplementationArtifact> idDetermination, ImplementationArtifact o, int idx, List<ImplementationArtifact> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + this.a = o; + } + + public ImplementationArtifactResource(ImplementationArtifact a, List<ImplementationArtifact> implementationArtifacts, IPersistable res) { + this(new IIdDetermination<ImplementationArtifact>() { + + @Override + public String getId(ImplementationArtifact e) { + return e.getName(); + } + }, a, implementationArtifacts.indexOf(a), implementationArtifacts, res); + } + + public ImplementationArtifact getImplementationArtifact() { + return this.a; + } + + @Override + public void setArtifactType(ArtifactTypeId artifactTypeId) { + this.getImplementationArtifact().setArtifactType(artifactTypeId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public void setArtifactTemplate(ArtifactTemplateId artifactTemplateId) { + this.getImplementationArtifact().setArtifactRef(artifactTemplateId.getQName()); + BackendUtils.persist(this.res); + } + + @Override + public ImplementationArtifact getA() { + return this.a; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java new file mode 100644 index 0000000..e1d7aa6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.artifacts; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact; +import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource; +import org.eclipse.winery.repository.resources.interfaces.InterfaceResource; + +/** + * ImplementationArtifact instead of TImplementationArtifact has to be used + * because of difference in the XSD at tImplementationArtifacts vs. + * tDeploymentArtifacts + */ +public class ImplementationArtifactsResource extends GenericArtifactsResource<ImplementationArtifactResource, ImplementationArtifact> { + + private List<ImplementationArtifact> implementationArtifacts; + + + public ImplementationArtifactsResource(List<ImplementationArtifact> implementationArtifact, INodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) { + super(ImplementationArtifactResource.class, ImplementationArtifact.class, implementationArtifact, res); + this.implementationArtifacts = implementationArtifact; + } + + /** + * @return a cast to TNodeTypeImplementationResource of the parent of this + * resource. + */ + protected NodeTypeImplementationResource getNTI() { + return (NodeTypeImplementationResource) this.res; + } + + /** + * @return a cast to TNodeTypeImplementationResource of the parent of this + * resource. + */ + protected RelationshipTypeImplementationResource getRTI() { + return (RelationshipTypeImplementationResource) this.res; + } + + @Override + public Collection<ImplementationArtifactResource> getAllArtifactResources() { + Collection<ImplementationArtifactResource> res = new ArrayList<ImplementationArtifactResource>(this.implementationArtifacts.size()); + for (ImplementationArtifact da : this.implementationArtifacts) { + ImplementationArtifactResource r = new ImplementationArtifactResource(da, this.implementationArtifacts, this.res); + res.add(r); + } + return res; + } + + /** required by artifacts.jsp **/ + public List<InterfaceResource> getInterfacesOfAssociatedType() { + boolean isNodeTypeImplementation = this.res instanceof NodeTypeImplementationResource; + QName type; + List<InterfaceResource> interfaces = new ArrayList<InterfaceResource>(); + if (isNodeTypeImplementation) { + type = this.getNTI().getType(); + NodeTypeResource typeResource = (NodeTypeResource) new NodeTypesResource().getComponentInstaceResource(type); + interfaces.addAll(typeResource.getInterfaces().getAllEntityResources()); + } else { + type = this.getRTI().getType(); + RelationshipTypeResource typeResource = (RelationshipTypeResource) new RelationshipTypesResource().getComponentInstaceResource(type); + interfaces.addAll(typeResource.getSourceInterfaces().getAllEntityResources()); + interfaces.addAll(typeResource.getTargetInterfaces().getAllEntityResources()); + } + return interfaces; + } + + @Override + public String getId(ImplementationArtifact entity) { + return entity.getName(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java new file mode 100644 index 0000000..6783948 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.documentation; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TDocumentation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class DocumentationResource extends EntityWithoutIdResource<TDocumentation> { + + public DocumentationResource(TDocumentation o, int idx, List<TDocumentation> list, IPersistable res) { + super(o, idx, list, res); + } + + @PUT + @Consumes(MediaType.TEXT_HTML) + @Produces(MediaType.TEXT_PLAIN) + public Response setValue(String documentation) { + this.o.getContent().clear(); + this.o.getContent().add(documentation); + this.list.set(this.idx, this.o); + return CollectionsHelper.persist(this.res, this.idDetermination, this.o); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java new file mode 100644 index 0000000..1466a57 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.documentation; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.model.tosca.TDocumentation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class DocumentationsResource extends EntityWithoutIdCollectionResource<DocumentationResource, TDocumentation> { + + private static final Logger logger = LoggerFactory.getLogger(DocumentationResource.class); + + + public DocumentationsResource(IPersistable res, List<TDocumentation> documentations) { + super(DocumentationResource.class, TDocumentation.class, documentations, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/documentation.jsp", this.list); + } + + /** + * Adds a new documentation + */ + @POST + @Consumes(MediaType.TEXT_HTML) + public Response addNewElement(String documentation) { + if (documentation == null) { + return Response.status(Status.BAD_REQUEST).entity("No content provided").build(); + } + TDocumentation doc = new TDocumentation(); + doc.getContent().add(documentation); + // TODO: check for duplicates as in instance states + this.list.add(doc); + return CollectionsHelper.persist(this.res, this, doc); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java new file mode 100644 index 0000000..e5025b1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates; + +import javax.ws.rs.DELETE; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; + +/** + * Interface ensuring that no methods are forgotten when implementing an + * {@link AbstractComponentInstanceResource}, which is also a template + */ +public interface IEntityTemplateResource<E extends TEntityTemplate> extends IHasTypeReference { + + @Path("properties/") + public PropertiesResource getPropertiesResource(); + + @DELETE + public Response onDelete(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java new file mode 100644 index 0000000..4341095 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; + +import com.sun.jersey.api.view.Viewable; + +public class PropertiesResource { + + private AbstractComponentInstanceResource res; + private TEntityTemplate template; + + + /** + * @param template the template to store the definitions at + * @param res the resource to save after modifications + */ + public PropertiesResource(TEntityTemplate template, AbstractComponentInstanceResource res) { + this.template = template; + this.res = res; + } + + /** + * Currently, properties can only be updated as a whole XML fragment + * + * Getting/setting a fragment of properties is not possible yet + */ + @PUT + @Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON}) + public Response setProperties(TEntityTemplate.Properties properties) { + this.getTemplate().setProperties(properties); + return BackendUtils.persist(this.res); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytemplates/properties.jsp", this); + } + + /** data for the JSP **/ + + public TEntityTemplate getTemplate() { + return this.template; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java new file mode 100644 index 0000000..ee9064b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates; + +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class TEntityTemplateResource<E extends TEntityTemplate> extends EntityWithIdResource<E> implements IEntityTemplateResource<E>, IHasTypeReference { + + /** + * This constructor is used for both entity templates nested in an component + * instance as well as for entity templates being component instances + * itself. + * + * As Java does not support multi-inheritance, we implemented a quick hack + * to re-use this class as inner implementation at templates extending + * AbstractComponentInstanceResourceDefinitionsBacked + */ + public TEntityTemplateResource(IIdDetermination<E> idDetermination, E o, int idx, List<E> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + // public String getId() { + // return this.template.getId(); + // } + // + // public void setId(String id) { + // // TODO: There is no check for uniqueness of the given id + // this.template.setId(id); + // } + + /** + * {@inheritDoc} + */ + @Override + public QName getType() { + return this.o.getType(); + } + + @Path("type") + @GET + public String getTypeAsQNameString() { + return this.getType().toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public Response setType(QName type) { + this.o.setType(type); + return BackendUtils.persist(this.res); + } + + /** + * {@inheritDoc} + */ + @Override + public Response setType(String typeStr) { + return this.setType(QName.valueOf(typeStr)); + } + + /** + * {@inheritDoc} + */ + @Override + public PropertiesResource getPropertiesResource() { + return new PropertiesResource(this.o, (AbstractComponentInstanceResource) this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java new file mode 100644 index 0000000..256e376 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +/** + * This resource models the list of TEntityTemplates + */ +public abstract class TEntityTemplatesResource<R extends EntityWithIdResource<T>, T extends TEntityTemplate> extends EntityWithIdCollectionResource<R, T> { + + public TEntityTemplatesResource(Class<R> entityResourceTClazz, Class<T> entityTClazz, List<T> list, IPersistable res) { + super(entityResourceTClazz, entityTClazz, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java new file mode 100644 index 0000000..f3ed0e9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.tosca.TArtifactReference; +import org.eclipse.winery.model.tosca.TArtifactTemplate; +import org.eclipse.winery.model.tosca.TArtifactTemplate.ArtifactReferences; +import org.eclipse.winery.model.tosca.TDeploymentArtifact; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifact; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceWithReferencesResource; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources.entitytemplates.IEntityTemplateResource; +import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.entitytypes.artifacttypes.ArtifactTypeResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +/** + * Models an Artifact Template with its artifact references + * + * The associated files (through tArtifactReference) are stored directly within + * this resource. The element <ArtifactReference> is generated during export + * only + * + * This class inherits from AbstractComponentInstanceResourceDefinitionsBacked + * and not from TEntityTemplateResource<TArtifactTemplate>, because + * ArtifactTemplates are directly available under TDefinitions and we need the + * generic resource handling + */ + +public class ArtifactTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IEntityTemplateResource<TArtifactTemplate>, IHasName { + + private final TEntityTemplateResource<TArtifactTemplate> entityTemplateResource; + + + public ArtifactTemplateResource(ArtifactTemplateId id) { + super(id); + // we provide the minimum requirements for the resource + this.entityTemplateResource = new TEntityTemplateResource<TArtifactTemplate>(null, this.getTArtifactTemplate(), 0, null, this); + } + + /** + * @return null if no artifact type resource is defined + */ + public ArtifactTypeResource getAritfactTypeResource() { + ArtifactTypeId atId = new ArtifactTypeId(this.getTArtifactTemplate().getType()); + return new ArtifactTypeResource(atId); + } + + private TArtifactTemplate getTArtifactTemplate() { + return (TArtifactTemplate) this.element; + } + + @Override + public String getName() { + String name = this.getTArtifactTemplate().getName(); + if (name == null) { + return this.getTArtifactTemplate().getId(); + } else { + return name; + } + } + + @Override + public Response setName(String name) { + this.getTArtifactTemplate().setName(name); + return BackendUtils.persist(this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TArtifactTemplate(); + } + + @Override + protected void copyIdToFields() { + this.getTArtifactTemplate().setId(this.getId().getXmlId().getDecoded()); + // Namespace cannot be set as the namespace is contained in TDefinitions only + } + + /** + * {@inheritDoc} + */ + @Override + public void synchronizeReferences() { + TArtifactTemplate template = this.getTArtifactTemplate(); + + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId((ArtifactTemplateId) this.id); + SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(fileDir); + if (files.isEmpty()) { + // clear artifact references + template.setArtifactReferences(null); + } else { + ArtifactReferences artifactReferences = new ArtifactReferences(); + template.setArtifactReferences(artifactReferences); + List<TArtifactReference> artRefList = artifactReferences.getArtifactReference(); + for (RepositoryFileReference ref : files) { + // determine path + // path relative from the root of the CSAR is ok (COS01, line 2663) + String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref)); + + // put path into data structure + // we do not use Inlude/Exclude as we directly reference a concrete file + TArtifactReference artRef = new TArtifactReference(); + artRef.setReference(path); + artRefList.add(artRef); + } + } + } + + @Path("files/") + public FilesResource getFilesResource() { + ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId((ArtifactTemplateId) this.id); + return new FilesResource(fileDir); + } + + /*********************************************************************** + * "inheritance" from TEntityTemplateResource<TArtifactTemplate> * + * + * Offering all methods of TEntityTemplateResource<TArtifactTemplate> and + * forwarding it to our private instance of it + */ + + @Override + public QName getType() { + return this.entityTemplateResource.getType(); + } + + @Override + public Response setType(QName type) { + this.entityTemplateResource.setType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + this.entityTemplateResource.setType(typeStr); + return BackendUtils.persist(this); + } + + @Override + public PropertiesResource getPropertiesResource() { + return new PropertiesResource(this.getTArtifactTemplate(), this); + } + + int getReferenceCount() { + // We do not use a database, therefore, we have to go through all possibilities pointing to the artifact template + // DAs and IAs point to an artifact template + // DAs are contained in Node Type Implementations and Node Templates + // IAs are contained in Node Type Implementations and Relationship Type Implementations + + int count = 0; + + Collection<TDeploymentArtifact> allDAs = new HashSet<>(); + Collection<TImplementationArtifact> allIAs = new HashSet<>(); + + // handle Node Type Implementation, which contains DAs and IAs + SortedSet<NodeTypeImplementationId> nodeTypeImplementations = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeImplementationId.class); + for (NodeTypeImplementationId ntiId : nodeTypeImplementations) { + NodeTypeImplementationResource ntiRes = (NodeTypeImplementationResource) AbstractComponentsResource.getComponentInstaceResource(ntiId); + TDeploymentArtifacts deploymentArtifacts = ntiRes.getNTI().getDeploymentArtifacts(); + if (deploymentArtifacts != null) { + allDAs.addAll(deploymentArtifacts.getDeploymentArtifact()); + } + TImplementationArtifacts implementationArtifacts = ntiRes.getNTI().getImplementationArtifacts(); + if (implementationArtifacts != null) { + allIAs.addAll(implementationArtifacts.getImplementationArtifact()); + } + } + + // check all Relationshiptype Implementations for IAs + SortedSet<RelationshipTypeImplementationId> relationshipTypeImplementations = Repository.INSTANCE.getAllTOSCAComponentIds(RelationshipTypeImplementationId.class); + for (RelationshipTypeImplementationId rtiId : relationshipTypeImplementations) { + RelationshipTypeImplementationResource rtiRes = (RelationshipTypeImplementationResource) AbstractComponentsResource.getComponentInstaceResource(rtiId); + TImplementationArtifacts implementationArtifacts = rtiRes.getRTI().getImplementationArtifacts(); + if (implementationArtifacts != null) { + allIAs.addAll(implementationArtifacts.getImplementationArtifact()); + } + } + + // check all node templates for DAs + SortedSet<ServiceTemplateId> serviceTemplates = Repository.INSTANCE.getAllTOSCAComponentIds(ServiceTemplateId.class); + for (ServiceTemplateId sid : serviceTemplates) { + ServiceTemplateResource serviceTemplateRes = (ServiceTemplateResource) AbstractComponentsResource.getComponentInstaceResource(sid); + TTopologyTemplate topologyTemplate = serviceTemplateRes.getServiceTemplate().getTopologyTemplate(); + if (topologyTemplate != null) { + List<TEntityTemplate> nodeTemplateOrRelationshipTemplate = topologyTemplate.getNodeTemplateOrRelationshipTemplate(); + for (TEntityTemplate template : nodeTemplateOrRelationshipTemplate) { + if (template instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) template; + TDeploymentArtifacts deploymentArtifacts = nodeTemplate.getDeploymentArtifacts(); + if (deploymentArtifacts != null) { + allDAs.addAll(deploymentArtifacts.getDeploymentArtifact()); + } + } + } + } + } + + // now we have all DAs and IAs + + QName ourQName = this.getQName(); + + // check DAs for artifact templates + for (TDeploymentArtifact da : allDAs) { + QName artifactRef = da.getArtifactRef(); + if (ourQName.equals(artifactRef)) { + count++; + } + } + + // check IAs for artifact templates + for (TImplementationArtifact ia : allIAs) { + QName artifactRef = ia.getArtifactRef(); + if (ourQName.equals(artifactRef)) { + count++; + } + } + + return count; + } + + /** + * Query parameter {@code type}:<br /> + * Returns the type of the artifact template + * + * Query parameter {@code referenceCount}:<br /> + * Determines the number of elements known by the repository which point to + * this resource. This method probably can be moved up the type hierarchy. + * Currently, it is only required here by the topology modeler. + * + * @return the type of the artifact template OR the number of references + * pointing to this resource + */ + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response getRefereneCount(@QueryParam("referenceCount") String referenceCount, @QueryParam("type") String type) { + if (referenceCount != null) { + String res = Integer.toString(this.getReferenceCount()); + return Response.ok().entity(res).build(); + } else if (type != null) { + String res = this.getType().toString(); + return Response.ok().entity(res).build(); + } else { + // we enforce the query parameter to be extensible to other queries + return Response.status(Status.BAD_REQUEST).entity("You have to pass the query parameter referenceCount or type").build(); + } + + } + + /* not yet implemented */ + /* + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getReferenes(@QueryParam("references") String references) { + if (references== null) { + // we enforce the query parameter to be extensible to other queries + return Response.status(Status.BAD_REQUEST).entity("You have to pass the query parameter references").build(); + } + + String res = Integer.toString(this.getReferenceCount()); + return Response.ok().entity(res).build(); + } + */ + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java new file mode 100644 index 0000000..e02a668 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +/** + * This class does NOT inherit from TEntityTemplatesResource<ArtifactTemplate> + * as these templates are directly nested in a TDefinitionsElement + */ +public class ArtifactTemplatesResource extends AbstractComponentsWithTypeReferenceResource<ArtifactTemplateResource> { +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java new file mode 100644 index 0000000..0a910fe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.FileMeta; +import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class FilesResource { + + private static final Logger logger = LoggerFactory.getLogger(FilesResource.class); + private final ArtifactTemplateDirectoryId fileDir; + + + public FilesResource(ArtifactTemplateDirectoryId fileDir) { + this.fileDir = fileDir; + } + + private String getData4jqueryFileUpload(List<FileMeta> metas) { + String data4jqueryFileUpload = Utils.Object2JSON(metas); + data4jqueryFileUpload = "{\"files\":" + data4jqueryFileUpload + "}"; + return data4jqueryFileUpload; + } + + /** + * Handles the upload of a <em>single</em> file. Adds the given file to the + * current artifact template. + * + * If the file already exists, is it <em>overridden</em> + * + * @return JSON with data required by JQuery-File-Upload (see + * https://github.com/blueimp/jQuery-File-Upload/wiki/Setup) + */ + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response onPost(@FormDataParam("files[]") InputStream uploadedInputStream, @FormDataParam("files[]") FormDataContentDisposition fileDetail, @FormDataParam("files[]") FormDataBodyPart body, @Context UriInfo uriInfo) { + // existence check not required as instantiation of the resource ensures that the object only exists if the resource exists + FilesResource.logger.debug("Beginning with file upload"); + + String fileName = fileDetail.getFileName(); + if (StringUtils.isEmpty(fileName)) { + return Response.status(Status.BAD_REQUEST).build(); + } + RepositoryFileReference ref = this.fileName2fileRef(fileName, false); + + // TODO: instead of fixing the media type, we could overwrite the browser's mediatype by using some user configuration + BufferedInputStream bis = new BufferedInputStream(uploadedInputStream); + MediaType mediaType = Utils.getFixedMimeType(bis, fileName, body.getMediaType()); + + Response response = BackendUtils.putContentToFile(ref, bis, mediaType); + if (response.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) { + return response; + } + + // create FileMeta object + String URL = Utils.getAbsoluteURL(this.fileDir) + Util.URLencode(fileName); + String thumbnailURL = uriInfo.getBaseUriBuilder().path(Constants.PATH_MIMETYPEIMAGES).path(FilenameUtils.getExtension(fileName) + Constants.SUFFIX_MIMETYPEIMAGES).build().toString(); + long size; + try { + size = Repository.INSTANCE.getSize(ref); + } catch (IOException e) { + FilesResource.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + FileMeta fileMeta = new FileMeta(fileName, size, URL, thumbnailURL); + + List<FileMeta> metas = new ArrayList<FileMeta>(); + metas.add(fileMeta); + return Response.created(Utils.createURI(URL)).entity(this.getData4jqueryFileUpload(metas)).build(); + } + + /** + * Returns a list of file meta object + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getJSON() { + return this.getData4jqueryFileUpload(this.getAllFileMetas()); + } + + private List<FileMeta> getAllFileMetas() { + List<FileMeta> res = new ArrayList<FileMeta>(); + SortedSet<RepositoryFileReference> fileRefs = Repository.INSTANCE.getContainedFiles(this.fileDir); + for (RepositoryFileReference ref : fileRefs) { + res.add(new FileMeta(ref)); + } + return res; + } + + private RepositoryFileReference fileName2fileRef(String fileName, boolean encoded) { + if (encoded) { + fileName = Util.URLdecode(fileName); + } + RepositoryFileReference ref = new RepositoryFileReference(this.fileDir, fileName); + return ref; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytemplates/artifacttemplates/files.jsp"); + } + + @GET + @Path("/{fileName}") + public Response getFile(@PathParam("fileName") String fileName, @HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = this.fileName2fileRef(fileName, true); + return BackendUtils.returnRepoPath(ref, modified); + } + + @DELETE + @Path("/{fileName}") + public Response deleteFile(@PathParam("fileName") String fileName) { + RepositoryFileReference ref = this.fileName2fileRef(fileName, true); + return BackendUtils.delete(ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java new file mode 100644 index 0000000..4375378 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * The sub packages of this package contains all resources, which are derived + * from tEntityTemplate + * + * EntityTemplates get their namespaces from the surrounding + * Definitions-element. <br /> + * Nevertheless, they are stored using the same filesystem structure as + * EntityTypes + * + * {@link org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.RelationshipTemplateResource} + * and + * {@link org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource} + * are stored in the topology package + */ +package org.eclipse.winery.repository.resources.entitytemplates; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java new file mode 100644 index 0000000..e69a282 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates.policytemplates; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TPolicyTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources.entitytemplates.IEntityTemplateResource; +import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class PolicyTemplateResource extends AbstractComponentInstanceResource implements IEntityTemplateResource<TPolicyTemplate>, IHasName { + + private static final Logger logger = LoggerFactory.getLogger(PolicyTemplateResource.class); + + + /** + * Constructor has to be public because of test cases + */ + public PolicyTemplateResource(PolicyTemplateId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TPolicyTemplate getPolicyTemplate() { + return (TPolicyTemplate) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TPolicyTemplate(); + } + + @Override + public QName getType() { + return this.getPolicyTemplate().getType(); + } + + @Override + public Response setType(QName type) { + this.getPolicyTemplate().setType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + this.getPolicyTemplate().setType(QName.valueOf(typeStr)); + return BackendUtils.persist(this); + } + + @Override + public PropertiesResource getPropertiesResource() { + return new PropertiesResource(this.getPolicyTemplate(), this); + } + + @Override + protected void copyIdToFields() { + this.getPolicyTemplate().setId(this.getId().getXmlId().getDecoded()); + } + + @Override + public String getName() { + String name = this.getPolicyTemplate().getName(); + if (name == null) { + return this.getPolicyTemplate().getId(); + } else { + return name; + } + } + + @Override + public Response setName(String name) { + this.getPolicyTemplate().setName(name); + return BackendUtils.persist(this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java new file mode 100644 index 0000000..685ab66 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates.policytemplates; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +/** + * Manages all policy types in all available namespaces <br /> + * The actual implementation is done in the + * AbstractComponentsWithTypeReferenceResource + */ +public class PolicyTemplatesResource extends AbstractComponentsWithTypeReferenceResource<PolicyTemplateResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java new file mode 100644 index 0000000..8b48e74 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypeimplementations; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal; +import org.eclipse.winery.repository.resources.IHasTypeReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class EntityTypeImplementationResource extends AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal implements IHasTypeReference { + + private static final Logger logger = LoggerFactory.getLogger(EntityTypeImplementationResource.class); + + + protected EntityTypeImplementationResource(TOSCAComponentId id) { + super(id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java new file mode 100644 index 0000000..95b95d2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations; + +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.model.tosca.TDeploymentArtifacts; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TNodeTypeImplementation; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource; +import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.artifacts.DeploymentArtifactsResource; +import org.eclipse.winery.repository.resources.artifacts.ImplementationArtifactsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource; + +public class NodeTypeImplementationResource extends EntityTypeImplementationResource implements INodeTemplateResourceOrNodeTypeImplementationResource, INodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + + public NodeTypeImplementationResource(NodeTypeImplementationId id) { + super(id); + } + + /** + * public because of exporter + */ + public TNodeTypeImplementation getNTI() { + return (TNodeTypeImplementation) this.getElement(); + } + + /** + * Even if both node type implementations and relationship type + * implementations have implementation artifacts, there is no common + * supertype. To avoid endless casts, we just implement the method here + * + * @return + */ + @Path("implementationartifacts/") + public ImplementationArtifactsResource getImplementationArtifacts() { + TImplementationArtifacts implementationArtifacts; + implementationArtifacts = this.getNTI().getImplementationArtifacts(); + if (implementationArtifacts == null) { + implementationArtifacts = new TImplementationArtifacts(); + this.getNTI().setImplementationArtifacts(implementationArtifacts); + } + return new ImplementationArtifactsResource(implementationArtifacts.getImplementationArtifact(), this); + } + + /** + * Only NodeTypes have deployment artifacts, not RelationshipType. + * Therefore, this method is declared in + * {@link NodeTypeImplementationResource} and not in + * {@link EntityTypeImplementationResource} + */ + @Path("deploymentartifacts/") + public DeploymentArtifactsResource getDeploymentArtifacts() { + TDeploymentArtifacts deploymentArtifacts; + deploymentArtifacts = this.getNTI().getDeploymentArtifacts(); + if (deploymentArtifacts == null) { + deploymentArtifacts = new TDeploymentArtifacts(); + this.getNTI().setDeploymentArtifacts(deploymentArtifacts); + } + return new DeploymentArtifactsResource(deploymentArtifacts.getDeploymentArtifact(), this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TNodeTypeImplementation(); + } + + @Override + protected void copyIdToFields() { + this.getNTI().setTargetNamespace(this.getId().getNamespace().getDecoded()); + this.getNTI().setName(this.getId().getXmlId().getDecoded()); + } + + @Override + public QName getType() { + return this.getNTI().getNodeType(); + } + + @Override + public Response setType(QName type) { + this.getNTI().setNodeType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + QName type = QName.valueOf(typeStr); + return this.setType(type); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java new file mode 100644 index 0000000..b9c0836 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +public class NodeTypeImplementationsResource extends AbstractComponentsWithTypeReferenceResource<NodeTypeImplementationResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java new file mode 100644 index 0000000..af1c346 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * The sub packages of this package contains all resources, which are + * implementations of a type. <br /> + * The specification does NOT introduce tEntityTypeImplementation, but we + * implement as if that had been happened. + */ +package org.eclipse.winery.repository.resources.entitytypeimplementations; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java new file mode 100644 index 0000000..521758a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations; + +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImplementationArtifacts; +import org.eclipse.winery.model.tosca.TRelationshipTypeImplementation; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource; +import org.eclipse.winery.repository.resources.artifacts.ImplementationArtifactsResource; +import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource; + +public class RelationshipTypeImplementationResource extends EntityTypeImplementationResource implements INodeTypeImplementationResourceOrRelationshipTypeImplementationResource { + + public RelationshipTypeImplementationResource(RelationshipTypeImplementationId id) { + super(id); + } + + public TRelationshipTypeImplementation getRTI() { + return (TRelationshipTypeImplementation) this.getElement(); + } + + /** + * Even if both node type implementations and relationship type + * implementations have implementation artifacts, there is no common + * supertype. To avoid endless casts, we just implement the method here + */ + @Path("implementationartifacts/") + public ImplementationArtifactsResource getImplementationArtifacts() { + TImplementationArtifacts implementationArtifacts; + implementationArtifacts = this.getRTI().getImplementationArtifacts(); + if (implementationArtifacts == null) { + implementationArtifacts = new TImplementationArtifacts(); + this.getRTI().setImplementationArtifacts(implementationArtifacts); + } + return new ImplementationArtifactsResource(implementationArtifacts.getImplementationArtifact(), this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TRelationshipTypeImplementation(); + } + + @Override + protected void copyIdToFields() { + this.getRTI().setTargetNamespace(this.getId().getNamespace().getDecoded()); + this.getRTI().setName(this.getId().getXmlId().getDecoded()); + } + + @Override + public QName getType() { + return this.getRTI().getRelationshipType(); + } + + @Override + public Response setType(QName type) { + this.getRTI().setRelationshipType(type); + return BackendUtils.persist(this); + } + + @Override + public Response setType(String typeStr) { + QName qname = QName.valueOf(typeStr); + return this.setType(qname); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java new file mode 100644 index 0000000..f503a6f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations; + +import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource; + +public class RelationshipTypeImplementationsResource extends AbstractComponentsWithTypeReferenceResource<RelationshipTypeImplementationResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java new file mode 100644 index 0000000..5f4d06e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes; + +import java.util.Collection; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId; +import org.eclipse.winery.repository.resources.admin.NamespacesResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * specifies the methods required by implementations.jsp + */ +public abstract class ImplementationsOfOneType { + + private final TopologyGraphElementEntityTypeId typeId; + + + public ImplementationsOfOneType(TopologyGraphElementEntityTypeId typeId) { + this.typeId = typeId; + } + + public TopologyGraphElementEntityTypeId getTypeId() { + return this.typeId; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/implementations.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public abstract Response getJSON(); + + public Collection<Namespace> getNamespaceAutocompletionList() { + return NamespacesResource.getNamespaces(); + } + + /** + * @return a list of type implementations implementing the associated node + * type + */ + public abstract String getImplementationsTableData(); + + /** + * The string used as URL part + */ + public abstract String getType(); + + /** + * The string displayed to the user + */ + public abstract String getTypeStr(); + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java new file mode 100644 index 0000000..4eaea1c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates.InstanceState; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.backend.BackendUtils; + +import com.sun.jersey.api.view.Viewable; + +/** + * Resource for instance states <br /> + * Used by relationship types and node types + */ +public class InstanceStatesResource { + + private TopologyGraphElementEntityTypeResource typeResource; + private TTopologyElementInstanceStates instanceStates; + + + /** + * + * @param instanceStates the instanceStates to manage + * @param typeResource the type resource, where the instance states are + * managed. This reference is required to fire "persist()" in + * case of updates + */ + public InstanceStatesResource(TTopologyElementInstanceStates instanceStates, TopologyGraphElementEntityTypeResource typeResource) { + this.instanceStates = instanceStates; + this.typeResource = typeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/instancestates.jsp", this); + } + + public List<String> getInstanceStates() { + List<InstanceState> instanceStates = this.instanceStates.getInstanceState(); + ArrayList<String> states = new ArrayList<String>(instanceStates.size()); + for (InstanceState instanceState : instanceStates) { + states.add(instanceState.getState()); + } + return states; + } + + @DELETE + @Path("{instanceState}") + public Response deleteInstanceState(@PathParam("instanceState") String instanceStateToRemove) { + if (StringUtils.isEmpty(instanceStateToRemove)) { + return Response.status(Status.BAD_REQUEST).entity("null instance to remove").build(); + } + instanceStateToRemove = Util.URLdecode(instanceStateToRemove); + + // InstanceState does not override "equals()", therefore we have to manually remove it + + List<InstanceState> instanceStates = this.instanceStates.getInstanceState(); + Iterator<InstanceState> iterator = instanceStates.iterator(); + boolean found = false; + while (iterator.hasNext() && !found) { + if (iterator.next().getState().equals(instanceStateToRemove)) { + found = true; + } + } + + if (!found) { + return Response.status(Status.NOT_FOUND).build(); + } + + iterator.remove(); + + return BackendUtils.persist(this.typeResource); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addInstanceState(@FormParam("state") String state) { + if (StringUtils.isEmpty(state)) { + return Response.notAcceptable(null).build(); + } + + // InstanceState does not override "equals()", therefore we have to manually check for existance + + List<InstanceState> instanceStates = this.instanceStates.getInstanceState(); + Iterator<InstanceState> iterator = instanceStates.iterator(); + boolean found = false; + while (iterator.hasNext() && !found) { + if (iterator.next().getState().equals(state)) { + found = true; + } + } + + if (found) { + // no error, just return + return Response.noContent().build(); + } + + InstanceState instanceState = new InstanceState(); + instanceState.setState(state); + instanceStates.add(instanceState); + + return BackendUtils.persist(this.typeResource); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java new file mode 100644 index 0000000..6cebfe8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.repository.resources.EntityTypeResource; + +public abstract class TopologyGraphElementEntityTypeResource extends EntityTypeResource { + + protected TopologyGraphElementEntityTypeResource(TOSCAComponentId id) { + super(id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java new file mode 100644 index 0000000..232d4f9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.artifacttypes; + +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.model.tosca.TArtifactType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup; +import org.eclipse.winery.repository.resources.EntityTypeResource; + +public class ArtifactTypeResource extends EntityTypeResource { + + public ArtifactTypeResource(ArtifactTypeId id) { + super(id); + } + + + private final QName qnameFileExtension = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "fileExtension"); + + + /** + * @return the file extension associated with this artifact type. May be + * null + */ + @GET + @Path("/fileextension") + public String getAssociatedFileExtension() { + return this.getDefinitions().getOtherAttributes().get(this.qnameFileExtension); + } + + @PUT + @Path("/fileextension") + public Response setAssociatedFileExtension(String fileExtension) { + this.getDefinitions().getOtherAttributes().put(this.qnameFileExtension, fileExtension); + return BackendUtils.persist(this); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TArtifactType(); + } + + @Override + public SortedSet<Select2OptGroup> getListOfAllInstances() { + return this.getListOfAllInstances(ArtifactTemplateId.class); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java new file mode 100644 index 0000000..b52aa31 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.artifacttypes; + +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ids.definitions.ArtifactTypeId; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class ArtifactTypesResource extends AbstractComponentsResource<ArtifactTypeResource> { + + // This cannot be used as the INSTANCE is per startup of the whole + // application + // We could do some checking for the number of ArtifactTypeResources or + // timestamp, + // + // private final HashMap<String, ArtifactTypeResource> fileExtensionMapping + // = new ArtifactTypesResource().getFileExtensionMapping(); + + /** + * @return a mapping from file extension to artifact type resources + */ + // public HashMap<String, ArtifactTypeResource> getFileExtensionMapping() { + // HashMap<String, ArtifactTypeResource> res = new HashMap<String, + // ArtifactTypeResource>(); + // for (ArtifactTypeResource at : this.getArtifactTypeResources()) { + // if (at.getAssociatedFileExtension() != null) { + // res.put(at.getAssociatedFileExtension(), at); + // } + // } + // return res; + // } + + @GET + // should be "QName", but that MIME type is not available. XLink is too + // complicated for our setup + @Produces(MediaType.TEXT_PLAIN) + public Response getArtifactTypeQNameForExtension(@QueryParam("extension") String extension) { + if (extension == null) { + return Response.status(Status.NOT_ACCEPTABLE).build(); + } + ArtifactTypeResource artifactType = this.getArtifactTypeForExtension(extension); + Response res; + if (artifactType == null) { + res = Response.status(Status.NOT_FOUND).build(); + } else { + res = Response.ok().entity(artifactType.getId().getQName().toString()).build(); + } + return res; + } + + /** + * Returns the first matching ArtifactTypeResource for the given file + * extension. Returns null if no such ArtifactType can be found + * + * The case of the extension is ignored. + * + * This is more a DAO method + */ + public ArtifactTypeResource getArtifactTypeForExtension(String extension) { + SortedSet<ArtifactTypeId> allArtifactTypeIds = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class); + ArtifactTypeResource res = null; + for (ArtifactTypeId id : allArtifactTypeIds) { + ArtifactTypeResource r = new ArtifactTypeResource(id); + if (extension.equalsIgnoreCase(r.getAssociatedFileExtension())) { + res = r; + break; + } + } + return res; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java new file mode 100644 index 0000000..924efd4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.capabilitytypes; + +import org.eclipse.winery.model.tosca.TCapabilityType; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class CapabilityTypeResource extends EntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(CapabilityTypeResource.class); + + + /** + * Constructor has to be public because of test cases + */ + public CapabilityTypeResource(CapabilityTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + * + * @return the CapabilityType object this resource is representing + */ + public TCapabilityType getCapabilityType() { + return (TCapabilityType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TCapabilityType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java new file mode 100644 index 0000000..a34aac2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.capabilitytypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all capability types in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class CapabilityTypesResource extends AbstractComponentsResource<CapabilityTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java new file mode 100644 index 0000000..63d483d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.entitytypes.ImplementationsOfOneType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; + +public class ImplementationsOfOneNodeTypeResource extends ImplementationsOfOneType { + + private static final Logger logger = LoggerFactory.getLogger(ImplementationsOfOneNodeTypeResource.class); + + + /** + * The constructor is different from the usual constructors as this resource + * does NOT store own data, but retrieves its data solely from the + * associated node type + * + * @param nodeTypeId the node type id, where this list of implementations + * belongs to + */ + public ImplementationsOfOneNodeTypeResource(NodeTypeId nodeTypeId) { + super(nodeTypeId); + } + + /** + * required by implementations.jsp + * + * @return for each node type implementation implementing the associated + * node type + */ + @Override + public String getImplementationsTableData() { + String res; + JsonFactory jsonFactory = new JsonFactory(); + StringWriter tableDataSW = new StringWriter(); + try { + JsonGenerator jGenerator = jsonFactory.createGenerator(tableDataSW); + jGenerator.writeStartArray(); + + Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, this.getTypeId().getQName()); + for (NodeTypeImplementationId ntiID : allNodeTypeImplementations) { + jGenerator.writeStartArray(); + jGenerator.writeString(ntiID.getNamespace().getDecoded()); + jGenerator.writeString(ntiID.getXmlId().getDecoded()); + jGenerator.writeEndArray(); + } + jGenerator.writeEndArray(); + jGenerator.close(); + tableDataSW.close(); + res = tableDataSW.toString(); + } catch (Exception e) { + ImplementationsOfOneNodeTypeResource.logger.error(e.getMessage(), e); + res = "[]"; + } + return res; + } + + @Override + public String getType() { + return "nodetype"; + } + + @Override + public String getTypeStr() { + return "Node Type"; + } + + @Override + public Response getJSON() { + Collection<NodeTypeImplementationId> allImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, this.getTypeId().getQName()); + ArrayList<QName> res = new ArrayList<QName>(allImplementations.size()); + for (NodeTypeImplementationId id : allImplementations) { + res.add(id.getQName()); + } + return Response.ok().entity(res).build(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java new file mode 100644 index 0000000..6c573a5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TNodeType.CapabilityDefinitions; +import org.eclipse.winery.model.tosca.TNodeType.Interfaces; +import org.eclipse.winery.model.tosca.TNodeType.RequirementDefinitions; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.repository.resources.entitytypes.InstanceStatesResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs.CapabilityDefinitionsResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs.RequirementDefinitionsResource; +import org.eclipse.winery.repository.resources.interfaces.InterfacesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NodeTypeResource extends TopologyGraphElementEntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(NodeTypeResource.class); + + + public NodeTypeResource(NodeTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TNodeType getNodeType() { + return (TNodeType) this.getElement(); + } + + /** sub-resources **/ + + @Path("implementations/") + public ImplementationsOfOneNodeTypeResource getImplementations() { + return new ImplementationsOfOneNodeTypeResource((NodeTypeId) this.id); + } + + @Path("instancestates/") + public InstanceStatesResource getInstanceStatesResource() { + TTopologyElementInstanceStates instanceStates = this.getNodeType().getInstanceStates(); + if (instanceStates == null) { + // if an explicit (empty) list does not exist, create it + instanceStates = new TTopologyElementInstanceStates(); + this.getNodeType().setInstanceStates(instanceStates); + } + return new InstanceStatesResource(instanceStates, this); + } + + @Path("interfaces/") + public InterfacesResource getInterfaces() { + Interfaces interfaces = this.getNodeType().getInterfaces(); + if (interfaces == null) { + interfaces = new Interfaces(); + this.getNodeType().setInterfaces(interfaces); + } + return new InterfacesResource(null, interfaces.getInterface(), this); + } + + @Path("requirementdefinitions/") + public RequirementDefinitionsResource getRequirementDefinitions() { + RequirementDefinitions definitions = this.getNodeType().getRequirementDefinitions(); + if (definitions == null) { + definitions = new RequirementDefinitions(); + this.getNodeType().setRequirementDefinitions(definitions); + } + return new RequirementDefinitionsResource(this, definitions.getRequirementDefinition()); + } + + @Path("capabilitydefinitions/") + public CapabilityDefinitionsResource getCapabilityDefinitions() { + CapabilityDefinitions definitions = this.getNodeType().getCapabilityDefinitions(); + if (definitions == null) { + definitions = new CapabilityDefinitions(); + this.getNodeType().setCapabilityDefinitions(definitions); + } + return new CapabilityDefinitionsResource(this, definitions.getCapabilityDefinition()); + } + + @Path("visualappearance/") + public VisualAppearanceResource getVisualAppearanceResource() { + return new VisualAppearanceResource(this, this.getElement().getOtherAttributes(), (NodeTypeId) this.id); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TNodeType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java new file mode 100644 index 0000000..798e5a5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all nodetypes in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class NodeTypesResource extends AbstractComponentsResource<NodeTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java new file mode 100644 index 0000000..d897efe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes; + +import java.io.InputStream; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.constants.QNames; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.constants.Filename; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.GenericVisualAppearanceResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class VisualAppearanceResource extends GenericVisualAppearanceResource { + + private static final Logger logger = LoggerFactory.getLogger(VisualAppearanceResource.class); + + + public VisualAppearanceResource(NodeTypeResource res, Map<QName, String> map, NodeTypeId parentId) { + super(res, map, new VisualAppearanceId(parentId)); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/nodetypes/visualappearance.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @GET + @Path("50x50") + public Response get50x50Image(@HeaderParam("If-Modified-Since") String modified) { + return this.getImage(Filename.FILENAME_BIG_ICON, modified); + } + + @PUT + @Path("50x50") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response post50x50Image(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + return this.putImage(Filename.FILENAME_BIG_ICON, uploadedInputStream, body.getMediaType()); + } + + @GET + @Path("bordercolor") + public String getBorderColor() { + return BackendUtils.getColorAndSetDefaultIfNotExisting(this.getId().getParent().getXmlId().getDecoded(), QNames.QNAME_BORDER_COLOR, this.otherAttributes, this.res); + } + + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("bordercolor") + public Response putBorderColor(@FormParam("color") String color) { + this.otherAttributes.put(QNames.QNAME_BORDER_COLOR, color); + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java new file mode 100644 index 0000000..b7eea92 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import java.lang.reflect.Method; +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.ConstraintsResource; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Bundles common properties of TRequirementDefinition and TCapabilityDefinition + * + * We agreed in the project not to modify org.eclipse.winery.model.tosca. + * Therefore, this resource models the common properties of a + * TRequirementDefinition and a TCapabilityDefinition + */ +public abstract class AbstractReqOrCapDefResource<ReqOrCapDef> extends EntityWithIdResource<ReqOrCapDef> implements IIdDetermination<ReqOrCapDef> { + + private static final Logger logger = LoggerFactory.getLogger(AbstractReqOrCapDefResource.class); + + protected NodeTypeResource parent; + + // the capability or the requirement + private Object reqOrCapDef; + + private List<TConstraint> constraints; + + + /** + * @param constraints additional parameter (in comparison to the constructor + * of EntityWithIdResource) as we require that sublist for the + * constrinats sub resource + */ + public AbstractReqOrCapDefResource(IIdDetermination<ReqOrCapDef> idDetermination, ReqOrCapDef reqOrCapDef, int idx, List<ReqOrCapDef> list, NodeTypeResource res, List<TConstraint> constraints) { + super(idDetermination, reqOrCapDef, idx, list, res); + assert ((reqOrCapDef instanceof TRequirementDefinition) || (reqOrCapDef instanceof TCapabilityDefinition)); + this.parent = res; + this.reqOrCapDef = reqOrCapDef; + this.constraints = constraints; + } + + @GET + @Path("name") + public String getName() { + return (String) this.invokeGetter("getName"); + } + + static String getName(Object reqOrCapDef) { + return (String) AbstractReqOrCapDefResource.invokeGetter(reqOrCapDef, "getName"); + } + + @GET + @Path("lowerbound") + public int getLowerBound() { + return (int) this.invokeGetter("getLowerBound"); + } + + @GET + @Path("upperbound") + public String getUpperBound() { + return (String) this.invokeGetter("getUpperBound"); + } + + @PUT + @Path("name") + public Response setName(@FormParam(value = "name") String name) { + // TODO: type check - see also min/max Instance of a node template + this.invokeSetter("setName", name); + return BackendUtils.persist(this.parent); + } + + @PUT + @Path("lowerbound") + public Response setLowerBound(@FormParam(value = "lowerbound") String value) { + // TODO: type check + this.invokeSetter("setLowerBound", value); + return BackendUtils.persist(this.parent); + } + + @PUT + @Path("upperbound") + public Response setUpperBound(@FormParam(value = "upperbound") String value) { + // TODO: type check + this.invokeSetter("setUpperBound", value); + return BackendUtils.persist(this.parent); + } + + @Path("constraints/") + public ConstraintsResource getConstraintsResource() { + return new ConstraintsResource(this.constraints, this.parent); + } + + private static Object invokeGetter(Object reqOrCapDef, String getterName) { + Method method; + Object res; + try { + method = reqOrCapDef.getClass().getMethod(getterName); + res = method.invoke(reqOrCapDef); + } catch (Exception e) { + AbstractReqOrCapDefResource.logger.error("Could not invoke getter {}", getterName, e); + throw new IllegalStateException(e); + } + return res; + } + + private Object invokeGetter(String getterName) { + return AbstractReqOrCapDefResource.invokeGetter(this.reqOrCapDef, getterName); + } + + /** + * Quick hack method for RequirementOrCapabilityDefinitionsResource + */ + static void invokeSetter(Object reqOrCapDef, String setterName, Object value) { + Method method; + try { + method = reqOrCapDef.getClass().getMethod(setterName, value.getClass()); + method.invoke(reqOrCapDef, value); + } catch (Exception e) { + AbstractReqOrCapDefResource.logger.error("Could not invoke setter {}", setterName, e); + throw new IllegalStateException(e); + } + } + + private void invokeSetter(String setterName, Object value) { + AbstractReqOrCapDefResource.invokeSetter(this.reqOrCapDef, setterName, value); + } + + @GET + @Path("type") + @Produces(MediaType.TEXT_PLAIN) + public String getTypeAsString() { + return this.getType().toString(); + } + + /** + * required by the JSP. + * + * Therefore, we have two getters for the type: QName for the JSP and String + * for REST clients + */ + public abstract QName getType(); + + /** + * Required by reqandcapdefs.jsp + */ + public Object getDef() { + return this.reqOrCapDef; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java new file mode 100644 index 0000000..0fd3bd3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TCapabilityDefinition.Constraints; +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +/** + * Implementation similar to RequirementDefinitionResource, but with + * TCapabilityDefinition instead of TRequirementDefinition + */ +public final class CapabilityDefinitionResource extends AbstractReqOrCapDefResource<TCapabilityDefinition> { + + private TCapabilityDefinition capDef; + + + /** + * Constructor has to follow the pattern of EnetityTResource as the + * constructor is invoked by reflection in EntityWithIdcollectionResource + * + * @param res the resource this req def is nested in. Has to be of Type + * "NodeTypeResource". Due to the implementation of + * org.eclipse.winery .repository.resources._support.collections. + * withid.EntityWithIdCollectionResource + * .getEntityResourceInstance(EntityT, int), we have to use + * "AbstractComponentInstanceResource" as type + */ + public CapabilityDefinitionResource(IIdDetermination<TCapabilityDefinition> idDetermination, TCapabilityDefinition capDef, int idx, List<TCapabilityDefinition> list, AbstractComponentInstanceResource res) { + super(idDetermination, capDef, idx, list, (NodeTypeResource) res, CapabilityDefinitionResource.getConstraints(capDef)); + this.capDef = capDef; + } + + /** + * Quick hack to avoid internal server error + */ + public CapabilityDefinitionResource(IIdDetermination<TCapabilityDefinition> idDetermination, TCapabilityDefinition capDef, int idx, List<TCapabilityDefinition> list, IPersistable res) { + this(idDetermination, capDef, idx, list, (AbstractComponentInstanceResource) res); + } + + /** + * Fetch the list of constraints from the given definition. If the list does + * not exist, the list is created an stored in the given capDef + */ + public static List<TConstraint> getConstraints(TCapabilityDefinition capDef) { + Constraints constraints = capDef.getConstraints(); + if (constraints == null) { + constraints = new Constraints(); + capDef.setConstraints(constraints); + } + return constraints.getConstraint(); + } + + public QName getType() { + return this.capDef.getCapabilityType(); + } + + @PUT + @Path("type") + public Response setType(@FormParam(value = "type") String value) { + QName qname = QName.valueOf(value); + this.capDef.setCapabilityType(qname); + return BackendUtils.persist(this.parent); + } + + @Override + public String getId(TCapabilityDefinition e) { + return e.getName(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java new file mode 100644 index 0000000..d93edb4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class CapabilityDefinitionsResource extends RequirementOrCapabilityDefinitionsResource<CapabilityDefinitionResource, TCapabilityDefinition> { + + private static final Logger logger = LoggerFactory.getLogger(CapabilityDefinitionsResource.class); + + + public CapabilityDefinitionsResource(NodeTypeResource res, List<TCapabilityDefinition> defs) { + super(CapabilityDefinitionResource.class, TCapabilityDefinition.class, defs, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/nodetypes/reqandcapdefs/capdefs.jsp", this); + } + + @Override + public Collection<QName> getAllTypes() { + SortedSet<CapabilityTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(CapabilityTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java new file mode 100644 index 0000000..aeee000 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TConstraint; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.model.tosca.TRequirementDefinition.Constraints; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +public final class RequirementDefinitionResource extends AbstractReqOrCapDefResource<TRequirementDefinition> { + + private TRequirementDefinition reqDef; + + + /** + * Constructor has to follow the pattern of EnetityTResource as the + * constructor is invoked by reflection in EntityWithIdcollectionResource + * + * @param res the resource this req def is nested in. Has to be of Type + * "NodeTypeResource". Due to the implementation of + * org.eclipse.winery .repository.resources._support.collections. + * withid.EntityWithIdCollectionResource + * .getEntityResourceInstance(EntityT, int), we have to use + * "AbstractComponentInstanceResource" as type + */ + public RequirementDefinitionResource(IIdDetermination<TRequirementDefinition> idDetermination, TRequirementDefinition reqDef, int idx, List<TRequirementDefinition> list, AbstractComponentInstanceResource res) { + super(idDetermination, reqDef, idx, list, (NodeTypeResource) res, RequirementDefinitionResource.getConstraints(reqDef)); + this.reqDef = reqDef; + } + + /** + * Quick fix to avoid internal server error when opening + * RequirementDefinitions Tab + */ + public RequirementDefinitionResource(IIdDetermination<TRequirementDefinition> idDetermination, TRequirementDefinition reqDef, int idx, List<TRequirementDefinition> list, IPersistable res) { + this(idDetermination, reqDef, idx, list, (AbstractComponentInstanceResource) res); + } + + /** + * Fetch the list of constraints from the given definition. If the list does + * not exist, the list is created an stored in the given def + */ + public static List<TConstraint> getConstraints(TRequirementDefinition def) { + Constraints constraints = def.getConstraints(); + if (constraints == null) { + constraints = new Constraints(); + def.setConstraints(constraints); + } + return constraints.getConstraint(); + } + + public QName getType() { + return this.reqDef.getRequirementType(); + } + + @PUT + @Path("type") + public Response setType(@FormParam(value = "type") String value) { + QName qname = QName.valueOf(value); + this.reqDef.setRequirementType(qname); + return BackendUtils.persist(this.parent); + } + + @Override + public String getId(TRequirementDefinition e) { + return e.getName(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java new file mode 100644 index 0000000..62db596 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.RequirementTypeId; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +import com.sun.jersey.api.view.Viewable; + +public class RequirementDefinitionsResource extends RequirementOrCapabilityDefinitionsResource<RequirementDefinitionResource, TRequirementDefinition> { + + public RequirementDefinitionsResource(NodeTypeResource res, List<TRequirementDefinition> defs) { + super(RequirementDefinitionResource.class, TRequirementDefinition.class, defs, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/nodetypes/reqandcapdefs/reqdefs.jsp", this); + } + + @Override + public Collection<QName> getAllTypes() { + SortedSet<RequirementTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(RequirementTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java new file mode 100644 index 0000000..0c6936e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import java.util.Collection; +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * This superclass has only a few methods as we cannot easily abstract from the + * subclasses: We would need Java reflection to invoke "getName" (to get the + * subresource). The hope is that this copy'n'paste programming will not + * introduce bugs when changing childs + * + * We try to abstract from the problems by using generics and reflections + * + * @param <ReqDefOrCapDef> TRequirementDefinition or TCapabilityDefinition + * @param <ReqDefOrCapDefResource> the resource managing ReqDefOrCapDef + */ +public abstract class RequirementOrCapabilityDefinitionsResource<ReqDefOrCapDefResource extends AbstractReqOrCapDefResource<ReqDefOrCapDef>, ReqDefOrCapDef> extends EntityWithIdCollectionResource<ReqDefOrCapDefResource, ReqDefOrCapDef> { + + protected final NodeTypeResource res; + + + public RequirementOrCapabilityDefinitionsResource(Class<ReqDefOrCapDefResource> entityResourceTClazz, Class<ReqDefOrCapDef> entityTClazz, List<ReqDefOrCapDef> list, NodeTypeResource res) { + super(entityResourceTClazz, entityTClazz, list, res); + this.res = res; + } + + @Override + public abstract Viewable getHTML(); + + /** + * @return collection of all available types + */ + public abstract Collection<QName> getAllTypes(); + + @POST + // As there is no supertype of TCapabilityType and TRequirementType containing the common attributes, we have to rely on unchecked casts + @SuppressWarnings("unchecked") + public Response onPost(@FormParam("name") String name, @FormParam("type") String type, @FormParam("lowerbound") String lowerBound, @FormParam("upperbound") String upperbound) { + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("Name has to be provided").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("Type has to be provided").build(); + } + + int lbound = 1; + if (!StringUtils.isEmpty(lowerBound)) { + try { + lbound = Integer.parseInt(lowerBound); + } catch (NumberFormatException e) { + return Response.status(Status.BAD_REQUEST).entity("Bad format of lowerbound: " + e.getMessage()).build(); + } + } + + String ubound = "1"; + if (!StringUtils.isEmpty(upperbound)) { + ubound = upperbound; + } + + // we also support replacement of existing requirements + // therefore, we loop through the existing requirements + int idx = -1; + boolean found = false; + for (ReqDefOrCapDef d : this.list) { + idx++; + if (this.getId(d).equals(name)) { + found = true; + break; + } + } + + QName typeQName = QName.valueOf(type); + // Create object and put type in it + ReqDefOrCapDef def; + if (this instanceof CapabilityDefinitionsResource) { + def = (ReqDefOrCapDef) new TCapabilityDefinition(); + ((TCapabilityDefinition) def).setCapabilityType(typeQName); + } else { + assert (this instanceof RequirementDefinitionsResource); + def = (ReqDefOrCapDef) new TRequirementDefinition(); + ((TRequirementDefinition) def).setRequirementType(typeQName); + } + + // copy all other data into object + AbstractReqOrCapDefResource.invokeSetter(def, "setName", name); + AbstractReqOrCapDefResource.invokeSetter(def, "setLowerBound", lbound); + AbstractReqOrCapDefResource.invokeSetter(def, "setUpperBound", ubound); + + if (found) { + // replace element + this.list.set(idx, def); + } else { + // add new element + this.list.add(def); + } + + Response r = BackendUtils.persist(this.res); + return r; + } + + @Override + public String getId(ReqDefOrCapDef reqDefOrCapDef) { + return AbstractReqOrCapDefResource.getName(reqDefOrCapDef); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java new file mode 100644 index 0000000..6fbbc5a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * The sub packages of this package contains all resources, which are derived + * from tEntityType + */ +package org.eclipse.winery.repository.resources.entitytypes; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java new file mode 100644 index 0000000..0e4b560 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.policytypes; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.model.tosca.TPolicyType; + +import com.sun.jersey.api.view.Viewable; + +public class AppliesToResource { + + private PolicyTypeResource policyTypeResource; + + + public AppliesToResource(PolicyTypeResource policyTypeResource) { + this.policyTypeResource = policyTypeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/policytypes/appliesto.jsp", this); + } + + public TPolicyType getPolicyType() { + return this.policyTypeResource.getPolicyType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java new file mode 100644 index 0000000..036cc73 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java @@ -0,0 +1,28 @@ +package org.eclipse.winery.repository.resources.entitytypes.policytypes; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import com.sun.jersey.api.view.Viewable; + +public class LanguageResource { + + private PolicyTypeResource policyTypeResource; + + + public LanguageResource(PolicyTypeResource policyTypeResource) { + this.policyTypeResource = policyTypeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/policytypes/language.jsp", this); + } + + public String getLanguage() { + return this.policyTypeResource.getPolicyType().getPolicyLanguage(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java new file mode 100644 index 0000000..62c728a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.policytypes; + +import java.util.SortedSet; + +import javax.ws.rs.Path; + +import org.eclipse.winery.common.ids.definitions.PolicyTemplateId; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TPolicyType; +import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class PolicyTypeResource extends EntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(PolicyTypeResource.class); + + + /** + * Constructor has to be public because of test cases + */ + public PolicyTypeResource(PolicyTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TPolicyType getPolicyType() { + return (TPolicyType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TPolicyType(); + } + + @Path("appliesto/") + public AppliesToResource getAppliesTo() { + return new AppliesToResource(this); + } + + @Path("language/") + public LanguageResource getLanguage() { + return new LanguageResource(this); + } + + @Override + public SortedSet<Select2OptGroup> getListOfAllInstances() { + return this.getListOfAllInstances(PolicyTemplateId.class); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java new file mode 100644 index 0000000..17d4db0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.policytypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all policy types in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class PolicyTypesResource extends AbstractComponentsResource<PolicyTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java new file mode 100644 index 0000000..a5338ed --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.properties; + +import java.util.List; + +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TEntityType; + +/** + * Collects data used by the JSP + */ +public class JSPData { + + // FIXME: this is a quick hack and provides a fixed list of available + // property types only. This list has to be made dynamically updatable (and offer plugins to edit) + // currently only http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#built-in-datatypes are supported + private static final String[] availablePropertyTypes = {"xsd:string", "xsd:boolean", "xsd:decimal", "xsd:float", "xsd:anyURI", "xsd:QName"}; + + private final PropertiesDefinitionResource propertiesDefinitionResource; + private final WinerysPropertiesDefinition wpd; + + + public JSPData(PropertiesDefinitionResource propertiesDefinitionResource, WinerysPropertiesDefinition wpd) { + this.propertiesDefinitionResource = propertiesDefinitionResource; + this.wpd = wpd; + } + + public List<PropertyDefinitionKV> getPropertyDefinitionKVList() { + // as this method is used by the JSP, we have to initialize the list and not provide a fake list + // in other words: we are in the mode, where the user has chosen the winery property handling + assert (this.getIsWineryKeyValueProperties()); + if (this.wpd.getPropertyDefinitionKVList() == null) { + return java.util.Collections.emptyList(); + } else { + return this.wpd.getPropertyDefinitionKVList(); + } + } + + public Boolean getIsWineryKeyValueProperties() { + return (this.wpd != null); + // the jsp renders list data only if the list is existing + // we could (somehow) also always keep the old list, but we opted for keeping the choice between the four options also in the XML (and not storing stale data) + // in the case, the WPD is derived from XSD, the list is rendered nevertheless + } + + public boolean getIsWineryKeyValuePropertiesDerivedFromXSD() { + return ((this.wpd != null) && (this.wpd.getIsDerivedFromXSD() != null)); + } + + public String[] getAvailablePropertyTypes() { + return JSPData.availablePropertyTypes; + } + + public TEntityType getEntityType() { + return this.propertiesDefinitionResource.getEntityType(); + } + + public String getElementName() { + if (this.wpd == null) { + return null; + } else { + return this.wpd.getElementName(); + } + } + + public String getNamespace() { + if (this.wpd == null) { + return null; + } else { + return this.wpd.getNamespace(); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java new file mode 100644 index 0000000..6a63791 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.properties; + +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.constants.MimeTypes; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.properties.winery.WinerysPropertiesDefinitionResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +/** + * Models + * <ol> + * <li>TOSCA conforming properties definition (XML element / XML schema / none)</li> + * <li>Winery's KV properties (in the subresource "winery")</li> + * </ol> + * + * This class does not have "KV" in its name, because it models + * {@link TEntityType.PropertiesDefinition} + */ +public class PropertiesDefinitionResource { + + private static final Logger logger = LoggerFactory.getLogger(PropertiesDefinitionResource.class); + + // We hold a copy of super.res as we work on the type EntityTypeResource instead of AbstractComponentInstanceResource + private final EntityTypeResource parentRes; + + // we assume that this class is created at each request + // therefore, we can have "wpd" final + private final WinerysPropertiesDefinition wpd; + + + public PropertiesDefinitionResource(EntityTypeResource res) { + this.parentRes = res; + this.wpd = ModelUtilities.getWinerysPropertiesDefinition(res.getEntityType()); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/properties/propertiesDefinition.jsp", new JSPData(this, this.wpd)); + } + + public TEntityType getEntityType() { + return this.parentRes.getEntityType(); + } + + @Path("winery/") + public WinerysPropertiesDefinitionResource getWinerysPropertiesDefinitionResource() { + // this.wpd is null if there is no winery definition exisitin. The subresource handles that case, too + return new WinerysPropertiesDefinitionResource(this.parentRes, this.wpd); + } + + @DELETE + public Response clearPropertiesDefinition() { + this.getEntityType().setPropertiesDefinition(null); + ModelUtilities.removeWinerysPropertiesDefinition(this.getEntityType()); + return BackendUtils.persist(this.parentRes); + } + + public boolean getIsWineryKeyValueProperties() { + return (this.wpd != null); + } + + @GET + @Produces(MimeTypes.MIMETYPE_XSD) + public Response getXSD() { + if (this.getIsWineryKeyValueProperties()) { + return Response.ok().entity(ModelUtilities.getWinerysPropertiesDefinitionXSDAsDocument(this.wpd)).build(); + } else { + // not yet implemented + // We would have to check the imports in the repo for the defined property + // This also has to be similarly done at the export to determine the right imports + return Response.status(Status.NOT_FOUND).build(); + } + } + + @GET + @RestDoc(methodDescription = "We provide the XSD at . and at ./xsd/ to enable simple quering in the browser without the hazzle of setting the correct mime type.") + @Path("xsd/") + @Produces(MimeTypes.MIMETYPE_XSD) + public Response getXSDAtSubResource() { + return this.getXSD(); + } + + // @formatter:off + @POST + @RestDoc(methodDescription="Updates/creates a property based on XSD element or XML schema.") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response onPost( + @FormParam("name") @RestDocParam(description="Either xsdelement or xsdtype. 'name' comes from x-editable, which uses that as field name") String name, + @FormParam("value") @RestDocParam(description="The qname") String value) { + // @formatter:on + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("You have to provide a key/type or a name/value pair").build(); + } + if (StringUtils.isEmpty(value)) { + return Response.status(Status.BAD_REQUEST).entity("If a name is provided, a value has also to be provided").build(); + } + + // first of all, remove Winery's Properties definition (if it exists) + ModelUtilities.removeWinerysPropertiesDefinition(this.getEntityType()); + + QName qname = QName.valueOf(value); + + // replace old properties definition by new one + PropertiesDefinition def = new PropertiesDefinition(); + if (name.equals("xsdtype")) { + def.setType(qname); + } else if (name.equals("xsdelement")) { + def.setElement(qname); + } else { + return Response.status(Status.BAD_REQUEST).entity("Invalid name. Choose xsdelement or xsdtype").build(); + } + this.getEntityType().setPropertiesDefinition(def); + List<String> errors = new ArrayList<>(); + BackendUtils.deriveWPD(this.getEntityType(), errors); + // currently the errors are just logged + for (String error : errors) { + PropertiesDefinitionResource.logger.debug(error); + } + return BackendUtils.persist(this.parentRes); + + } + +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java new file mode 100644 index 0000000..f967042 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.properties.winery; + +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * Supports Winery's k/v properties introducing sub resources + * "PropertyDefinition", which defines <em>one</em> property + */ +public class PropertyDefinitionKVListResource extends EntityWithIdCollectionResource<PropertyDefinitionKVResource, PropertyDefinitionKV> { + + public PropertyDefinitionKVListResource(EntityTypeResource res, PropertyDefinitionKVList list) { + super(PropertyDefinitionKVResource.class, PropertyDefinitionKV.class, list, res); + } + + @Override + public String getId(PropertyDefinitionKV entity) { + return entity.getKey(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java new file mode 100644 index 0000000..00a8d24 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.properties.winery; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.restdoc.annotations.RestDoc; + +/** + * Models a definition of one property + * + * This is NOT in line with CSPRD01, which forces one element of one type + */ +public class PropertyDefinitionKVResource extends EntityWithIdResource<PropertyDefinitionKV> { + + public PropertyDefinitionKVResource(IIdDetermination<PropertyDefinitionKV> idDetermination, PropertyDefinitionKV o, int idx, List<PropertyDefinitionKV> list, AbstractComponentInstanceResource res) { + super(idDetermination, o, idx, list, res); + } + + public PropertyDefinitionKVResource(IIdDetermination<PropertyDefinitionKV> idDetermination, PropertyDefinitionKV o, int idx, List<PropertyDefinitionKV> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @GET + @RestDoc(methodDescription = "@return type is the 'id' of the type ('shortType'), not the full type name") + @Path("type") + public String getType() { + return this.o.getType(); + } + + @PUT + @RestDoc(methodDescription = "@return type is the 'id' of the type ('shortType'), not the full type name") + @Path("type") + public Response setType(@FormParam("type") String type) { + this.o.setType(type); + return BackendUtils.persist(this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java new file mode 100644 index 0000000..0d219e3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.properties.winery; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TEntityType; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList; +import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.EntityTypeResource; +import org.restdoc.annotations.RestDoc; + +import com.sun.jersey.api.NotFoundException; + +public class WinerysPropertiesDefinitionResource { + + private final EntityTypeResource res; + private final WinerysPropertiesDefinition wpd; + + + /** + * @param res the resource where winery's k/v properties are defined + * @param wpd winery's properties definition object, MAY be null + */ + public WinerysPropertiesDefinitionResource(EntityTypeResource res, WinerysPropertiesDefinition wpd) { + this.res = res; + this.wpd = wpd; + } + + @POST + @RestDoc(methodDescription = "switches the mode to winery properties instead of element/type properties") + public Response onPost() { + TEntityType et = this.res.getEntityType(); + + // clear current properties definition + et.setPropertiesDefinition(null); + + // create empty winery properties definition and persist it + WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition(); + ModelUtilities.replaceWinerysPropertiesDefinition(et, wpd); + return BackendUtils.persist(this.res); + } + + @Path("namespace") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getNamespace() { + if (this.wpd == null) { + throw new NotFoundException(); + } + return this.wpd.getNamespace(); + } + + @Path("namespace") + @PUT + @Consumes(MediaType.TEXT_PLAIN) + public Response setNamespace(String namespace) { + if (this.wpd == null) { + throw new NotFoundException(); + } + this.wpd.setNamespace(namespace); + return BackendUtils.persist(this.res); + } + + @Path("elementname") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getElementName() { + if (this.wpd == null) { + throw new NotFoundException(); + } + return this.wpd.getElementName(); + } + + @Path("elementname") + @PUT + @Consumes(MediaType.TEXT_PLAIN) + public Response setLocalname(String elementName) { + if (this.wpd == null) { + throw new NotFoundException(); + } + this.wpd.setElementName(elementName); + return BackendUtils.persist(this.res); + } + + @Path("elementname") + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response setLocalnameViaWebUI(@FormParam(value = "name") String elementName) { + if (this.wpd == null) { + throw new NotFoundException(); + } + this.wpd.setElementName(elementName); + return BackendUtils.persist(this.res); + } + + /** + * Here, also the addition of k/v properties is handled. + */ + @Path("list/") + public PropertyDefinitionKVListResource getListResource() { + if (this.wpd == null) { + throw new NotFoundException(); + } + PropertyDefinitionKVList list = this.wpd.getPropertyDefinitionKVList(); + if (list == null) { + list = new PropertyDefinitionKVList(); + this.wpd.setPropertyDefinitionKVList(list); + } + return new PropertyDefinitionKVListResource(this.res, list); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java new file mode 100644 index 0000000..c7cf2d6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.entitytypes.ImplementationsOfOneType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; + +public class ImplementationsOfOneRelationshipTypeResource extends ImplementationsOfOneType { + + public ImplementationsOfOneRelationshipTypeResource(RelationshipTypeId typeId) { + super(typeId); + } + + + private static final Logger logger = LoggerFactory.getLogger(ImplementationsOfOneRelationshipTypeResource.class); + + + /** + * required by implementations.jsp + * + * Method similar top the one of ImplementationsOfOneNodeTypeResource + * + * @return for each node type implementation implementing the associated + * node type + */ + @Override + public String getImplementationsTableData() { + String res; + JsonFactory jsonFactory = new JsonFactory(); + StringWriter tableDataSW = new StringWriter(); + try { + JsonGenerator jGenerator = jsonFactory.createGenerator(tableDataSW); + jGenerator.writeStartArray(); + + Collection<RelationshipTypeImplementationId> allNTIids = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, this.getTypeId().getQName()); + for (RelationshipTypeImplementationId ntiID : allNTIids) { + jGenerator.writeStartArray(); + jGenerator.writeString(ntiID.getNamespace().getDecoded()); + jGenerator.writeString(ntiID.getXmlId().getDecoded()); + jGenerator.writeEndArray(); + } + jGenerator.writeEndArray(); + jGenerator.close(); + tableDataSW.close(); + res = tableDataSW.toString(); + } catch (Exception e) { + ImplementationsOfOneRelationshipTypeResource.logger.error(e.getMessage(), e); + res = "[]"; + } + return res; + } + + @Override + public String getType() { + return "relationshiptype"; + } + + @Override + public String getTypeStr() { + return "Relationship Type"; + } + + @Override + public Response getJSON() { + Collection<RelationshipTypeImplementationId> allImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, this.getTypeId().getQName()); + ArrayList<QName> res = new ArrayList<QName>(allImplementations.size()); + for (RelationshipTypeImplementationId id : allImplementations) { + res.add(id.getQName()); + } + return Response.ok().entity(res).build(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java new file mode 100644 index 0000000..c874bd5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes; + +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRelationshipType.SourceInterfaces; +import org.eclipse.winery.model.tosca.TRelationshipType.TargetInterfaces; +import org.eclipse.winery.model.tosca.TRelationshipType.ValidSource; +import org.eclipse.winery.model.tosca.TRelationshipType.ValidTarget; +import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates; +import org.eclipse.winery.common.ids.definitions.NodeTypeId; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.InstanceStatesResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.interfaces.InterfacesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class RelationshipTypeResource extends TopologyGraphElementEntityTypeResource { + + private static final Logger logger = LoggerFactory.getLogger(RelationshipTypeResource.class); + + + public RelationshipTypeResource(RelationshipTypeId id) { + super(id); + } + + @Path("implementations/") + public ImplementationsOfOneRelationshipTypeResource getImplementations() { + return new ImplementationsOfOneRelationshipTypeResource((RelationshipTypeId) this.id); + } + + @Path("visualappearance/") + public VisualAppearanceResource getVisualAppearanceResource() { + return new VisualAppearanceResource(this, this.getElement().getOtherAttributes(), (RelationshipTypeId) this.id); + } + + @Path("instancestates/") + public InstanceStatesResource getInstanceStatesResource() { + TTopologyElementInstanceStates instanceStates = this.getRelationshipType().getInstanceStates(); + if (instanceStates == null) { + // if an explicit (empty) list does not exist, create it + instanceStates = new TTopologyElementInstanceStates(); + this.getRelationshipType().setInstanceStates(instanceStates); + } + return new InstanceStatesResource(this.getRelationshipType().getInstanceStates(), this); + } + + @Path("sourceinterfaces/") + public InterfacesResource getSourceInterfaces() { + SourceInterfaces interfaces = this.getRelationshipType().getSourceInterfaces(); + if (interfaces == null) { + interfaces = new SourceInterfaces(); + this.getRelationshipType().setSourceInterfaces(interfaces); + } + return new InterfacesResource("source", interfaces.getInterface(), this); + } + + @Path("targetinterfaces/") + public InterfacesResource getTargetInterfaces() { + TargetInterfaces interfaces = this.getRelationshipType().getTargetInterfaces(); + if (interfaces == null) { + interfaces = new TargetInterfaces(); + this.getRelationshipType().setTargetInterfaces(interfaces); + } + return new InterfacesResource("target", interfaces.getInterface(), this); + } + + @Path("validendings/") + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/relationshiptypes/validendings.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @Path("validsource") + @GET + public String getValidSource() { + ValidSource validSource; + if (((validSource = this.getRelationshipType().getValidSource()) == null) || (validSource.getTypeRef() == null)) { + return null; + } + return this.getRelationshipType().getValidSource().getTypeRef().toString(); + } + + @Path("validsource") + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response setValidSource(String typeRef) { + ValidSource vs = new ValidSource(); + QName qname = QName.valueOf(typeRef); + vs.setTypeRef(qname); + this.getRelationshipType().setValidSource(vs); + return BackendUtils.persist(this); + } + + @Path("validtarget") + @GET + public String getValidTarget() { + ValidTarget validTarget; + if (((validTarget = this.getRelationshipType().getValidTarget()) == null) || (validTarget.getTypeRef() == null)) { + return null; + } + return this.getRelationshipType().getValidTarget().getTypeRef().toString(); + } + + @Path("validtarget") + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response setValidTarget(String typeRef) { + ValidTarget vt = new ValidTarget(); + QName qname = QName.valueOf(typeRef); + vt.setTypeRef(qname); + this.getRelationshipType().setValidTarget(vt); + return BackendUtils.persist(this); + } + + /** + * Required for validendings.jsp + */ + public Collection<NodeTypeId> getPossibleValidEndings() { + SortedSet<NodeTypeId> allNodeTypeIds = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeId.class); + return allNodeTypeIds; + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TRelationshipType getRelationshipType() { + return (TRelationshipType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TRelationshipType(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java new file mode 100644 index 0000000..1c73ab0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class RelationshipTypesResource extends AbstractComponentsResource<RelationshipTypeResource> { +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java new file mode 100644 index 0000000..c17c19b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + * Jerome Tagliaferri - support for setting the color + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes; + +import java.io.StringWriter; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.constants.Defaults; +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.constants.QNames; +import org.eclipse.winery.common.ids.definitions.RelationshipTypeId; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId; +import org.eclipse.winery.repository.resources.GenericVisualAppearanceResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.sun.jersey.api.view.Viewable; + +public class VisualAppearanceResource extends GenericVisualAppearanceResource { + + private static final Logger logger = LoggerFactory.getLogger(VisualAppearanceResource.class); + + private static final QName QNAME_ARROWHEAD_SOURCE = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "sourceArrowHead"); + private static final QName QNAME_ARROWHEAD_TARGET = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "targetArrowHead"); + private static final QName QNAME_DASH = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "dash"); + private static final QName QNAME_LINEWIDTH = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "linewidth"); + private static final QName QNAME_HOVER_COLOR = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "hovercolor"); + + + public VisualAppearanceResource(RelationshipTypeResource res, Map<QName, String> map, RelationshipTypeId parentId) { + super(res, map, new VisualAppearanceId(parentId)); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML() { + Viewable viewable = new Viewable("/jsp/entitytypes/relationshiptypes/visualappearance.jsp", this); + return Response.ok().entity(viewable).build(); + } + + @GET + @RestDoc(methodDescription = "@return JSON object to be used at jsPlumb.registerConnectionType('NAME', <data>)") + @Produces(MediaType.APPLICATION_JSON) + public Response getConnectionTypeForJsPlumbData() { + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + try { + JsonGenerator jg = jsonFactory.createGenerator(sw); + jg.writeStartObject(); + + jg.writeFieldName("connector"); + jg.writeString("Flowchart"); + + jg.writeFieldName("paintStyle"); + jg.writeStartObject(); + jg.writeFieldName("lineWidth"); + jg.writeNumber(this.getLineWidth()); + jg.writeFieldName("strokeStyle"); + jg.writeObject(this.getColor()); + String dash = this.getDash(); + if (!StringUtils.isEmpty(dash)) { + String dashStyle = null; + switch (dash) { + case "dotted": + dashStyle = "1 5"; + break; + case "dotted2": + dashStyle = "3 4"; + break; + case "plain": + // default works + // otherwise, "1 0" can be used + break; + } + if (dashStyle != null) { + jg.writeStringField("dashstyle", dashStyle); + } + } + jg.writeEndObject(); + + jg.writeFieldName("hoverPaintStyle"); + jg.writeStartObject(); + jg.writeFieldName("strokeStyle"); + jg.writeObject(this.getHoverColor()); + jg.writeEndObject(); + + // BEGIN: Overlays + + jg.writeFieldName("overlays"); + jg.writeStartArray(); + + // source arrow head + String head = this.getSourceArrowHead(); + if (!head.equals("none")) { + jg.writeStartArray(); + jg.writeString(head); + + jg.writeStartObject(); + + jg.writeFieldName("location"); + jg.writeNumber(0); + + // arrow should point towards the node and not away from it + jg.writeFieldName("direction"); + jg.writeNumber(-1); + + jg.writeFieldName("width"); + jg.writeNumber(20); + + jg.writeFieldName("length"); + jg.writeNumber(12); + + jg.writeEndObject(); + jg.writeEndArray(); + } + + // target arrow head + head = this.getTargetArrowHead(); + if (!head.equals("none")) { + jg.writeStartArray(); + jg.writeString(head); + jg.writeStartObject(); + jg.writeFieldName("location"); + jg.writeNumber(1); + jg.writeFieldName("width"); + jg.writeNumber(20); + jg.writeFieldName("length"); + jg.writeNumber(12); + jg.writeEndObject(); + jg.writeEndArray(); + } + + // Type in brackets on the arrow + jg.writeStartArray(); + jg.writeString("Label"); + jg.writeStartObject(); + jg.writeStringField("id", "label"); + jg.writeStringField("label", "(" + ((RelationshipTypeResource) this.res).getName() + ")"); + jg.writeStringField("cssClass", "relationshipTypeLabel"); + jg.writeFieldName("location"); + jg.writeNumber(0.5); + jg.writeEndObject(); + jg.writeEndArray(); + + jg.writeEndArray(); + + // END: Overlays + + jg.writeEndObject(); + + jg.close(); + } catch (Exception e) { + VisualAppearanceResource.logger.error(e.getMessage(), e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build(); + } + String res = sw.toString(); + return Response.ok(res).build(); + } + + private String getOtherAttributeWithDefault(QName qname, String def) { + String res = this.otherAttributes.get(qname); + if (StringUtils.isEmpty(res)) { + return def; + } else { + return res; + } + } + + /* * * source arrow head * * */ + + public String getSourceArrowHead() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_ARROWHEAD_SOURCE, Defaults.DEFAULT_RT_ARROWHEAD_SOURCE); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + @Path("sourcearrowhead") + public Response onPutSourceHead(String config) { + if (StringUtils.isEmpty(config)) { + return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build(); + } + this.otherAttributes.put(VisualAppearanceResource.QNAME_ARROWHEAD_SOURCE, config); + return BackendUtils.persist(this.res); + } + + /* * * target arrow head * * */ + + public String getTargetArrowHead() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_ARROWHEAD_TARGET, Defaults.DEFAULT_RT_ARROWHEAD_TARGET); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + @Path("targetarrowhead") + public Response onPutTargetHead(String config) { + if (StringUtils.isEmpty(config)) { + return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build(); + } + this.otherAttributes.put(VisualAppearanceResource.QNAME_ARROWHEAD_TARGET, config); + return BackendUtils.persist(this.res); + } + + /* * * + * + * stroke dash array / represents the line + * + * Attention: if a linewidth != 1 is chosen, the dash has to be multiplied somehow by the line width + * See: http://jsplumbtoolkit.com/doc/paint-styles: + * "The dashstyle attribute is specified as an array of strokes and spaces, where each value is some multiple of the width of the Connector" + * + * * * */ + + public String getDash() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_DASH, Defaults.DEFAULT_RT_DASH); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + @Path("dash") + public Response onPutDash(String config) { + if (StringUtils.isEmpty(config)) { + return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build(); + } + this.otherAttributes.put(VisualAppearanceResource.QNAME_DASH, config); + return BackendUtils.persist(this.res); + } + + /* * * stroke/line width * * */ + + public String getLineWidth() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_LINEWIDTH, Defaults.DEFAULT_RT_LINEWIDTH); + } + + /* * * color * * */ + + /** + * read by topologytemplateeditor.jsp via ${it.color} + */ + public String getColor() { + return BackendUtils.getColorAndSetDefaultIfNotExisting(this.getId().getParent().getXmlId().getDecoded(), QNames.QNAME_COLOR, this.otherAttributes, this.res); + } + + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("color") + public Response onPutColor(@FormParam("color") String color) { + this.otherAttributes.put(QNames.QNAME_COLOR, color); + return BackendUtils.persist(this.res); + } + + /** + * read by topologytemplateeditor.jsp via ${it.hoverColor} + */ + public String getHoverColor() { + return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_HOVER_COLOR, Defaults.DEFAULT_RT_HOVER_COLOR); + } + + @PUT + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("hovercolor") + public Response onPutHoverColor(@FormParam("color") String color) { + this.otherAttributes.put(VisualAppearanceResource.QNAME_HOVER_COLOR, color); + return BackendUtils.persist(this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java new file mode 100644 index 0000000..c076835 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.requirementtypes; + +import java.util.Collection; +import java.util.SortedSet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; + +import com.sun.jersey.api.NotFoundException; +import com.sun.jersey.api.view.Viewable; + +public class RequiredCapabilityTypeResource { + + private RequirementTypeResource requirementTypeResource; + + + public RequiredCapabilityTypeResource(RequirementTypeResource requirementTypeResource) { + this.requirementTypeResource = requirementTypeResource; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/entitytypes/requirementtypes/requiredcapabilitytype.jsp", this); + } + + public TRequirementType getRequirementType() { + return this.requirementTypeResource.getRequirementType(); + } + + @PUT + @Consumes(MediaType.TEXT_PLAIN) + public Response putRequiredCapabilityType(String type) { + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("type must not be empty").build(); + } + QName qname = QName.valueOf(type); + CapabilityTypeId id = new CapabilityTypeId(qname); + if (Repository.INSTANCE.exists(id)) { + // everything allright. Store new reference + this.getRequirementType().setRequiredCapabilityType(qname); + return BackendUtils.persist(this.requirementTypeResource); + } else { + throw new NotFoundException("Given QName could not be resolved to an existing capability type"); + } + } + + @DELETE + public Response deleteRequiredCapabilityType() { + this.getRequirementType().setRequiredCapabilityType(null); + return BackendUtils.persist(this.requirementTypeResource); + } + + /** required for jsp **/ + public Collection<QName> getAllCapabilityTypes() { + SortedSet<CapabilityTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(CapabilityTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java new file mode 100644 index 0000000..0f143fb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.requirementtypes; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.common.ids.definitions.RequirementTypeId; +import org.eclipse.winery.repository.resources.EntityTypeResource; + +public class RequirementTypeResource extends EntityTypeResource { + + public RequirementTypeResource(RequirementTypeId id) { + super(id); + } + + /** + * Convenience method to avoid casting at the caller's side. + */ + public TRequirementType getRequirementType() { + return (TRequirementType) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TRequirementType(); + } + + @Path("requiredcapabilitytype/") + public RequiredCapabilityTypeResource getRequiredCapabilityTypeResource() { + return new RequiredCapabilityTypeResource(this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java new file mode 100644 index 0000000..955e4fb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.requirementtypes; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages all capability types in all available namespaces <br /> + * The actual implementation is done in the AbstractComponentsResource + */ +public class RequirementTypesResource extends AbstractComponentsResource<RequirementTypeResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java new file mode 100644 index 0000000..82ff02e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.imports; + +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportsResource; +import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportsResource; + +/** + * The specification does not nest the sequence of import elements in an imports + * container. We introduce such a container to be consistent with the other + * resource naming + */ +public class ImportsResource { + + @Path("{id}/") + public AbstractComponentsResource getXSDsResource(@PathParam("id") String id) { + // once: decoding for browser locations + id = Util.URLdecode(id); + // once again: real URI + id = Util.URLdecode(id); + if (id.equals("http://www.w3.org/2001/XMLSchema")) { + // Models http://www.w3.org/2001/XMLSchema. We do not use xsd instead of the + // encoded namespace, because this induces special cases at many places + return new XSDImportsResource(); + } else { + return new GenericImportsResource(id); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java new file mode 100644 index 0000000..ddcb462 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.imports.genericimports; + +import java.util.SortedSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource; + +public class GenericImportResource extends AbstractComponentInstanceResource { + + // The import belonging to this resource + protected final TImport theImport; + + + public GenericImportResource(GenericImportId id) { + super(id); + + boolean needsPersistence = false; + + if (this.getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation().isEmpty()) { + // super class loaded an existing definitions + + // we have to manually assign our import right + this.theImport = this.getDefinitions().getImport().get(0); + + // element is not assigned as there are no service templates/... + // we assign the value to be sure that no NPEs occur + this.element = this.theImport; + } else { + // super class created a new import + + // store it locally + this.theImport = (TImport) this.element; + + // undo the side effect of adding it at the wrong place at TDefinitions + this.getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation().clear(); + + // add import at the right place + this.getDefinitions().getImport().add(this.theImport); + + // Super class has persisted the definitions + // We have to persist the new variant + needsPersistence = true; + } + + if (this.theImport.getLocation() == null) { + // invalid import -- try to synchronize with storage + + SortedSet<RepositoryFileReference> containedFiles = Repository.INSTANCE.getContainedFiles(id); + // there is also a .definitions contained + // we are only interested in the non-.definitions + for (RepositoryFileReference ref : containedFiles) { + if (!ref.getFileName().endsWith(".definitions")) { + // associated file found + // set the filename of the import to the found xsd + // TODO: no more validity checks are done currently. In the case of XSD: targetNamespace matches, not more than one xsd + this.theImport.setLocation(ref.getFileName()); + needsPersistence = true; + break; + } + } + } + + if (needsPersistence) { + BackendUtils.persist(this); + } + } + + @Override + protected TExtensibleElements createNewElement() { + throw new IllegalStateException("This should not never happen."); + } + + @Override + protected void copyIdToFields() { + // this.theImport cannot be used as this method is called by the super constructor + ((TImport) this.element).setNamespace(this.id.getNamespace().getDecoded()); + } + + @GET + @Path("{filename}") + public Response getFile(@PathParam("filename") String fileName) { + fileName = Util.URLdecode(fileName); + String location; + if ((location = this.getLocation()) == null) { + return Response.status(Status.NOT_FOUND).build(); + } + if (!location.equals(fileName)) { + return Response.status(Status.NOT_FOUND).build(); + } + RepositoryFileReference ref = new RepositoryFileReference(this.id, location); + return BackendUtils.returnRepoPath(ref, null); + + } + + public String getLocation() { + return this.theImport.getLocation(); + } + + /** + * @return a name suitable for componentnaming.jspf + */ + public String getName() { + if (this.getLocation() == null) { + return this.id.getXmlId().getDecoded(); + } else { + return this.getLocation(); + } + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java new file mode 100644 index 0000000..9117175 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.imports.genericimports; + +import org.eclipse.winery.common.ids.definitions.imports.GenericImportId; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +/** + * Manages a certain kind of imports without special treatments + */ +public class GenericImportsResource extends AbstractComponentsResource<GenericImportResource> { + + private String type; + + + /** + * @param id the (decoded) id, e.g., http://schemas.xmlsoap.org/wsdl/ + */ + public GenericImportsResource(String id) { + this.type = id; + } + + @Override + public GenericImportResource getComponentInstaceResource(String namespace, String id, boolean encoded) { + GenericImportId iId = new GenericImportId(namespace, id, encoded, this.type); + return new GenericImportResource(iId); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java new file mode 100644 index 0000000..49ea468 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.imports.xsdimports; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.XMLConstants; + +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSObject; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TImport; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * Even if we are not a component instance, we use that infrastructure to manage + * imports. Some hacks will be necessary. However, these are less effort than + * doing a clean design + */ +public class XSDImportResource extends GenericImportResource { + + private static final Logger logger = LoggerFactory.getLogger(XSDImportResource.class); + + + public XSDImportResource(XSDImportId id) { + super(id); + } + + @Override + protected TExtensibleElements createNewElement() { + TImport imp = new TImport(); + imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI); + return imp; + } + + /** + * public required by XSDImportsResource + * + * @return null if XSD file does not exist + */ + public RepositoryFileReference getXSDFileReference() { + String loc = this.getLocation(); + if (loc == null) { + return null; + } + final RepositoryFileReference ref = new RepositoryFileReference(this.id, loc); + return ref; + } + + /** + * @return null if no file is associated + */ + private XSModel getXSModel() { + final RepositoryFileReference ref = this.getXSDFileReference(); + return BackendUtils.getXSModel(ref); + } + + // we need "unchecked", because of the parsing of the cache + @SuppressWarnings("unchecked") + public Collection<String> getAllDefinedLocalNames(short type) { + RepositoryFileReference ref = this.getXSDFileReference(); + if (ref == null) { + return Collections.emptySet(); + } + Date lastUpdate = Repository.INSTANCE.getLastUpdate(ref); + + String cacheFileName = "definedLocalNames " + Integer.toString(type) + ".cache"; + RepositoryFileReference cacheRef = new RepositoryFileReference(this.id, cacheFileName); + boolean cacheNeedsUpdate = true; + if (Repository.INSTANCE.exists(cacheRef)) { + Date lastUpdateCache = Repository.INSTANCE.getLastUpdate(cacheRef); + if (lastUpdate.compareTo(lastUpdateCache) <= 0) { + cacheNeedsUpdate = false; + } + } + + List<String> result; + if (cacheNeedsUpdate) { + + XSModel model = this.getXSModel(); + if (model == null) { + return Collections.emptySet(); + } + XSNamedMap components = model.getComponents(type); + //@SuppressWarnings("unchecked") + int len = components.getLength(); + result = new ArrayList<String>(len); + for (int i = 0; i < len; i++) { + XSObject item = components.item(i); + // if queried for TYPE_DEFINITION, then XSD base types (such as IDREF) are also returned + // We want to return only types defined in the namespace of this resource + if (item.getNamespace().equals(this.id.getNamespace().getDecoded())) { + result.add(item.getName()); + } + } + + String cacheContent = null; + try { + cacheContent = Utils.mapper.writeValueAsString(result); + } catch (JsonProcessingException e) { + XSDImportResource.logger.error("Could not generate cache content", e); + } + try { + Repository.INSTANCE.putContentToFile(cacheRef, cacheContent, MediaType.APPLICATION_JSON_TYPE); + } catch (IOException e) { + XSDImportResource.logger.error("Could not update cache", e); + } + } else { + // read content from cache + // cache should contain most recent information + try (InputStream is = Repository.INSTANCE.newInputStream(cacheRef)) { + result = Utils.mapper.readValue(is, java.util.List.class); + } catch (IOException e) { + XSDImportResource.logger.error("Could not read from cache", e); + result = Collections.emptyList(); + } + } + return result; + } + + public Collection<String> getAllDefinedElementsLocalNames() { + return this.getAllDefinedLocalNames(XSConstants.ELEMENT_DECLARATION); + } + + public Collection<String> getAllDefinedTypesLocalNames() { + return this.getAllDefinedLocalNames(XSConstants.TYPE_DEFINITION); + } + + @GET + @RestDoc(methodDescription = "May be used by the modeler to generate an XML editor based on the XML schema") + // we cannot use "MimeTypes.MIMETYPE_XSD" here as the latter is "text/xml" and org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsAsResponse() also produces text/xml + @Produces("text/xsd") + public Response getXSD() { + String location; + if ((location = this.getLocation()) == null) { + return Response.status(Status.NOT_FOUND).build(); + } + RepositoryFileReference ref = new RepositoryFileReference(this.id, location); + return BackendUtils.returnRepoPath(ref, null); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java new file mode 100644 index 0000000..61af3bd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.imports.xsdimports; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.definitions.imports.XSDImportId; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; +import org.restdoc.annotations.RestDoc; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/** + * Manages all imports of type XML Schema Definition <br /> + * The actual implementation is done in the AbstractComponentsResource + * + * FIXME: This class should be generalized to handle ImportId + */ +public class XSDImportsResource extends AbstractComponentsResource<XSDImportResource> { + + @Path("{namespace}/") + @GET + @RestDoc(methodDescription = "Returns all available local names of defined elements in this namespace") + @Produces(MediaType.APPLICATION_JSON) + public String getAllElementLocalNames(@PathParam("namespace") String nsString, @QueryParam(value = "elements") String returnElements, @QueryParam(value = "types") String returnTypes) { + // returnElements is not read as either types or elements may be read + Set<String> allNCNames = this.getAllElementLocalNamesAsSet(nsString, returnTypes != null); + try { + return Utils.mapper.writeValueAsString(allNCNames); + } catch (JsonProcessingException e) { + throw new IllegalStateException(e); + } + } + + /** + * @param nsString the namesapce as String + * @param returnTypes true: return ElementTypes, false: return Elements + */ + private Set<String> getAllElementLocalNamesAsSet(final String nsString, final boolean getTypes) { + Set<XSDImportId> importsOfNS = this.getImportsOfNS(nsString); + + // TreeSet enables ordering + Set<String> allNCNames = new TreeSet<String>(); + + for (XSDImportId imp : importsOfNS) { + XSDImportResource res = new XSDImportResource(imp); + Collection<String> col; + if (getTypes) { + col = res.getAllDefinedTypesLocalNames(); + } else { + col = res.getAllDefinedElementsLocalNames(); + } + allNCNames.addAll(col); + } + return allNCNames; + } + + /** + * Finds out all imports belonging to the given namespace + * + * @param nsString the namespace to query + */ + private Set<XSDImportId> getImportsOfNS(final String nsString) { + // FIXME: Currently not supported by the repository, therefore, we filter by hand + Set<XSDImportId> allImports = Repository.INSTANCE.getAllTOSCAComponentIds(XSDImportId.class); + Namespace ns = new Namespace(nsString, true); + Set<XSDImportId> importsOfNs = new HashSet<XSDImportId>(); + for (XSDImportId imp : allImports) { + if (imp.getNamespace().equals(ns)) { + importsOfNs.add(imp); + } + } + return importsOfNs; + } + + /** + * Returns a mapping from localnames to XSD files, containing the defined + * local names for the given namespace + */ + public Map<String, RepositoryFileReference> getMapFromLocalNameToXSD(final String nsString, final boolean getTypes) { + Set<XSDImportId> importsOfNS = this.getImportsOfNS(nsString); + Map<String, RepositoryFileReference> result = new HashMap<>(); + for (XSDImportId imp : importsOfNS) { + XSDImportResource res = new XSDImportResource(imp); + Collection<String> col; + if (getTypes) { + col = res.getAllDefinedTypesLocalNames(); + } else { + col = res.getAllDefinedElementsLocalNames(); + } + RepositoryFileReference ref = res.getXSDFileReference(); + for (String localName : col) { + result.put(localName, ref); + } + } + return result; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java new file mode 100644 index 0000000..b7b7c15 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.interfaces; + +import java.util.List; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class InterfaceResource extends EntityWithIdResource<TInterface> { + + private final TInterface iface; + + + public InterfaceResource(IIdDetermination<TInterface> idDetermination, TInterface o, int idx, List<TInterface> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + this.iface = o; + } + + /** + * required by artifacts.jsp + */ + public String getName() { + return this.iface.getName(); + } + + @Path("operations/") + public OperationsResource getOperationsResouce() { + List<TOperation> list = this.o.getOperation(); + return new OperationsResource(list, this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java new file mode 100644 index 0000000..4acfbd9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.interfaces; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource; +import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class InterfacesResource extends EntityWithIdCollectionResource<InterfaceResource, TInterface> { + + private static final Logger logger = LoggerFactory.getLogger(InterfacesResource.class); + + private TopologyGraphElementEntityTypeResource typeResource; + + private String urlPrefix; + + + public InterfacesResource(IPersistable res, List<TInterface> list) { + super(InterfaceResource.class, TInterface.class, list, res); + } + + /** + * @param urlPrefix prefix to be prepended to the URL. + * "source"|"target"|null. E.g., "source" for "sourceinterfaces" + */ + public InterfacesResource(String urlPrefix, List<TInterface> list, IPersistable typeResource) { + super(InterfaceResource.class, TInterface.class, list, typeResource); + this.urlPrefix = urlPrefix; + this.typeResource = (TopologyGraphElementEntityTypeResource) typeResource; + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/interfaces/interfaces.jsp", this); + } + + /** + * Implementation base: <br /> + * {@link org.eclipse.winery.repository.resources.AbstractComponentResource. + * onPost(String)} + * + * @return entity: id of the stored interface + */ + @POST + @RestDoc(methodDescription = "Creates a new interface. Returns conflict if interface already exists") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response onPost(@FormParam("interfaceName") String interfaceName) { + if (StringUtils.isEmpty(interfaceName)) { + return Response.status(Status.BAD_REQUEST).entity("null interfaceName").build(); + } + + TInterface iface = new TInterface(); + iface.setName(interfaceName); + + // check for duplicates + // return "conflict" if interface already exists + if (this.alreadyContains(iface)) { + return Response.status(Status.CONFLICT).build(); + } + + this.list.add(iface); + return BackendUtils.persist(this.res); + } + + /** + * Required by interfaces.jsp + */ + public String getUrlPrefix() { + return this.urlPrefix; + } + + @Override + public String getId(TInterface entity) { + return entity.getName(); + } + + /** + * @return the namespace of the node/relationship type + */ + public String getNamespace() { + return this.typeResource.getId().getNamespace().getDecoded(); + } + + /** + * @return the name of the node/relationship type + */ + public String getName() { + return this.typeResource.getName(); + } + + public String getRelationshipTypeOrNodeTypeURLFragment() { + if (this.typeResource instanceof RelationshipTypeResource) { + return "relationshiptype"; + } else { + return "nodetype"; + } + } + + public String getRelationshipTypeOrNodeType() { + if (this.typeResource instanceof RelationshipTypeResource) { + return "Relationship Type"; + } else { + return "Node Type"; + } + } + + public String getTypeQName() { + String res = this.typeResource.getId().getQName().toString(); + return res; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java new file mode 100644 index 0000000..7657e99 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.interfaces; + +import java.util.List; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TInterface; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.model.tosca.TOperation.InputParameters; +import org.eclipse.winery.model.tosca.TOperation.OutputParameters; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OperationResource extends EntityWithIdResource<TOperation> { + + private static final Logger logger = LoggerFactory.getLogger(OperationResource.class); + + + public OperationResource(IIdDetermination<TOperation> idDetermination, TOperation o, int idx, List<TOperation> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + /** + * @return TOperation object for the corresponding object of operationName + * in the operation list contained in the given interface. null if + * interface could not be found in list + */ + public static TOperation getTOperation(String operationName, TInterface iface) { + List<TOperation> operationList = iface.getOperation(); + for (TOperation op : operationList) { + if (op.getName().equals(operationName)) { + return op; + } + } + return null; + } + + @Path("inputparameters/") + public ParametersResource getInputparameters() { + InputParameters inputParameters = this.o.getInputParameters(); + if (inputParameters == null) { + inputParameters = new InputParameters(); + this.o.setInputParameters(inputParameters); + } + return new ParametersResource(inputParameters.getInputParameter(), this.res); + } + + @Path("outputparameters/") + public ParametersResource getOutputparameters() { + OutputParameters outputParameters = this.o.getOutputParameters(); + if (outputParameters == null) { + outputParameters = new OutputParameters(); + this.o.setOutputParameters(outputParameters); + } + return new ParametersResource(outputParameters.getOutputParameter(), this.res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java new file mode 100644 index 0000000..3e214e4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.interfaces; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.tosca.TOperation; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.restdoc.annotations.RestDocParam; + +import com.sun.jersey.api.view.Viewable; + +public class OperationsResource extends EntityWithIdCollectionResource<OperationResource, TOperation> { + + public OperationsResource(List<TOperation> list, IPersistable res) { + super(OperationResource.class, TOperation.class, list, res); + } + + @Override + public String getId(TOperation entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public Response createOperation(@FormParam("name") @RestDocParam(description = "used as name and id") String operationName) { + if (StringUtils.isEmpty(operationName)) { + return Response.status(Status.BAD_REQUEST).entity("operationName not provided").build(); + } + + operationName = Util.URLdecode(operationName); + + // TODO: check for duplicates as in instance states + + TOperation operation = new TOperation(); + operation.setName(operationName); + this.list.add(operation); + + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java new file mode 100644 index 0000000..46662fd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.interfaces; + +import java.util.List; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TParameter; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class ParameterResource extends EntityWithIdResource<TParameter> { + + public ParameterResource(IIdDetermination<TParameter> idDetermination, TParameter o, int idx, List<TParameter> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @GET + @Path("type") + public String getType() { + return this.o.getType(); + } + + @PUT + @Path("type") + public Response putType(@FormParam(value = "type") String type) { + this.o.setType(type); + return BackendUtils.persist(this.res); + } + + @GET + @Path("required") + public String getRequired() { + return this.o.getRequired().toString(); + } + + @PUT + @Path("required") + public Response putRequired(@FormParam(value = "required") String required) { + TBoolean tb = TBoolean.valueOf(required); + this.o.setRequired(tb); + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java new file mode 100644 index 0000000..c3afcbc --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.interfaces; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.tosca.TBoolean; +import org.eclipse.winery.model.tosca.TParameter; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class ParametersResource extends EntityWithIdCollectionResource<ParameterResource, TParameter> { + + private static final Logger logger = LoggerFactory.getLogger(ParametersResource.class); + + + public ParametersResource(List<TParameter> parameters, IPersistable typeResource) { + super(ParameterResource.class, TParameter.class, parameters, typeResource); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + // @formatter:off + public Response createParamter( + @FormParam("name") String name, + @FormParam("type") String type, + @FormParam("required") @RestDocParam(description="type tYesNo, not Boolean. For convenience, on/off is also supported. In case this parameter is not provided, 'off' is assumed. This is in contrast to the specification, but it eases implementing the UI") String required) { + // @formatter:on + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("name must not be null").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("type must not be null").build(); + } + + TParameter param = new TParameter(); + param.setName(name); + param.setType(type); + TBoolean tb; + if (required == null) { + // The specification states that the default value is "yes" + // We assume "no", because Chrome does not send the checkbox data if a checkbox is not checked + tb = TBoolean.NO; + } else { + if (required.equalsIgnoreCase("on")) { + tb = TBoolean.YES; + } else if (required.equalsIgnoreCase("off")) { + tb = TBoolean.NO; + } else { + try { + tb = TBoolean.valueOf(required); + } catch (java.lang.IllegalArgumentException e) { + return Response.status(Status.BAD_REQUEST).entity("Wrong format of required").build(); + } + } + } + param.setRequired(tb); + + this.list.add(param); + + return BackendUtils.persist(this.res); + } + + @Override + public String getId(TParameter entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java new file mode 100644 index 0000000..ea94a21 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +/** + * This package contains the REST resources + * + * Mostly, they produces Viewables, where a JSP and the current resource is + * passed As the JSP itself handles plain Java objects and not Responses, the + * resources have also methods returning POJOs. This might be ugly design, but + * was quick to implement. + * + * The package structure is mirrored in src/main/webapp/jsp to ease finding the + * JSPs belonging to a resource. + * + * The resources are <em>not</em> in line with the resource model of the TOSCA + * container. Especially, we do not employ HATEOAS here. + */ +package org.eclipse.winery.repository.resources; + diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java new file mode 100644 index 0000000..6a249df --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.common.ids.elements.PlansId; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TExtensibleElements; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.PlanModelReference; +import org.eclipse.winery.model.tosca.TPlans; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.AbstractComponentInstanceWithReferencesResource; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.BoundaryDefinitionsResource; +import org.eclipse.winery.repository.resources.servicetemplates.plans.PlansResource; +import org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal.SelfServicePortalResource; +import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.TopologyTemplateResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ServiceTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IHasName { + + private static final Logger logger = LoggerFactory.getLogger(ServiceTemplateResource.class); + + + public ServiceTemplateResource(ServiceTemplateId id) { + super(id); + } + + /** sub-resources **/ + + @Path("topologytemplate/") + public TopologyTemplateResource getTopologyTemplateResource() { + if (this.getServiceTemplate().getTopologyTemplate() == null) { + // the main service template resource exists + // default topology template: empty template + // This eases the JSPs etc. and is valid as a non-existant topology template is equal to an empty one + this.getServiceTemplate().setTopologyTemplate(new TTopologyTemplate()); + } + return new TopologyTemplateResource(this); + } + + @Path("plans/") + public PlansResource getPlansResource() { + TPlans plans = this.getServiceTemplate().getPlans(); + if (plans == null) { + plans = new TPlans(); + this.getServiceTemplate().setPlans(plans); + } + return new PlansResource(plans.getPlan(), this); + } + + @Path("selfserviceportal/") + public SelfServicePortalResource getSelfServicePortalResource() { + return new SelfServicePortalResource(this); + } + + @Path("boundarydefinitions/") + public BoundaryDefinitionsResource getBoundaryDefinitionsResource() { + TBoundaryDefinitions boundaryDefinitions = this.getServiceTemplate().getBoundaryDefinitions(); + if (boundaryDefinitions == null) { + boundaryDefinitions = new TBoundaryDefinitions(); + this.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions); + } + return new BoundaryDefinitionsResource(this, boundaryDefinitions); + } + + @Override + public String getName() { + String name = this.getServiceTemplate().getName(); + if (name == null) { + // place default + name = this.getId().getXmlId().getDecoded(); + } + return name; + } + + @Override + public Response setName(String name) { + this.getServiceTemplate().setName(name); + return BackendUtils.persist(this); + } + + // @formatter:off + @GET + @RestDoc(methodDescription="Returns the associated node type, which can be substituted by this service template.<br />" + + "@return a QName of the form {namespace}localName is returned.") + @Path("substitutableNodeType") + @Produces(MediaType.TEXT_PLAIN) + // @formatter:on + public Response getSubstitutableNodeTypeAsResponse() { + QName qname = this.getServiceTemplate().getSubstitutableNodeType(); + if (qname == null) { + return Response.status(Status.NOT_FOUND).build(); + } else { + return Response.ok(qname.toString()).build(); + } + } + + /** + * + * @return null if there is no substitutable node type + */ + public QName getSubstitutableNodeType() { + return this.getServiceTemplate().getSubstitutableNodeType(); + } + + @DELETE + @RestDoc(methodDescription = "Removes the association to substitutable node type") + @Path("substitutableNodeType") + public Response deleteSubstitutableNodeType() { + this.getServiceTemplate().setSubstitutableNodeType(null); + BackendUtils.persist(this); + return Response.noContent().build(); + } + + public TServiceTemplate getServiceTemplate() { + return (TServiceTemplate) this.getElement(); + } + + @Override + protected TExtensibleElements createNewElement() { + return new TServiceTemplate(); + } + + @Override + protected void copyIdToFields() { + this.getServiceTemplate().setId(this.getId().getXmlId().getDecoded()); + this.getServiceTemplate().setTargetNamespace(this.getId().getNamespace().getDecoded()); + } + + /** + * Synchronizes the known plans with the data in the XML. When there is a + * stored file, but no known entry in the XML, we guess "BPEL" as language + * and "build plan" as type. + * + * @throws IOException + */ + @Override + public void synchronizeReferences() { + // locally stored plans + TPlans plans = this.getServiceTemplate().getPlans(); + + // plans stored in the repository + PlansId plansContainerId = new PlansId((ServiceTemplateId) this.getId()); + SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class); + + Set<PlanId> plansToAdd = new HashSet<PlanId>(); + plansToAdd.addAll(nestedPlans); + + if (nestedPlans.isEmpty()) { + if (plans == null) { + // data on the file system equals the data -> no plans + return; + } else { + // we have to check for equality later + } + } + + if (plans == null) { + plans = new TPlans(); + this.getServiceTemplate().setPlans(plans); + } + + for (Iterator<TPlan> iterator = plans.getPlan().iterator(); iterator.hasNext();) { + TPlan plan = iterator.next(); + if (plan.getPlanModel() != null) { + // in case, a plan is directly contained in a Model element, we do not need to do anything + continue; + } + PlanModelReference planModelReference = plan.getPlanModelReference(); + if ((planModelReference = plan.getPlanModelReference()) != null) { + String ref = planModelReference.getReference(); + if ((ref == null) || ref.startsWith("../")) { + // references to local plans start with "../" + // special case (due to errors in the importer): empty PlanModelReference field + if (plan.getId() == null) { + // invalid plan entry: no id. + // we remove the entry + iterator.remove(); + continue; + } + PlanId planId = new PlanId(plansContainerId, new XMLId(plan.getId(), false)); + if (nestedPlans.contains(planId)) { + // everything allright + // we do NOT need to add the plan on the HDD to the XML + plansToAdd.remove(planId); + } else { + // no local storage for the plan, we remove it from the XML + iterator.remove(); + } + } + } + } + + // add all plans locally stored, but not contained in the XML, as plan element to the plans of the service template. + List<TPlan> thePlans = plans.getPlan(); + for (PlanId planId : plansToAdd) { + SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(planId); + if (files.size() != 1) { + throw new IllegalStateException("Currently, only one file per plan is supported."); + } + RepositoryFileReference ref = files.iterator().next(); + + TPlan plan = new TPlan(); + plan.setId(planId.getXmlId().getDecoded()); + plan.setName(planId.getXmlId().getDecoded()); + plan.setPlanType(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN); + plan.setPlanLanguage(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE); + + // create a PlanModelReferenceElement pointing to that file + String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref)); + // path is relative from the definitions element + path = "../" + path; + PlanModelReference pref = new PlanModelReference(); + pref.setReference(path); + + plan.setPlanModelReference(pref); + thePlans.add(plan); + } + + try { + this.persist(); + } catch (IOException e) { + throw new IllegalStateException("Could not persist resource", e); + } + return; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java new file mode 100644 index 0000000..fd8b82c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates; + +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class ServiceTemplatesResource extends AbstractComponentsResource<ServiceTemplateResource> { + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java new file mode 100644 index 0000000..0d4b141 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java @@ -0,0 +1,113 @@ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.SortedSet; + +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.taglibs.standard.functions.Functions; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.ids.definitions.PolicyTypeId; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlans; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.TypeWithShortName; +import org.eclipse.winery.repository.datatypes.select2.Select2DataItem; +import org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager; + +public class BoundaryDefinitionsJSPData { + + private final TServiceTemplate ste; + private final TBoundaryDefinitions defs; + private URI baseURI; + + + /** + * + * @param ste the service template of the boundary definitions. Required to + * get a list of all plans + * @param baseURI the base URI of the service. Requried for rendering the + * topology template for the selections + */ + public BoundaryDefinitionsJSPData(TServiceTemplate ste, URI baseURI) { + this.ste = ste; + this.defs = ste.getBoundaryDefinitions(); + this.baseURI = baseURI; + } + + private String getDefinedProperties() { + Properties p = ModelUtilities.getProperties(this.defs); + Object o = p.getAny(); + if (o == null) { + // nothing stored -> return empty string + return ""; + } else { + // something stored --> return that + return Utils.getXMLAsString(p.getAny()); + } + } + + /** + * Helper method to return an initialized properties object only containing + * the user-defined properties. The TOSCA properties-element is not returned + * as the TOSCA XSD allows a single element only + */ + public String getDefinedPropertiesAsEscapedHTML() { + String s = this.getDefinedProperties(); + s = StringEscapeUtils.escapeHtml4(s); + return s; + } + + public String getDefinedPropertiesAsJSONString() { + String s = this.getDefinedProperties(); + s = StringEscapeUtils.escapeEcmaScript(s); + return s; + } + + public TBoundaryDefinitions getDefs() { + return this.defs; + } + + public String getBoundaryDefinitionsAsXMLStringEncoded() { + String res = Utils.getXMLAsString(this.defs); + return Functions.escapeXml(res); + } + + public Collection<TypeWithShortName> getConstraintTypes() { + return ConstraintTypesManager.INSTANCE.getTypes(); + } + + public Collection<QName> getAllPolicyTypes() { + SortedSet<PolicyTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(PolicyTypeId.class); + return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds); + } + + public String getRepositoryURL() { + return this.baseURI.toString(); + } + + public List<Select2DataItem> getlistOfAllPlans() { + TPlans plans = this.ste.getPlans(); + if (plans == null) { + return null; + } else { + List<Select2DataItem> res = new ArrayList<>(plans.getPlan().size()); + for (TPlan plan : plans.getPlan()) { + String id = plan.getId(); + String name = ModelUtilities.getNameWithIdFallBack(plan); + Select2DataItem di = new Select2DataItem(id, name); + res.add(di); + } + return res; + } + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java new file mode 100644 index 0000000..58dfbe9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Capabilities; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Interfaces; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Policies; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties.PropertyMappings; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Requirements; +import org.eclipse.winery.model.tosca.TCapabilityRef; +import org.eclipse.winery.model.tosca.TRequirementRef; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces.InterfacesResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies.PoliciesResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.CapabilitiesResource; +import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.w3c.dom.Document; + +import com.sun.jersey.api.view.Viewable; + +public class BoundaryDefinitionsResource { + + private final ServiceTemplateResource serviceTemplateResource; + private final TBoundaryDefinitions boundaryDefinitions; + + + public BoundaryDefinitionsResource(ServiceTemplateResource serviceTemplateResource, TBoundaryDefinitions boundaryDefinitions) { + this.serviceTemplateResource = serviceTemplateResource; + this.boundaryDefinitions = boundaryDefinitions; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML(@Context UriInfo uriInfo) { + return new Viewable("/jsp/servicetemplates/boundarydefinitions/boundarydefinitions.jsp", new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri())); + } + + @PUT + @RestDoc(methodDescription = "Replaces the boundary definitions by the information given in the XML") + @Consumes(MediaType.TEXT_XML) + public Response setModel(TBoundaryDefinitions boundaryDefinitions) { + this.serviceTemplateResource.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions); + return BackendUtils.persist(this.serviceTemplateResource); + } + + @Path("properties/") + @PUT + @Consumes(MediaType.TEXT_XML) + @RestDoc(resourceDescription = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.") + public Response putProperties(@RestDocParam(description = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Document doc) { + org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties properties = ModelUtilities.getProperties(this.boundaryDefinitions); + properties.setAny(doc.getDocumentElement()); + return BackendUtils.persist(this.serviceTemplateResource); + } + + @Path("requirements/") + public RequirementsResource getRequiremensResource() { + Requirements requirements = this.boundaryDefinitions.getRequirements(); + if (requirements == null) { + requirements = new Requirements(); + this.boundaryDefinitions.setRequirements(requirements); + } + List<TRequirementRef> refs = requirements.getRequirement(); + return new RequirementsResource(this.serviceTemplateResource, refs); + } + + @Path("capabilities/") + public CapabilitiesResource getCapabilitiesResource() { + Capabilities caps = this.boundaryDefinitions.getCapabilities(); + if (caps == null) { + caps = new Capabilities(); + this.boundaryDefinitions.setCapabilities(caps); + } + List<TCapabilityRef> refs = caps.getCapability(); + return new CapabilitiesResource(this.serviceTemplateResource, refs); + } + + @Path("policies/") + public PoliciesResource getPoliciesResource() { + Policies policies = this.boundaryDefinitions.getPolicies(); + if (policies == null) { + policies = new Policies(); + this.boundaryDefinitions.setPolicies(policies); + } + return new PoliciesResource(policies.getPolicy(), this.serviceTemplateResource); + } + + /** + * This path is below "boundary definitions" to ease implementation If it + * was modeled following the XSD, it would have been nested below + * "properties". We did not do that + */ + @Path("propertymappings/") + public PropertyMappingsResource getPropertyMappings() { + Properties properties = this.boundaryDefinitions.getProperties(); + if (properties == null) { + properties = new Properties(); + this.boundaryDefinitions.setProperties(properties); + } + PropertyMappings propertyMappings = properties.getPropertyMappings(); + if (propertyMappings == null) { + propertyMappings = new PropertyMappings(); + properties.setPropertyMappings(propertyMappings); + } + return new PropertyMappingsResource(propertyMappings, this.serviceTemplateResource); + } + + @Path("interfaces/") + public InterfacesResource getInterfacesResource() { + Interfaces interfaces = this.boundaryDefinitions.getInterfaces(); + if (interfaces == null) { + interfaces = new Interfaces(); + this.boundaryDefinitions.setInterfaces(interfaces); + } + return new InterfacesResource(interfaces.getInterface(), this.serviceTemplateResource); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java new file mode 100644 index 0000000..a6872e0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions; + +import java.util.Iterator; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties.PropertyMappings; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TPropertyMapping; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; + +public class PropertyMappingsResource { + + private final PropertyMappings propertyMappings; + private final ServiceTemplateResource res; + + + public PropertyMappingsResource(PropertyMappings propertyMappings, ServiceTemplateResource res) { + this.propertyMappings = propertyMappings; + this.res = res; + } + + @Path("{serviceTemplatePropertyRef}") + @DELETE + public Response onDelete(@PathParam("serviceTemplatePropertyRef") String serviceTemplatePropertyRef) { + serviceTemplatePropertyRef = Util.URLdecode(serviceTemplatePropertyRef); + Iterator<TPropertyMapping> iterator = this.propertyMappings.getPropertyMapping().iterator(); + while (iterator.hasNext()) { + TPropertyMapping propertyMapping = iterator.next(); + if (propertyMapping.getServiceTemplatePropertyRef().equals(serviceTemplatePropertyRef)) { + iterator.remove(); + return BackendUtils.persist(this.res); + } + } + // if the property mapping was not found, we reach this point + // otherwise "iterator.remove()" has called and the resource persisted + return Response.status(Status.NOT_FOUND).build(); + } + + private void updatePropertyMapping(TPropertyMapping propertyMapping, String serviceTemplatePropertyRef, TEntityTemplate template, String targetPropertyRef) { + propertyMapping.setServiceTemplatePropertyRef(serviceTemplatePropertyRef); + propertyMapping.setTargetObjectRef(template); + propertyMapping.setTargetPropertyRef(targetPropertyRef); + } + + @RestDoc(methodDescription = "Creates or updates a property mapping with the given fields") + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + // @formatter:off + public Response onPost( + @FormParam("serviceTemplatePropertyRef") String serviceTemplatePropertyRef, + @FormParam("targetObjectRef") String targetObjectRef, + @FormParam("targetPropertyRef") String targetPropertyRef + ) { + // @formatter:on + if (StringUtils.isEmpty(serviceTemplatePropertyRef)) { + return Response.status(Status.BAD_REQUEST).entity("serviceTemplatePropertyRef must not be empty").build(); + } + if (StringUtils.isEmpty(targetObjectRef)) { + return Response.status(Status.BAD_REQUEST).entity("targetObjectRef must not be empty").build(); + } + if (StringUtils.isEmpty(targetPropertyRef)) { + return Response.status(Status.BAD_REQUEST).entity("targetPropertyRef must not be empty").build(); + } + + TEntityTemplate template = ModelUtilities.findNodeTemplateOrRequirementOfNodeTemplateOrCapabilityOfNodeTemplateOrRelationshipTemplate(this.res.getServiceTemplate().getTopologyTemplate(), targetObjectRef); + if (template == null) { + return Response.status(Status.BAD_REQUEST).entity("targetObjectRef " + targetObjectRef + " could not be resolved.").build(); + } + + // replace propertyMapping if it exists + Iterator<TPropertyMapping> iterator = this.propertyMappings.getPropertyMapping().iterator(); + while (iterator.hasNext()) { + TPropertyMapping propertyMapping = iterator.next(); + if (propertyMapping.getServiceTemplatePropertyRef().equals(serviceTemplatePropertyRef)) { + // we found a property with the same mapping + // just update it ... + this.updatePropertyMapping(propertyMapping, serviceTemplatePropertyRef, template, targetPropertyRef); + // ... and finish processing + return BackendUtils.persist(this.res); + } + } + + // the property mapping didn't exist, + // we create a new one + TPropertyMapping newPropertyMapping = new TPropertyMapping(); + this.updatePropertyMapping(newPropertyMapping, serviceTemplatePropertyRef, template, targetPropertyRef); + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java new file mode 100644 index 0000000..b69e802 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces; + +import java.util.List; + +import javax.ws.rs.Path; + +import org.eclipse.winery.model.tosca.TExportedInterface; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; + +public class ExportedInterfaceResource extends EntityWithIdResource<TExportedInterface> { + + public ExportedInterfaceResource(IIdDetermination<TExportedInterface> idDetermination, TExportedInterface o, int idx, List<TExportedInterface> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @Path("exportedoperations/") + public ExportedOperationsResource getExportedOperationsResource() { + return new ExportedOperationsResource(this.o.getOperation(), this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java new file mode 100644 index 0000000..dd10751 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces; + +import java.io.StringWriter; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TExportedOperation; +import org.eclipse.winery.model.tosca.TExportedOperation.NodeOperation; +import org.eclipse.winery.model.tosca.TExportedOperation.Plan; +import org.eclipse.winery.model.tosca.TExportedOperation.RelationshipOperation; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; + +public class ExportedOperationResource extends EntityWithIdResource<TExportedOperation> { + + private static final Logger logger = LoggerFactory.getLogger(ExportedOperationResource.class); + + + public ExportedOperationResource(IIdDetermination<TExportedOperation> idDetermination, TExportedOperation o, int idx, List<TExportedOperation> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public String getJSONRepresentation() { + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + try { + JsonGenerator jg = jsonFactory.createGenerator(sw); + jg.writeStartObject(); + String type = this.getType(); + jg.writeStringField("type", type); + jg.writeStringField("ref", this.getReference()); + if ((type != null) && (!type.equals("Plan"))) { + jg.writeStringField("interfacename", this.getInterfaceName()); + jg.writeStringField("operationname", this.getOperationName()); + } + jg.writeEndObject(); + jg.close(); + } catch (Exception e) { + ExportedOperationResource.logger.error(e.getMessage(), e); + throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build()); + } + String res = sw.toString(); + return res; + } + + /** + * + * @return "NodeOperation" | "RelationshipOperation" | "Plan" | null. null + * is returned if no type is set + */ + @Path("type") + @GET + public String getType() { + if (this.o.getNodeOperation() != null) { + return "NodeOperation"; + } else if (this.o.getRelationshipOperation() != null) { + return "RelationshipOperation"; + } else if (this.o.getPlan() != null) { + return "Plan"; + } else { + return null; + } + } + + @Path("type") + @PUT + public Response setType(String type) { + switch (type) { + case "NodeOperation": + if (this.o.getNodeOperation() == null) { + // only do something, if the type is really changed + this.o.setRelationshipOperation(null); + this.o.setPlan(null); + NodeOperation no = new NodeOperation(); + this.o.setNodeOperation(no); + } + break; + case "RelationshipOperation": + if (this.o.getRelationshipOperation() == null) { + // only do something, if the type is really changed + this.o.setNodeOperation(null); + this.o.setPlan(null); + RelationshipOperation ro = new RelationshipOperation(); + this.o.setRelationshipOperation(ro); + } + break; + case "Plan": + if (this.o.getPlan() == null) { + // only do something, if the type is really changed + this.o.setNodeOperation(null); + this.o.setRelationshipOperation(null); + Plan plan = new Plan(); + this.o.setPlan(plan); + } + break; + default: + return Response.status(Status.BAD_REQUEST).entity("Unknown type " + type).build(); + } + return BackendUtils.persist(this.res); + } + + /** + * @return null if no reference is set + */ + @Path("ref") + @GET + public String getReference() { + if (this.o.getNodeOperation() != null) { + TNodeTemplate nt = (TNodeTemplate) this.o.getNodeOperation().getNodeRef(); + if (nt == null) { + return null; + } + return nt.getId(); + } else if (this.o.getRelationshipOperation() != null) { + TRelationshipTemplate rt = (TRelationshipTemplate) this.o.getRelationshipOperation().getRelationshipRef(); + if (rt == null) { + return null; + } + return rt.getId(); + } else if (this.o.getPlan() != null) { + TPlan plan = (TPlan) this.o.getPlan().getPlanRef(); + if (plan == null) { + return null; + } + return plan.getId(); + } else { + // no type set -> no reference can be returned + return null; + } + } + + @Path("ref") + @PUT + public Response setReference(String ref) { + TServiceTemplate ste = ((ServiceTemplateResource) this.res).getServiceTemplate(); + + // we assume that a correctly set type also means that getX (getNodeOperation, ...) returns non null + switch (this.getType()) { + case "NodeOperation": + TNodeTemplate nodeTemplate = ModelUtilities.resolveNodeTemplate(ste, ref); + this.o.getNodeOperation().setNodeRef(nodeTemplate); + break; + case "RelationshipOperation": + TRelationshipTemplate relationshipTemplate = ModelUtilities.resolveRelationshipTemplate(ste, ref); + this.o.getRelationshipOperation().setRelationshipRef(relationshipTemplate); + break; + case "Plan": + TPlan plan = ModelUtilities.resolvePlan(ste, ref); + this.o.getPlan().setPlanRef(plan); + break; + default: + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unknown type " + this.getType()).build(); + } + return BackendUtils.persist(this.res); + } + + @Path("interfacename") + @GET + public String getInterfaceName() { + if (this.o.getNodeOperation() != null) { + return this.o.getNodeOperation().getInterfaceName(); + } else if (this.o.getRelationshipOperation() != null) { + return this.o.getRelationshipOperation().getInterfaceName(); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an interface").build()); + } else { + throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unsupported state of ExportedOperation").build()); + } + } + + @Path("interfacename") + @PUT + public Response setInterfaceName(String interfacename) { + if (this.o.getNodeOperation() != null) { + this.o.getNodeOperation().setInterfaceName(interfacename); + } else if (this.o.getRelationshipOperation() != null) { + this.o.getRelationshipOperation().setInterfaceName(interfacename); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an interface").build()); + } else { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("No type set").build()); + } + return BackendUtils.persist(this.res); + } + + @Path("operationname") + @GET + public String getOperationName() { + if (this.o.getNodeOperation() != null) { + return this.o.getNodeOperation().getOperationName(); + } else if (this.o.getRelationshipOperation() != null) { + return this.o.getRelationshipOperation().getOperationName(); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an operation").build()); + } else { + throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unsupported state of ExportedOperation").build()); + } + } + + @Path("operationname") + @PUT + public Response setOperationName(String name) { + if (this.o.getNodeOperation() != null) { + this.o.getNodeOperation().setOperationName(name); + } else if (this.o.getRelationshipOperation() != null) { + this.o.getRelationshipOperation().setOperationName(name); + } else if (this.o.getPlan() != null) { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an operation").build()); + } else { + throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("No type set").build()); + } + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java new file mode 100644 index 0000000..d8788fd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TExportedOperation; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +public class ExportedOperationsResource extends EntityWithIdCollectionResource<ExportedOperationResource, TExportedOperation> { + + public ExportedOperationsResource(List<TExportedOperation> list, IPersistable res) { + super(ExportedOperationResource.class, TExportedOperation.class, list, res); + } + + @Override + public String getId(TExportedOperation entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("No implementation required: boundarydefinitions.jsp contains all required html."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java new file mode 100644 index 0000000..301f457 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TExportedInterface; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +public class InterfacesResource extends EntityWithIdCollectionResource<ExportedInterfaceResource, TExportedInterface> { + + public InterfacesResource(List<TExportedInterface> list, IPersistable res) { + super(ExportedInterfaceResource.class, TExportedInterface.class, list, res); + } + + @Override + public String getId(TExportedInterface entity) { + return entity.getName(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("No implementation required: boundarydefinitions.jsp contains all required html."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java new file mode 100644 index 0000000..6a342ea --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +/** + * This package models exported interfaces nested in a boundary definitions. + */ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java new file mode 100644 index 0000000..b18341f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies; + +import java.util.List; + +import javax.ws.rs.PUT; +import javax.ws.rs.core.Response; + +import org.eclipse.winery.model.tosca.TPolicy; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; + +import com.sun.jersey.api.view.Viewable; + +public class PoliciesResource extends EntityWithoutIdCollectionResource<PolicyResource, TPolicy> { + + public PoliciesResource(List<TPolicy> list, IPersistable res) { + super(PolicyResource.class, TPolicy.class, list, res); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not required: boundarydefinitions.jsp also includes the content of the Policy tab."); + } + + @PUT + public Response replaceAll(List<TPolicy> newList) { + this.list.clear(); + for (TPolicy policy : newList) { + this.list.add(policy); + } + return BackendUtils.persist(this.res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java new file mode 100644 index 0000000..08fbd8d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TPolicy; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class PolicyResource extends EntityWithoutIdResource<TPolicy> { + + public PolicyResource(TPolicy o, int idx, List<TPolicy> list, IPersistable res) { + super(o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java new file mode 100644 index 0000000..45bc0c7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +/** + * This package models policies nested in a boundary definitions. It could be resued for the topology modeler, but currently, this is not necessary. + */ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java new file mode 100644 index 0000000..80f2640 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TCapabilityRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * This class is an adaption from + * {@link org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource} + */ +public class CapabilitiesResource extends EntityWithoutIdCollectionResource<CapabilityResource, TCapabilityRef> { + + public CapabilitiesResource(IPersistable res, List<TCapabilityRef> refs) { + super(CapabilityResource.class, TCapabilityRef.class, refs, res); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet required: boundarydefinitions.jsp renders all tab content."); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addNewElement(@FormParam("name") String name, @FormParam("ref") String reference) { + // Implementation adapted from super addNewElement + + if (reference == null) { + return Response.status(Status.BAD_REQUEST).entity("A reference has to be provided").build(); + } + + TCapabilityRef ref = new TCapabilityRef(); + ref.setName(name); // may also be null + + // The XML model fordces us to put a reference to the object and not just the string + ServiceTemplateResource rs = (ServiceTemplateResource) this.res; + TCapability resolved = ModelUtilities.resolveCapability(rs.getServiceTemplate(), reference); + // In case nothing was found: report back to the user + if (resolved == null) { + return Response.status(Status.BAD_REQUEST).entity("Reference could not be resolved").build(); + } + + ref.setRef(resolved); + + // "this.alreadyContains(ref)" cannot be called as this leads to a mappable exception: The data does not contain an id where the given ref attribute may point to + + this.list.add(ref); + return CollectionsHelper.persist(this.res, this, ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java new file mode 100644 index 0000000..7cb7b49 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TCapabilityRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class CapabilityResource extends EntityWithoutIdResource<TCapabilityRef> { + + public CapabilityResource(TCapabilityRef o, int idx, List<TCapabilityRef> list, IPersistable res) { + super(o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java new file mode 100644 index 0000000..72a7476 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TRequirementRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource; + +public class RequirementResource extends EntityWithoutIdResource<TRequirementRef> { + + public RequirementResource(TRequirementRef o, int idx, List<TRequirementRef> list, IPersistable res) { + super(o, idx, list, res); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java new file mode 100644 index 0000000..dc6ad94 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementRef; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper; +import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; + +import com.sun.jersey.api.view.Viewable; + +/** + * This class is mirrored at + * {@link org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.CapabilitiesResource} + */ +public class RequirementsResource extends EntityWithoutIdCollectionResource<RequirementResource, TRequirementRef> { + + public RequirementsResource(IPersistable res, List<TRequirementRef> refs) { + super(RequirementResource.class, TRequirementRef.class, refs, res); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet required: boundarydefinitions.jsp renders all tab content."); + } + + /** + * Adds an element using form-encoding + * + * This is necessary as TRequirementRef contains an IDREF and the XML + * snippet itself does not contain the target id + * + * @param name the optional name of the requirement + * @param reference the reference to a requirement in the topology + */ + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Response addNewElement(@FormParam("name") String name, @FormParam("ref") String reference) { + // Implementation adapted from super addNewElement + + if (reference == null) { + return Response.status(Status.BAD_REQUEST).entity("A reference has to be provided").build(); + } + + TRequirementRef ref = new TRequirementRef(); + ref.setName(name); // may also be null + + // The XML model forces us to put a reference to the object and not just the string + ServiceTemplateResource rs = (ServiceTemplateResource) this.res; + TRequirement resolved = ModelUtilities.resolveRequirement(rs.getServiceTemplate(), reference); + // In case nothing was found: report back to the user + if (resolved == null) { + return Response.status(Status.BAD_REQUEST).entity("Reference could not be resolved").build(); + } + + ref.setRef(resolved); + + // "this.alreadyContains(ref)" cannot be called as this leads to a mappable exception: The data does not contain an id where the given ref attribute may point to + + this.list.add(ref); + return CollectionsHelper.persist(this.res, this, ref); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java new file mode 100644 index 0000000..f6a3c5d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +/** + * This package contains all classes for requirement refs and capability refs + * + * They are nested as "Requirements" / "Capabilities" in the boundary definitions, but the things itself are called "...Ref" + */ +package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java new file mode 100644 index 0000000..5a4b56f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2014-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.plans; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; + +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class PlanFileResource { + + private final PlanId planId; + private TPlan plan; + private ServiceTemplateResource res; + + + public PlanFileResource(ServiceTemplateResource res, PlanId planId, TPlan plan) { + this.res = res; + this.planId = planId; + this.plan = plan; + } + + /** + * Extracts the file reference from plan's planModelReference + */ + private RepositoryFileReference getFileRef() { + String reference = this.plan.getPlanModelReference().getReference(); + File f = new File(reference); + return new RepositoryFileReference(this.planId, f.getName()); + } + + @PUT + @Consumes({MediaType.MULTIPART_FORM_DATA}) + @RestDoc(methodDescription = "Resource currently works for BPMN4TOSCA plans only") + // @formatter:off + public Response onPutFile( + @FormDataParam("file") InputStream uploadedInputStream, + @FormDataParam("file") FormDataContentDisposition fileDetail, + @FormDataParam("file") FormDataBodyPart body + ) { + // @formatter:on + + String fileName = fileDetail.getFileName(); + RepositoryFileReference ref = new RepositoryFileReference(this.planId, fileName); + RepositoryFileReference oldRef = this.getFileRef(); + boolean persistanceNecessary; + if (ref.equals(oldRef)) { + // nothing todo, file will be replaced + persistanceNecessary = false; + } else { + // new filename sent + BackendUtils.delete(oldRef); + PlansResource.setPlanModelReference(this.plan, this.planId, fileName); + persistanceNecessary = true; + } + + // Really store it + try { + Repository.INSTANCE.putContentToFile(ref, uploadedInputStream, body.getMediaType()); + } catch (IOException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not store plan. " + e1.getMessage()).build(); + } + + if (persistanceNecessary) { + return BackendUtils.persist(this.res); + } else { + return Response.noContent().build(); + } + } + + @PUT + @Consumes({MediaType.APPLICATION_JSON}) + // @formatter:off + public Response onPutJSON(InputStream is) { + RepositoryFileReference ref = this.getFileRef(); + return BackendUtils.putContentToFile(ref, is, MediaType.APPLICATION_JSON_TYPE); + } + + /** + * Returns the stored file. + */ + @GET + public Response getFile(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = this.getFileRef(); + return BackendUtils.returnRepoPath(ref, modified); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java new file mode 100644 index 0000000..704c831 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2012-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.plans; + +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.common.ids.elements.PlansId; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.InputParameters; +import org.eclipse.winery.model.tosca.TPlan.OutputParameters; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.IHasName; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.eclipse.winery.repository.resources.interfaces.ParametersResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Does <em>not</em> implement + * {@link org.eclipse.winery.repository.resources.IHasTypeReference}, because + * the type of a plan is outside the system of TOSCA. + */ +public class PlanResource extends EntityWithIdResource<TPlan> implements IHasName { + + private static final Logger logger = LoggerFactory.getLogger(PlanResource.class); + + + public PlanResource(IIdDetermination<TPlan> idDetermination, TPlan o, int idx, List<TPlan> list, ServiceTemplateResource res) { + super(idDetermination, o, idx, list, res); + } + + /** + * Ugly hack to get the parent service template resource + * + */ + public ServiceTemplateResource getServiceTemplateResource() { + // Solution proposal 1: Each sub-resource should know its parent service + // template + // + // Solution proposal 2 (Generic solution): Each resource should know its + // parent resource + // + // Does not work when plan is used at as component instance (then, + // serviceTemplateResource is null). In this case, a plan is not associated + // with a service template. + + // we cannot use "((PlanId) id).getParent()" as this "only" returns an + // ID + // we could create a newly resource based on that ID + // However, the parent resource has already been created when the + // PlanResource has been generated: + // Jersey crawls down from the main resource through the service + // template resource to the plan resource + return (ServiceTemplateResource) this.res; + } + + /** + * Determines the id of the current resource + */ + private PlanId getId() { + ServiceTemplateId sId = (ServiceTemplateId) this.getServiceTemplateResource().getId(); + PlansId psId = new PlansId(sId); + PlanId pId = new PlanId(psId, new XMLId(this.o.getId(), false)); + return pId; + } + + @Override + @DELETE + public Response onDelete() { + Response res = super.onDelete(); + if (Utils.isSuccessFulResponse(res)) { + try { + Repository.INSTANCE.forceDelete(this.getId()); + } catch (IOException e) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not remove plan file").build(); + } + return BackendUtils.persist(this.res); + } else { + return res; + } + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Response getHTML(@Context UriInfo uriInfo) { + boolean isBPMN4TOSCA = this.o.getPlanLanguage().equals(org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20); + String bpmn4toscaBaseURL = Prefs.INSTANCE.getBPMN4TOSCABaseURL(); + if (isBPMN4TOSCA && (!StringUtils.isEmpty(bpmn4toscaBaseURL))) { + String uri = bpmn4toscaBaseURL; + URI repositoryURI = uriInfo.getBaseUri(); + uri += "?repositoryURL=" + Util.URLencode(repositoryURI.toString()); + TOSCAComponentId serviceTemplateId = this.getServiceTemplateResource().getId(); + uri += "&namespace=" + serviceTemplateId.getNamespace().getEncoded(); + uri += "&id=" + serviceTemplateId.getXmlId().getEncoded(); + uri += "&plan=" + this.getName(); + return Response.temporaryRedirect(Utils.createURI(uri)).build(); + } else { + // return Response.ok().entity("No editor plugin found for plan language " + this.o.getPlanLanguage()).build(); + URI fileURI = uriInfo.getAbsolutePath().resolve("file"); + return Response.seeOther(fileURI).build(); + } + } + + @Override + public String getName() { + String name = this.o.getName(); + if (name == null) { + name = this.o.getId(); + } + return name; + } + + @Override + public Response setName(@FormParam("value") String name) { + this.o.setName(name); + return BackendUtils.persist(this.res); + } + + @Path("file") + public PlanFileResource getPlanFileResource() { + return new PlanFileResource((ServiceTemplateResource) this.res, this.getId(), this.o); + } + + @GET + @Path("type") + public String getType() { + return this.o.getPlanType(); + } + + @PUT + @Path("type") + public Response setType(@FormParam("type") String type) { + this.o.setPlanType(type); + return BackendUtils.persist(this.res); + } + + @GET + @Path("language") + public String getLanguage() { + return this.o.getPlanLanguage(); + } + + @PUT + @Path("language") + public Response setLanguage(@FormParam("language") String language) { + this.o.setPlanType(language); + return BackendUtils.persist(this.res); + } + + @Path("inputparameters/") + public ParametersResource getInputParametersResource() { + InputParameters inputParameters = this.o.getInputParameters(); + if (inputParameters == null) { + inputParameters = new InputParameters(); + this.o.setInputParameters(inputParameters); + } + return new ParametersResource(inputParameters.getInputParameter(), this.getServiceTemplateResource()); + } + + @Path("outputparameters/") + public ParametersResource getOutputParametersResource() { + OutputParameters outputParameters = this.o.getOutputParameters(); + if (outputParameters == null) { + outputParameters = new OutputParameters(); + this.o.setOutputParameters(outputParameters); + } + return new ParametersResource(outputParameters.getOutputParameter(), this.getServiceTemplateResource()); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java new file mode 100644 index 0000000..13a8420 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2012-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.plans; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.common.ids.elements.PlanId; +import org.eclipse.winery.common.ids.elements.PlansId; +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.PlanModelReference; +import org.eclipse.winery.repository.Constants; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +/** + * Presents the plans nested in one Service Template + */ +public class PlansResource extends EntityWithIdCollectionResource<PlanResource, TPlan> { + + private static final Logger logger = LoggerFactory.getLogger(PlansResource.class); + + + public PlansResource(List<TPlan> plans, ServiceTemplateResource res) { + super(PlanResource.class, TPlan.class, plans, res); + } + + @Override + public Viewable getHTML() { + return new Viewable("/jsp/servicetemplates/plans/plans.jsp", new PlansResourceData(this.list)); + } + + @POST + @RestDoc(methodDescription = "<p>Linked plans are currently not supported. Existing plans with the same id are overwritten</p> <p>@return JSON with .tableData: Array with row data for dataTable</p>") + @Consumes({MediaType.MULTIPART_FORM_DATA}) + @Produces(MediaType.APPLICATION_JSON) + // the supertype consumes JSON and XML at org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource.addNewElement(EntityT) + // @formatter:off + public Response onPost( + @FormDataParam("planName") String name, + @FormDataParam("planType") String type, + @FormDataParam("planLanguage") @RestDocParam(description = "the plan language (e..g, BPMN or BPEL). Full URL.") String language, + @FormDataParam("file") @RestDocParam(description="(optional in the case of BPMN4TOSCA) file containing the plan.") InputStream uploadedInputStream, + @FormDataParam("file") FormDataContentDisposition fileDetail, + @FormDataParam("file") FormDataBodyPart body + ) { + // @formatter:on + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("planName must be given").build(); + } + if (StringUtils.isEmpty(type)) { + return Response.status(Status.BAD_REQUEST).entity("planType must be given").build(); + } + if (StringUtils.isEmpty(language)) { + return Response.status(Status.BAD_REQUEST).entity("planLanguage must be given").build(); + } + + boolean bpmn4toscaMode = org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20.equals(language); + if (!bpmn4toscaMode) { + if (uploadedInputStream == null) { + return Response.status(Status.BAD_REQUEST).entity("file must be given").build(); + } + } + + // A plan carries both a name and an ID + // To be user-friendly, we create the ID based on the name + // the drawback is, that we do not allow two plans with the same name + // during creation, but allow renaming plans to the same name (as we do + // not allow ID renaming) + String xmlId = Utils.createXMLidAsString(name); + + // BEGIN: Store plan file + + // Determine Id + PlansId plansId = new PlansId((ServiceTemplateId) ((ServiceTemplateResource) this.res).getId()); + PlanId planId = new PlanId(plansId, new XMLId(xmlId, false)); + // Ensure overwriting + if (Repository.INSTANCE.exists(planId)) { + try { + Repository.INSTANCE.forceDelete(planId); + // Quick hack to remove the deleted plan from the plans element + ((ServiceTemplateResource) this.res).synchronizeReferences(); + } catch (IOException e) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + } + + String fileName; + if (bpmn4toscaMode) { + fileName = xmlId + Constants.SUFFIX_BPMN4TOSCA; + RepositoryFileReference ref = new RepositoryFileReference(planId, fileName); + try { + Repository.INSTANCE.putContentToFile(ref, "{}", MediaType.APPLICATION_JSON_TYPE); + } catch (IOException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not create empty plan. " + e1.getMessage()).build(); + } + } else { + // We use the filename also as local file name. Alternatively, we could use the xml id + // With URL encoding, this should not be an issue + fileName = Util.URLencode(fileDetail.getFileName()); + + // Really store it + RepositoryFileReference ref = new RepositoryFileReference(planId, fileName); + try { + Repository.INSTANCE.putContentToFile(ref, uploadedInputStream, body.getMediaType()); + } catch (IOException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not store plan. " + e1.getMessage()).build(); + } + } + // END: Store plan file + + TPlan plan = new TPlan(); + plan.setId(xmlId); + plan.setName(name); + plan.setPlanType(type); + plan.setPlanLanguage(language); + PlansResource.setPlanModelReference(plan, planId, fileName); + this.list.add(plan); + + // prepare result + JsonFactory jsonFactory = new JsonFactory(); + StringWriter sw = new StringWriter(); + try { + JsonGenerator jGenerator = jsonFactory.createGenerator(sw); + jGenerator.writeStartObject(); + jGenerator.writeFieldName("tableData"); + jGenerator.writeStartArray(); + jGenerator.writeString(xmlId); + jGenerator.writeString(""); // precondition + jGenerator.writeString(name); + jGenerator.writeString(PlanTypesManager.INSTANCE.getShortName(type)); + jGenerator.writeString(PlanLanguagesManager.INSTANCE.getShortName(language)); + jGenerator.writeEndArray(); + jGenerator.writeEndObject(); + jGenerator.close(); + sw.close(); + } catch (JsonGenerationException e) { + PlansResource.logger.error(e.getMessage(), e); + return Response.serverError().build(); + } catch (IOException e) { + PlansResource.logger.error(e.getMessage(), e); + return Response.serverError().build(); + } + + Response res = BackendUtils.persist(this.res); + if (res.getStatus() == 204) { + // everything OK, return created + return Response.created(Utils.createURI(Util.URLencode(xmlId))).entity(sw.toString()).build(); + } else { + return res; + } + } + + static void setPlanModelReference(TPlan plan, PlanId planId, String fileName) { + PlanModelReference pref = new PlanModelReference(); + // Set path relative to Definitions/ path inside CSAR. + pref.setReference("../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(planId)) + fileName); + plan.setPlanModelReference(pref); + } + + @Override + public String getId(TPlan plan) { + return plan.getId(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java new file mode 100644 index 0000000..8527eb4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.plans; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Collection; +import java.util.List; + +import org.eclipse.winery.model.tosca.TPlan; +import org.eclipse.winery.model.tosca.TPlan.PlanModelReference; +import org.eclipse.winery.repository.datatypes.TypeWithShortName; +import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager; +import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; + +public class PlansResourceData { + + private static final Logger logger = LoggerFactory.getLogger(PlansResourceData.class); + + // data: [ [id, pre, name, type, lang]* ] + private String embeddedPlansTableData; + + // data: [ [id, pre, name, type, lang, reference]* ] + private String linkedPlansTableData; + + + /** + * Data object for the JSP + * + * @param serviceTemplateResource the service template the plans belong to + */ + public PlansResourceData(List<TPlan> plans) { + if (plans.isEmpty()) { + this.embeddedPlansTableData = "[]"; + this.linkedPlansTableData = "[]"; + return; + } + JsonFactory jsonFactory = new JsonFactory(); + StringWriter embeddedPlansTableDataSW = new StringWriter(); + StringWriter linkedPlansTableDataSW = new StringWriter(); + try { + JsonGenerator jGeneratorEmbedded = jsonFactory.createGenerator(embeddedPlansTableDataSW); + JsonGenerator jGeneratorLinked = jsonFactory.createGenerator(linkedPlansTableDataSW); + + jGeneratorEmbedded.writeStartArray(); + jGeneratorLinked.writeStartArray(); + + for (TPlan plan : plans) { + String name = plan.getName(); + if (name == null) { + // name defaults to id + name = plan.getId(); + } + String type = PlanTypesManager.INSTANCE.getShortName(plan.getPlanType()); + String language = PlanLanguagesManager.INSTANCE.getShortName(plan.getPlanLanguage()); + PlanModelReference planModelReference = plan.getPlanModelReference(); + String reference = planModelReference != null ? planModelReference.getReference() : null; + JsonGenerator gen; + boolean writeReference; + if (reference == null) { + gen = jGeneratorEmbedded; + writeReference = false; + } else if (reference.startsWith("../")) { + gen = jGeneratorEmbedded; + writeReference = false; + } else { + gen = jGeneratorLinked; + writeReference = true; + } + + gen.writeStartArray(); + gen.writeString(plan.getId()); + gen.writeString(""); // precondition + gen.writeString(name); + gen.writeString(type); + gen.writeString(language); + if (writeReference) { + gen.writeString(reference); + } + gen.writeEndArray(); + } + + jGeneratorEmbedded.writeEndArray(); + jGeneratorLinked.writeEndArray(); + + jGeneratorEmbedded.close(); + embeddedPlansTableDataSW.close(); + jGeneratorLinked.close(); + linkedPlansTableDataSW.close(); + } catch (JsonGenerationException e) { + PlansResourceData.logger.error(e.getMessage(), e); + this.embeddedPlansTableData = "[]"; + this.linkedPlansTableData = "[]"; + return; + } catch (IOException e) { + PlansResourceData.logger.error("", e); + this.embeddedPlansTableData = "[]"; + this.linkedPlansTableData = "[]"; + return; + } + this.embeddedPlansTableData = embeddedPlansTableDataSW.toString(); + this.linkedPlansTableData = linkedPlansTableDataSW.toString(); + } + + public String getEmbeddedPlansTableData() { + return this.embeddedPlansTableData; + } + + public String getLinkedPlansTableData() { + return this.linkedPlansTableData; + } + + public Collection<TypeWithShortName> getPlanTypes() { + return PlanTypesManager.INSTANCE.getTypes(); + } + + public Collection<TypeWithShortName> getPlanLanguages() { + return PlanLanguagesManager.INSTANCE.getTypes(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java new file mode 100644 index 0000000..9ce11f9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal; + +import java.io.IOException; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.winery.model.selfservice.ApplicationOption; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OptionResource extends EntityWithIdResource<ApplicationOption> { + + private static final Logger logger = LoggerFactory.getLogger(OptionResource.class); + + static final String ICON_JPG = "icon.jpg"; + static final String PLAN_INPUT_XML = "plan.input.xml"; + private SelfServiceMetaDataId ssmdId; + + + public OptionResource(IIdDetermination<ApplicationOption> idDetermination, ApplicationOption o, int idx, List<ApplicationOption> list, SelfServicePortalResource res) { + super(idDetermination, o, idx, list, res); + this.ssmdId = ((SelfServicePortalResource) this.res).getId(); + } + + private String getFileNamePrefix() { + return OptionResource.getFileNamePrefix(this.o.getId()); + } + + public static String getFileNamePrefix(String id) { + return "option_" + id + "_"; + } + + @Path(OptionResource.ICON_JPG) + @GET + public Response getIcon(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.getFileNamePrefix() + OptionResource.ICON_JPG); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Path("planinputmessage") + @GET + public Response getPlanInputMessage(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.getFileNamePrefix() + OptionResource.PLAN_INPUT_XML); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Override + public Response onDelete() { + // delete icon and plan model reference ... + + // delete icon + // we use the URL stored in the data instead of the generated URL to be compatible with manually edits + RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.o.getIconUrl()); + try { + Repository.INSTANCE.forceDelete(ref); + } catch (IOException e) { + OptionResource.logger.error("Could not remove file", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + + // delete plan input + // we use the URL stored in the data instead of the generated URL to be compatible with manually edits + ref = new RepositoryFileReference(this.ssmdId, this.o.getPlanInputMessageUrl()); + try { + Repository.INSTANCE.forceDelete(ref); + } catch (IOException e) { + OptionResource.logger.error("Could not remove file", e); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + + // after deleting files, continue with list deletion + return super.onDelete(); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java new file mode 100644 index 0000000..86fa102 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.winery.model.selfservice.ApplicationOption; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource; +import org.restdoc.annotations.RestDoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class OptionsResource extends EntityWithIdCollectionResource<OptionResource, ApplicationOption> { + + private static final Logger logger = LoggerFactory.getLogger(OptionsResource.class); + + + public OptionsResource(List<ApplicationOption> list, SelfServicePortalResource res) { + super(OptionResource.class, ApplicationOption.class, list, res); + } + + @Override + public String getId(ApplicationOption entity) { + return entity.getId(); + } + + @Override + public Viewable getHTML() { + throw new IllegalStateException("Not yet implemented."); + } + + @POST + @RestDoc(methodDescription = "Adds a new option<p>TODO: @return JSON with .tableData: Array with row data for dataTable</p>") + @Consumes(MediaType.MULTIPART_FORM_DATA) + // @formatter:off + public Response onPost( + @FormDataParam("name") String name, + @FormDataParam("description") String description, + @FormDataParam("planServiceName") String planServiceName, + @FormDataParam("planInputMessage") String planInputMessage, + @FormDataParam("file") InputStream uploadedInputStream, + @FormDataParam("file") FormDataContentDisposition fileDetail, + @FormDataParam("file") FormDataBodyPart body + ) { + // @formatter:on + if (StringUtils.isEmpty(name)) { + return Response.status(Status.BAD_REQUEST).entity("planName must be given").build(); + } + if (StringUtils.isEmpty(description)) { + return Response.status(Status.BAD_REQUEST).entity("description must be given").build(); + } + if (StringUtils.isEmpty(planServiceName)) { + return Response.status(Status.BAD_REQUEST).entity("planServiceName must be given").build(); + } + if (StringUtils.isEmpty(planInputMessage)) { + return Response.status(Status.BAD_REQUEST).entity("planInputMessage must be given").build(); + } + if (uploadedInputStream == null) { + return Response.status(Status.BAD_REQUEST).entity("file has to be provided").build(); + } + ApplicationOption option = new ApplicationOption(); + + String id = Utils.createXMLidAsString(name); + + String fileNamePrefix = OptionResource.getFileNamePrefix(id); + String iconFileName = fileNamePrefix + OptionResource.ICON_JPG; + String planInputMessageFileName = fileNamePrefix + OptionResource.PLAN_INPUT_XML; + + // create option data + option.setId(id); + option.setName(name); + option.setDescription(description); + option.setIconUrl(iconFileName); + option.setPlanInputMessageUrl(planInputMessageFileName); + option.setPlanServiceName(planServiceName); + + // BEGIN: store icon and planInputMessage + + SelfServiceMetaDataId ssmdId = ((SelfServicePortalResource) this.res).getId(); + + RepositoryFileReference iconRef = new RepositoryFileReference(ssmdId, iconFileName); + try { + Repository.INSTANCE.putContentToFile(iconRef, uploadedInputStream, body.getMediaType()); + } catch (IOException e) { + OptionsResource.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + + RepositoryFileReference planInputMessageRef = new RepositoryFileReference(ssmdId, planInputMessageFileName); + try { + Repository.INSTANCE.putContentToFile(planInputMessageRef, planInputMessage, MediaType.TEXT_XML_TYPE); + } catch (IOException e) { + OptionsResource.logger.error(e.getMessage(), e); + return Response.serverError().entity(e.getMessage()).build(); + } + + // END: store icon and planInputMessage + + this.list.add(option); + Response response = BackendUtils.persist(this.res); + return response; + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java new file mode 100644 index 0000000..98e1dcf --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.io.IOUtils; +import org.apache.taglibs.standard.functions.Functions; +import org.eclipse.winery.common.RepositoryFileReference; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.selfservice.Application; +import org.eclipse.winery.model.selfservice.Application.Options; +import org.eclipse.winery.model.tosca.TDocumentation; +import org.eclipse.winery.repository.JAXBSupport; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +public class SelfServicePortalResource implements IPersistable { + + private static final Logger logger = LoggerFactory.getLogger(SelfServicePortalResource.class); + + private final ServiceTemplateResource serviceTemplateResource; + + public final RepositoryFileReference data_xml_ref; + public final RepositoryFileReference icon_jpg_ref; + public final RepositoryFileReference image_jpg_ref; + + private final Application application; + + private final SelfServiceMetaDataId id; + + + public SelfServicePortalResource(ServiceTemplateId serviceTemplateId) { + this(null, serviceTemplateId); + } + + public SelfServicePortalResource(ServiceTemplateResource serviceTemplateResource) { + this(serviceTemplateResource, (ServiceTemplateId) serviceTemplateResource.getId()); + } + + SelfServiceMetaDataId getId() { + return this.id; + } + + /** + * @param serviceTemplateResource may be null + * @param serviceTemplateId the id, must not be null + */ + private SelfServicePortalResource(ServiceTemplateResource serviceTemplateResource, ServiceTemplateId serviceTemplateId) { + this.serviceTemplateResource = serviceTemplateResource; + this.id = new SelfServiceMetaDataId(serviceTemplateId); + this.data_xml_ref = new RepositoryFileReference(this.id, "data.xml"); + this.icon_jpg_ref = new RepositoryFileReference(this.id, "icon.jpg"); + this.image_jpg_ref = new RepositoryFileReference(this.id, "image.jpg"); + this.application = this.getData(); + } + + private Application getData() { + if (Repository.INSTANCE.exists(this.data_xml_ref)) { + Unmarshaller u = JAXBSupport.createUnmarshaller(); + try (InputStream is = Repository.INSTANCE.newInputStream(this.data_xml_ref);) { + return (Application) u.unmarshal(is); + } catch (IOException | JAXBException e) { + SelfServicePortalResource.logger.error("Could not read from " + this.data_xml_ref, e); + return new Application(); + } + } else { + return this.getDefaultApplicationData(); + } + } + + private Application getDefaultApplicationData() { + Application app = new Application(); + app.setIconUrl("icon.jpg"); + app.setImageUrl("image.jpg"); + if (this.serviceTemplateResource != null) { + app.setDisplayName(this.serviceTemplateResource.getName()); + List<TDocumentation> documentation = this.serviceTemplateResource.getServiceTemplate().getDocumentation(); + if ((documentation != null) && (!documentation.isEmpty())) { + TDocumentation doc = documentation.get(0); + List<Object> content = doc.getContent(); + if ((content != null) && (!content.isEmpty())) { + app.setDescription(content.get(0).toString()); + } + } + } + return app; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/servicetemplates/selfservicemetadata/selfservicemetadata.jsp", this); + } + + @Override + public void persist() throws IOException { + BackendUtils.persist(this.application, this.data_xml_ref, MediaType.TEXT_XML_TYPE); + } + + @PUT + @Consumes(MediaType.TEXT_XML) + public Response onPutXML(Application data) { + String content = Utils.getXMLAsString(data); + return BackendUtils.putContentToFile(this.data_xml_ref, content, MediaType.TEXT_XML_TYPE); + } + + @Path("icon.jpg") + @GET + public Response getIcon(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "icon.jpg"); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Path("icon.jpg") + @PUT + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response putIcon(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "icon.jpg"); + return BackendUtils.putContentToFile(ref, uploadedInputStream, body.getMediaType()); + } + + @Path("image.jpg") + @GET + public Response getImage(@HeaderParam("If-Modified-Since") String modified) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "image.jpg"); + return BackendUtils.returnRepoPath(ref, modified); + } + + @Path("image.jpg") + @PUT + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response putImage(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) { + RepositoryFileReference ref = new RepositoryFileReference(this.id, "image.jpg"); + return BackendUtils.putContentToFile(ref, uploadedInputStream, body.getMediaType()); + } + + @Path("displayname") + @PUT + public Response onPutOnDisplayName(@FormParam("value") String value) { + this.application.setDisplayName(value); + return BackendUtils.persist(this); + } + + @Path("description") + @PUT + public Response onPutOnDescription(@FormParam("value") String value) { + this.application.setDescription(value); + return BackendUtils.persist(this); + } + + @Path("options/") + public OptionsResource getOptionsResource() { + Options options = this.application.getOptions(); + if (options == null) { + options = new Options(); + this.application.setOptions(options); + } + return new OptionsResource(options.getOption(), this); + } + + /** + * @return the internal application object. Used for the export. + */ + public Application getApplication() { + return this.application; + } + + /** + * Used in JSP only + */ + public String getApplicationAsXMLStringEncoded() { + String res; + if (Repository.INSTANCE.exists(this.data_xml_ref)) { + StringWriter sw = new StringWriter(); + try (InputStream is = Repository.INSTANCE.newInputStream(this.data_xml_ref);) { + IOUtils.copy(is, sw); + } catch (IOException e) { + SelfServicePortalResource.logger.error("Could not read from file", e); + } + res = sw.toString(); + } else { + // return skeleton for application + // application object is already filled with default values if no file exists in repo + res = Utils.getXMLAsString(this.getApplication()); + } + return Functions.escapeXml(res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java new file mode 100644 index 0000000..2a59aa5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates; + +import java.util.List; +import java.util.Map; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.eclipse.winery.common.constants.Namespaces; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.artifacts.DeploymentArtifactsResource; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; + +public class NodeTemplateResource extends TEntityTemplateResource<TNodeTemplate> implements INodeTemplateResourceOrNodeTypeImplementationResource { + + public NodeTemplateResource(IIdDetermination<TNodeTemplate> idDetermination, TNodeTemplate o, int idx, List<TNodeTemplate> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } + + @Path("deploymentartifacts/") + public DeploymentArtifactsResource getDeploymentArtifacts() { + return new DeploymentArtifactsResource(this.o, this); + } + + @GET + @RestDoc(methodDescription = "* The following methods are currently *not* used by the topology modeler.<br />" + "The modeler is using the repository client to interact with the repository") + @Path("minInstances") + public String getMinInstances() { + return Integer.toString(this.o.getMinInstances()); + } + + @PUT + @Path("minInstances") + public Response setMinInstances(@FormParam(value = "minInstances") String minInstances) { + int min = Integer.parseInt(minInstances); + this.o.setMinInstances(min); + return BackendUtils.persist(this.res); + } + + @GET + @Path("maxInstances") + public String getMaxInstances() { + return this.o.getMaxInstances(); + } + + @PUT + @Path("maxInstances") + public Response setMaxInstances(@FormParam(value = "maxInstances") String maxInstances) { + // TODO: check for valid integer | "unbound" + this.o.setMaxInstances(maxInstances); + return BackendUtils.persist(this.res); + } + + + /* * * + * The visual appearance + * + * We do not use a subresource "visualappearance" here to avoid generation of more objects + * * */ + + private final QName qnameX = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "x"); + private final QName qnameY = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "y"); + + + @Path("x") + @GET + @RestDoc(methodDescription = "@return the x coordinate of the node template") + public String getX() { + Map<QName, String> otherAttributes = this.o.getOtherAttributes(); + return otherAttributes.get(this.qnameX); + } + + @Path("x") + @PUT + public Response setX(String x) { + this.o.getOtherAttributes().put(this.qnameX, x); + return BackendUtils.persist(this.res); + } + + @Path("y") + @GET + @RestDoc(methodDescription = "@return the y coordinate of the node template") + public String getY() { + Map<QName, String> otherAttributes = this.o.getOtherAttributes(); + return otherAttributes.get(this.qnameY); + } + + @Path("y") + @PUT + public Response setY(String y) { + this.o.getOtherAttributes().put(this.qnameY, y); + return BackendUtils.persist(this.res); + } + + @Override + public Namespace getNamespace() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + + /** + * Required for persistence after a change of the deployment artifact. + * Required by DeploymentArtifactResource to be able to persist + * + * @return the service template this node template belongs to + */ + public ServiceTemplateResource getServiceTemplateResource() { + return (ServiceTemplateResource) this.res; + } + + /** + * required for topology modeler to check for existence of a node template + * at the server + * + * @return empty response + */ + @HEAD + public Response getHEAD() { + return Response.noContent().build(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java new file mode 100644 index 0000000..64c5de8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplatesResource; + +import com.sun.jersey.api.view.Viewable; + +public class NodeTemplatesResource extends TEntityTemplatesResource<NodeTemplateResource, TNodeTemplate> { + + public NodeTemplatesResource(List<TNodeTemplate> list, IPersistable res) { + super(NodeTemplateResource.class, TNodeTemplate.class, list, res); + } + + @Override + public String getId(TNodeTemplate entity) { + return entity.getId(); + } + + @Override + public Viewable getHTML() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java new file mode 100644 index 0000000..a3eaed5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources._support.collections.IIdDetermination; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource; + +public class RelationshipTemplateResource extends TEntityTemplateResource<TRelationshipTemplate> { + + public RelationshipTemplateResource(IIdDetermination<TRelationshipTemplate> idDetermination, TRelationshipTemplate o, int idx, List<TRelationshipTemplate> list, IPersistable res) { + super(idDetermination, o, idx, list, res); + } +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java new file mode 100644 index 0000000..8073e83 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates; + +import java.util.List; + +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.repository.resources._support.IPersistable; +import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplatesResource; + +import com.sun.jersey.api.view.Viewable; + +public class RelationshipTemplatesResource extends TEntityTemplatesResource<RelationshipTemplateResource, TRelationshipTemplate> { + + public RelationshipTemplatesResource(List<TRelationshipTemplate> list, IPersistable res) { + super(RelationshipTemplateResource.class, TRelationshipTemplate.class, list, res); + } + + @Override + public String getId(TRelationshipTemplate entity) { + return entity.getId(); + } + + @Override + public Viewable getHTML() { + // TODO Auto-generated method stub + throw new IllegalStateException("Not yet implemented."); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java new file mode 100644 index 0000000..b4b3646 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2012-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.repository.Prefs; +import org.eclipse.winery.repository.Utils; +import org.eclipse.winery.repository.backend.BackendUtils; +import org.eclipse.winery.repository.client.IWineryRepositoryClient; +import org.eclipse.winery.repository.client.WineryRepositoryClientFactory; +import org.eclipse.winery.repository.json.TopologyTemplateModule; +import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource; +import org.restdoc.annotations.RestDoc; +import org.restdoc.annotations.RestDocParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.WebResource.Builder; +import com.sun.jersey.api.view.Viewable; + +public class TopologyTemplateResource { + + private static final Logger logger = LoggerFactory.getLogger(TopologyTemplateResource.class); + + private final TTopologyTemplate topologyTemplate; + + private final ServiceTemplateResource serviceTemplateRes; + + + /** + * A topology template is always nested in a service template + */ + public TopologyTemplateResource(ServiceTemplateResource parent) { + this.topologyTemplate = parent.getServiceTemplate().getTopologyTemplate(); + this.serviceTemplateRes = parent; + } + + + public static class DataForJSP { + + private String location; + private TTopologyTemplate topologyTemplate; + private URI repositoryURI; + private String additonalCSS; + private Boolean autoLayoutOnLoad; + private String additionalScript; + + + public DataForJSP(String location, URI repositoryURI, TTopologyTemplate topologyTemplate, String additonalCSS, String additionalScript, Boolean autoLayoutOnLoad) { + this.location = location; + this.repositoryURI = repositoryURI; + this.topologyTemplate = topologyTemplate; + this.additonalCSS = additonalCSS; + this.additionalScript = additionalScript; + this.autoLayoutOnLoad = autoLayoutOnLoad; + } + + public String getLocation() { + return this.location; + } + + public TTopologyTemplate getTopologyTemplate() { + return this.topologyTemplate; + } + + public String getAdditonalCSS() { + return this.additonalCSS; + } + + public String getAdditionalScript() { + return this.additionalScript; + } + + public Boolean getAutoLayoutOnLoad() { + return this.autoLayoutOnLoad; + } + + public IWineryRepositoryClient getClient() { + // Quick hack + // IWineryRepository is not implemented by Prefs.INSTANCE.getRepository() + // Therefore, we have to generate a real WineryRepositoryClient even if that causes more http load + IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + client.addRepository(this.repositoryURI.toString()); + return client; + } + + } + + + @GET + @RestDoc(methodDescription = "?edit is used in the URL to get the jsPlumb-based editor") + @Produces(MediaType.TEXT_HTML) + // @formatter:off + public Response getHTML( + @QueryParam(value = "edit") String edit, + @QueryParam(value = "script") @RestDocParam(description = "the script to include in a <script> tag. The function wineryViewExternalScriptOnLoad if it is defined. Only available if 'view' is also set") String script, + @QueryParam(value = "view") String view, + @QueryParam(value = "autoLayoutOnLoad") String autoLayoutOnLoad, + @Context UriInfo uriInfo) { + // @formatter:on + Response res; + String JSPName; + String location = Prefs.INSTANCE.getWineryTopologyModelerPath(); + location = uriInfo.getBaseUri().resolve(location).toString(); + // at the topology modeler, jersey needs to have an absolute path + URI repositoryURI = uriInfo.getBaseUri(); + location = location + "/?repositoryURL="; + location = location + Util.URLencode(repositoryURI.toString()); + ServiceTemplateId serviceTemplate = (ServiceTemplateId) this.serviceTemplateRes.getId(); + location = location + "&ns="; + location = location + serviceTemplate.getNamespace().getEncoded(); + location = location + "&id="; + location = location + serviceTemplate.getXmlId().getEncoded(); + if (edit == null) { + String additionalCSS = null; + Boolean autoLayoutOnLoadBoolean = false; + if (view == null) { + // integration in Winery + // currently not maintained: Winery includes ?view as iframe + JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplate.jsp"; + } else { + // view only mode + // fullscreen: additionalCSS and script possible + if (!"".equals(view)) { + // view with additional CSS + URI cssURI = URI.create(view); + if (cssURI.isAbsolute()) { + additionalCSS = view; + } else { + // relative URLs starts at "/css/topologyrendering/" + additionalCSS = uriInfo.getBaseUri().resolve("css/topologytemplaterendering/").resolve(view).toString(); + if (!additionalCSS.endsWith(".css")) { + additionalCSS += ".css"; + } + } + } + if (autoLayoutOnLoad != null) { + autoLayoutOnLoadBoolean = true; + } + JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp"; + } + Viewable viewable = new Viewable(JSPName, new DataForJSP(location, repositoryURI, this.topologyTemplate, additionalCSS, script, autoLayoutOnLoadBoolean)); + res = Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build(); + } else { + // edit mode + URI uri = Utils.createURI(location); + res = Response.seeOther(uri).build(); + } + return res; + } + + /** + * + * @param uriInfo the URI ending with "topologytemplate/" of a service + * template + */ + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response triggerGenerateBuildPlan(@Context UriInfo uriInfo) { + String plansURI = uriInfo.getAbsolutePath().resolve("../plans/").toString(); + String csarURI = uriInfo.getAbsolutePath().resolve("../?csar").toString(); + + String request = "<generatePlanForTopology><CSARURL>"; + request += csarURI; + request += "</CSARURL><PLANPOSTURL>"; + request += plansURI; + request += "</PLANPOSTURL></generatePlanForTopology>"; + + Client client = Client.create(); + Builder wr = client.resource("http://localhost:1339/planbuilder/sync").type(MediaType.APPLICATION_XML); + + try { + wr.post(String.class, request); + } catch (com.sun.jersey.api.client.UniformInterfaceException e) { + return Response.serverError().entity(e.getMessage()).build(); + } + + return Response.ok().build(); + } + + // @formatter:off + @GET + @RestDoc(methodDescription="Returns a JSON representation of the topology template. <br />" + + "X and Y coordinates are embedded as attributes. QName string with Namespace: <br />" + + "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} <br />" + + "@return The JSON representation of the topology template <em>without</em> associated artifacts and without the parent service template") + @Produces(MediaType.APPLICATION_JSON) + // @formatter:on + public Response getComponentInstanceJSON() { + Response res; + ObjectMapper mapper = new ObjectMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.registerModule(new TopologyTemplateModule()); + try { + // convert it to json + String json = mapper.writeValueAsString(this.topologyTemplate); + res = Response.ok(json).build(); + } catch (Exception e) { + TopologyTemplateResource.logger.error(e.getMessage(), e); + res = Response.serverError().entity(e.getMessage()).build(); + } + return res; + } + + @Path("nodetemplates/") + public NodeTemplatesResource getNodeTemplatesResource() { + // FIXME: onDelete will not work as we have a copy of the original list. We have to add a "listener" to remove at the list and route that remove to the original list + List<TNodeTemplate> l = BackendUtils.getAllNestedNodeTemplates(this.serviceTemplateRes.getServiceTemplate()); + return new NodeTemplatesResource(l, this.serviceTemplateRes); + } + + @Path("relationshiptemplates/") + public RelationshipTemplatesResource getRelationshipTemplatesResource() { + // FIXME: onDelete will not work. See getNodeTemplatesResource + List<TRelationshipTemplate> l = new ArrayList<TRelationshipTemplate>(); + for (TEntityTemplate t : this.topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (t instanceof TRelationshipTemplate) { + l.add((TRelationshipTemplate) t); + } + } + return new RelationshipTemplatesResource(l, this.serviceTemplateRes); + } + + @PUT + @RestDoc(methodDescription = "Replaces the topology by the information given in the XML") + @Consumes(MediaType.TEXT_XML) + public Response setModel(TTopologyTemplate topologyTemplate) { + this.serviceTemplateRes.getServiceTemplate().setTopologyTemplate(topologyTemplate); + return BackendUtils.persist(this.serviceTemplateRes); + } + + // @formatter:off + @GET + @RestDoc(methodDescription="<p>Returns an XML representation of the topology template." + + " X and Y coordinates are embedded as attributes. Namespace:" + + "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} </p>" + + "<p>{@link org.eclipse.winery.repository.client.WineryRepositoryClient." + + "getTopologyTemplate(QName)} consumes this template</p>" + + "<p>@return The XML representation of the topology template <em>without</em>" + + "associated artifacts and without the parent service template </p>") + @Produces(MediaType.TEXT_XML) + // @formatter:on + public Response getComponentInstanceXML() { + return Utils.getXML(TTopologyTemplate.class, this.topologyTemplate); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java new file mode 100644 index 0000000..21596e6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.tags; + +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.winery.common.ids.definitions.TOSCAComponentId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sun.jersey.api.view.Viewable; + +public class TagsResource { + + private static final Logger logger = LoggerFactory.getLogger(TagsResource.class); + + + public TagsResource(TOSCAComponentId parentId) { + } + + @GET + @Produces(MediaType.TEXT_HTML) + public Viewable getHTML() { + return new Viewable("/jsp/tags/tags.jsp", this); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java new file mode 100644 index 0000000..2c97e64 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.runtimeintegration; + +import org.eclipse.winery.repository.Utils; + +public class OpenTOSCAContainerConnection { + + /** + * Determines whether the OpenTOSCA container is locally available + * + * We currently check for localhost only as Winery currently does not allow + * for configuring an URL for the container + */ + public static boolean isContainerLocallyAvailable() { + // the string determining the location of the OpenTOSCA container admin resource + String adminPath = "http://localhost:8080/admin/"; + return Utils.isResourceAvailable(adminPath); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java new file mode 100644 index 0000000..9627605 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ + +/** + * This package offers classees to integrate different TOSCA runtimes + */ +package org.eclipse.winery.repository.runtimeintegration;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/resources/.gitignore b/winery/org.eclipse.winery.repository/src/main/resources/.gitignore new file mode 100644 index 0000000..e8f4e06 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/resources/.gitignore @@ -0,0 +1,3 @@ +#the properties are ignored since they are different from deployment to deployment +#A template is provided at conf/ +winery.properties diff --git a/winery/org.eclipse.winery.repository/src/main/resources/logback-test.xml b/winery/org.eclipse.winery.repository/src/main/resources/logback-test.xml new file mode 100644 index 0000000..7d1f5c6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/resources/logback-test.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line %method - %msg%n</pattern> + </encoder> + </appender> + + <logger name="org.eclipse.winery" level="DEBUG"/> + <logger name="org.eclipse.winery.repository.export.TOSCAExportUtil" level="TRACE"/> + <logger name="org.eclipse.winery.repository.export.CSARExporter" level="TRACE"/> + <logger name="org.eclipse.winery.repository.backend.filebased.GitBasedRepository" level="TRACE"/> + <logger name="org.eclipse.winery.repository.importing.CSARImporter" level="TRACE"/> + <logger name="org.eclipse.winery.repository.Utils" level="TRACE"/> + <logger name="org.apache.catalina.core.ApplicationDispatcher" level="SEVERE"/> + + <root level="info"> + <appender-ref ref="STDOUT" /> + </root> +</configuration> diff --git a/winery/org.eclipse.winery.repository/src/main/resources/logback.xml b/winery/org.eclipse.winery.repository/src/main/resources/logback.xml new file mode 100644 index 0000000..f0f7e87 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/resources/logback.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line %method - %msg%n</pattern> + </encoder> + </appender> + + <logger name="org.eclipse.winery" level="DEBUG"/> + <logger name="org.apache.catalina.core.ApplicationDispatcher" level="SEVERE"/> + + <root level="info"> + <appender-ref ref="STDOUT" /> + </root> +</configuration> diff --git a/winery/org.eclipse.winery.repository/src/main/resources/mime-types.properties b/winery/org.eclipse.winery.repository/src/main/resources/mime-types.properties new file mode 100644 index 0000000..ef7ae8b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/resources/mime-types.properties @@ -0,0 +1,19 @@ +############################################################################################# +# # +# Mime type mappings for file extensions. The entries in this file overide those # +# that are set in the supplied internal mime-type.properties file # +# # +# EDIT THIS FILE - This file should be changed to add to the default mime types # +# or override the settings in the default mime-types.properties file. # +# # +############################################################################################# + +# These entries override the mime-type definitions in the supplied list +json=application/json +sh=application/x-sh +war=application/x-zip +wsdl=application/wsdl+xml + +# The following entries do not exist in the full mime-type list +#props=text/plain +#conf=text/plain diff --git a/winery/org.eclipse.winery.repository/src/main/templates/Version.java b/winery/org.eclipse.winery.repository/src/main/templates/Version.java new file mode 100644 index 0000000..5f5dc55 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/templates/Version.java @@ -0,0 +1,7 @@ +package org.eclipse.winery.repository; + +public final class Version { + + public static String VERSION="${project.version}"; + +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.js b/winery/org.eclipse.winery.repository/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.js new file mode 100644 index 0000000..6eccbfe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.js @@ -0,0 +1,14987 @@ +/*! jQuery UI - v1.10.2 - 2013-03-14 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ +(function( $, undefined ) { + +var uuid = 0, + runiqueId = /^ui-id-\d+$/; + +// $.ui might exist from components with no dependencies, e.g., $.ui.position +$.ui = $.ui || {}; + +$.extend( $.ui, { + version: "1.10.2", + + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 + } +}); + +// plugins +$.fn.extend({ + focus: (function( orig ) { + return function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + orig.apply( this, arguments ); + }; + })( $.fn.focus ), + + scrollParent: function() { + var scrollParent; + if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); + }).eq(0); + } + + return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; + }, + + zIndex: function( zIndex ) { + if ( zIndex !== undefined ) { + return this.css( "zIndex", zIndex ); + } + + if ( this.length ) { + var elem = $( this[ 0 ] ), position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> + value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + }, + + uniqueId: function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + (++uuid); + } + }); + }, + + removeUniqueId: function() { + return this.each(function() { + if ( runiqueId.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + }); + } +}); + +// selectors +function focusable( element, isTabIndexNotNaN ) { + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap=#" + mapName + "]" )[0]; + return !!img && visible( img ); + } + return ( /input|select|textarea|button|object/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible( element ); +} + +function visible( element ) { + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; +} + +$.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + isTabIndexNaN = isNaN( tabIndex ); + return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); + } +}); + +// support: jQuery <1.8 +if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; + }); +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} + + + + + +// deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.support.selectstart = "onselectstart" in document.createElement( "div" ); +$.fn.extend({ + disableSelection: function() { + return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }, + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + } +}); + +$.extend( $.ui, { + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args ) { + var i, + set = instance.plugins[ name ]; + if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } + }, + + // only used by resizable + hasScroll: function( el, a ) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ( $( el ).css( "overflow" ) === "hidden") { + return false; + } + + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", + has = false; + + if ( el[ scroll ] > 0 ) { + return true; + } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[ scroll ] = 1; + has = ( el[ scroll ] > 0 ); + el[ scroll ] = 0; + return has; + } +}); + +})( jQuery ); + +(function( $, undefined ) { + +var uuid = 0, + slice = Array.prototype.slice, + _cleanData = $.cleanData; +$.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); +}; + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); +}; + +$.widget.extend = function( target ) { + var input = slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.widget.extend.apply( null, [ options ].concat(args) ) : + options; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} )._init(); + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "<div>", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( value === undefined ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( value === undefined ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +})( jQuery ); + +(function( $, undefined ) { + +var mouseHandled = false; +$( document ).mouseup( function() { + mouseHandled = false; +}); + +$.widget("ui.mouse", { + version: "1.10.2", + options: { + cancel: "input,textarea,button,select,option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .bind("mousedown."+this.widgetName, function(event) { + return that._mouseDown(event); + }) + .bind("click."+this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); + event.stopImmediatePropagation(); + return false; + } + }); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind("."+this.widgetName); + if ( this._mouseMoveDelegate ) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + } + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + if( mouseHandled ) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = (event.which === 1), + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + that.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return that._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return that._mouseUp(event); + }; + $(document) + .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .bind("mouseup."+this.widgetName, this._mouseUpDelegate); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); + } + + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(/* event */) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } +}); + +})(jQuery); + +(function( $, undefined ) { + +$.widget("ui.draggable", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "drag", + options: { + addClasses: true, + appendTo: "parent", + axis: false, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null + }, + _create: function() { + + if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { + this.element[0].style.position = "relative"; + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } + + this._mouseInit(); + + }, + + _destroy: function() { + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + + var o = this.options; + + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { + return false; + } + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) { + return false; + } + + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>") + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + + return true; + + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + this.helper.addClass("ui-draggable-dragging"); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css("position"); + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.positionAbs = this.element.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this.position = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + //Trigger event + callbacks + if(this._trigger("start", event) === false) { + this._clear(); + return false; + } + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } + + return true; + }, + + _mouseDrag: function(event, noPropagation) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + if(this._trigger("drag", event, ui) === false) { + this._mouseUp({}); + return false; + } + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var element, + that = this, + elementInDom = false, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { + dropped = $.ui.ddmanager.drop(this, event); + } + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + //if the original element is no longer in the DOM don't bother to continue (see #8269) + element = this.element[0]; + while ( element && (element = element.parentNode) ) { + if (element === document ) { + elementInDom = true; + } + } + if ( !elementInDom && this.options.helper === "original" ) { + return false; + } + + if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + if(that._trigger("stop", event) !== false) { + that._clear(); + } + }); + } else { + if(this._trigger("stop", event) !== false) { + this._clear(); + } + } + + return false; + }, + + _mouseUp: function(event) { + //Remove frame helpers + $("div.ui-draggable-iframeFix").each(function() { + this.parentNode.removeChild(this); + }); + + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) + if( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } + + return $.ui.mouse.prototype._mouseUp.call(this, event); + }, + + cancel: function() { + + if(this.helper.is(".ui-draggable-dragging")) { + this._mouseUp({}); + } else { + this._clear(); + } + + return this; + + }, + + _getHandle: function(event) { + return this.options.handle ? + !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : + true; + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); + + if(!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } + + if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { + helper.css("position", "absolute"); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + //This needs to be actually done for all browsers, since pageX/pageY includes this information + //Ugly IE fix + if((this.offsetParent[0] === document.body) || + (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0), + right: (parseInt(this.element.css("marginRight"),10) || 0), + bottom: (parseInt(this.element.css("marginBottom"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var over, c, ce, + o = this.options; + + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + o.containment === "document" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + o.containment === "document" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, + (o.containment === "document" ? 0 : $(window).scrollLeft()) + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + (o.containment === "document" ? 0 : $(window).scrollTop()) + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) { + c = $(o.containment); + ce = c[0]; + + if(!ce) { + return; + } + + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), + (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderRightWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, + (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderBottomWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom + ]; + this.relative_container = c; + + } else if(o.containment.constructor === Array) { + this.containment = o.containment; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var containment, co, top, left, + o = this.options, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName), + pageX = event.pageX, + pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + if(this.containment) { + if (this.relative_container){ + co = this.relative_container.offset(); + containment = [ this.containment[0] + co.left, + this.containment[1] + co.top, + this.containment[2] + co.left, + this.containment[3] + co.top ]; + } + else { + containment = this.containment; + } + + if(event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + //The absolute position has to be recalculated after plugins + if(type === "drag") { + this.positionAbs = this._convertPositionTo("absolute"); + } + return $.Widget.prototype._trigger.call(this, type, event, ui); + }, + + plugins: {}, + + _uiHash: function() { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs + }; + } + +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { + + var inst = $(this).data("ui-draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, "ui-sortable"); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). + sortable._trigger("activate", event, uiSortable); + } + }); + + }, + stop: function(event, ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("ui-draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + + this.instance.isOver = 0; + + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" + if(this.shouldRevert) { + this.instance.options.revert = this.shouldRevert; + } + + //Trigger the stop of the sortable + this.instance._mouseStop(event); + + this.instance.options.helper = this.instance.options._helper; + + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper === "original") { + this.instance.currentItem.css({ top: "auto", left: "auto" }); + } + + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } + + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("ui-draggable"), that = this; + + $.each(inst.sortables, function() { + + var innermostIntersecting = false, + thisSortable = this; + + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + + if(this.instance._intersectsWith(this.instance.containerCache)) { + innermostIntersecting = true; + $.each(inst.sortables, function () { + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + if (this !== thisSortable && + this.instance._intersectsWith(this.instance.containerCache) && + $.contains(thisSortable.instance.element[0], this.instance.element[0]) + ) { + innermostIntersecting = false; + } + return innermostIntersecting; + }); + } + + + if(innermostIntersecting) { + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) { + this.instance._mouseDrag(event); + } + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + + //Prevent reverting on this forced stop + this.instance.options.revert = false; + + // The out event needs to be triggered independently + this.instance._trigger("out", event, this.instance._uiHash(this.instance)); + + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) { + this.instance.placeholder.remove(); + } + + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } + + } + + }); + + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function() { + var t = $("body"), o = $(this).data("ui-draggable").options; + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } + t.css("cursor", o.cursor); + }, + stop: function() { + var o = $(this).data("ui-draggable").options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function() { + var i = $(this).data("ui-draggable"); + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + i.overflowOffset = i.scrollParent.offset(); + } + }, + drag: function( event ) { + + var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; + + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + + if(!o.axis || o.axis !== "x") { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } + } + + if(!o.axis || o.axis !== "y") { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } + } + + } else { + + if(!o.axis || o.axis !== "x") { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + } + + if(!o.axis || o.axis !== "y") { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(i, event); + } + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function() { + + var i = $(this).data("ui-draggable"), + o = i.options; + + i.snapElements = []; + + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if(this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } + }); + + }, + drag: function(event, ui) { + + var ts, bs, ls, rs, l, r, t, b, i, first, + inst = $(this).data("ui-draggable"), + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (i = inst.snapElements.length - 1; i >= 0; i--){ + + l = inst.snapElements[i].left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top; + b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + } + + first = (ts || bs || ls || rs); + + if(o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + } + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function() { + var min, + o = this.data("ui-draggable").options, + group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); + + if (!group.length) { return; } + + min = parseInt($(group[0]).css("zIndex"), 10) || 0; + $(group).each(function(i) { + $(this).css("zIndex", min + i); + }); + this.css("zIndex", (min + group.length)); + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } + } +}); + +})(jQuery); + +(function( $, undefined ) { + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +$.widget("ui.droppable", { + version: "1.10.2", + widgetEventPrefix: "drop", + options: { + accept: "*", + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null + }, + _create: function() { + + var o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; + + this.accept = $.isFunction(accept) ? accept : function(d) { + return d.is(accept); + }; + + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; + $.ui.ddmanager.droppables[o.scope].push(this); + + (o.addClasses && this.element.addClass("ui-droppable")); + + }, + + _destroy: function() { + var i = 0, + drop = $.ui.ddmanager.droppables[this.options.scope]; + + for ( ; i < drop.length; i++ ) { + if ( drop[i] === this ) { + drop.splice(i, 1); + } + } + + this.element.removeClass("ui-droppable ui-droppable-disabled"); + }, + + _setOption: function(key, value) { + + if(key === "accept") { + this.accept = $.isFunction(value) ? value : function(d) { + return d.is(value); + }; + } + $.Widget.prototype._setOption.apply(this, arguments); + }, + + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.addClass(this.options.activeClass); + } + if(draggable){ + this._trigger("activate", event, this.ui(draggable)); + } + }, + + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(draggable){ + this._trigger("deactivate", event, this.ui(draggable)); + } + }, + + _over: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.addClass(this.options.hoverClass); + } + this._trigger("over", event, this.ui(draggable)); + } + + }, + + _out: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("out", event, this.ui(draggable)); + } + + }, + + _drop: function(event,custom) { + + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return false; + } + + this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, "ui-droppable"); + if( + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && + $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + ) { childrenIntersection = true; return false; } + }); + if(childrenIntersection) { + return false; + } + + if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("drop", event, this.ui(draggable)); + return this.element; + } + + return false; + + }, + + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + } + +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) { + return false; + } + + var draggableLeft, draggableTop, + x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; + + switch (toleranceMode) { + case "fit": + return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); + case "intersect": + return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half + x2 - (draggable.helperProportions.width / 2) < r && // Left Half + t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half + y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + case "pointer": + draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); + return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); + case "touch": + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + default: + return false; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { "default": [] }, + prepareOffsets: function(t, event) { + + var i, j, + m = $.ui.ddmanager.droppables[t.options.scope] || [], + type = event ? event.type : null, // workaround for #2317 + list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); + + droppablesLoop: for (i = 0; i < m.length; i++) { + + //No disabled and non-accepted + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { + continue; + } + + // Filter out elements in the current dragged item + for (j=0; j < list.length; j++) { + if(list[j] === m[i].element[0]) { + m[i].proportions.height = 0; + continue droppablesLoop; + } + } + + m[i].visible = m[i].element.css("display") !== "none"; + if(!m[i].visible) { + continue; + } + + //Activate the droppable if used directly from draggables + if(type === "mousedown") { + m[i]._activate.call(m[i], event); + } + + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; + + } + + }, + drop: function(draggable, event) { + + var dropped = false; + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { + + if(!this.options) { + return; + } + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { + dropped = this._drop.call(this, event) || dropped; + } + + if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = true; + this.isover = false; + this._deactivate.call(this, event); + } + + }); + return dropped; + + }, + dragStart: function( draggable, event ) { + //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + }); + }, + drag: function(draggable, event) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) { + $.ui.ddmanager.prepareOffsets(draggable, event); + } + + //Run through all droppables and check their positions based on specific tolerance options + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) { + return; + } + + var parentInstance, scope, parent, + intersects = $.ui.intersect(draggable, this, this.options.tolerance), + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + if(!c) { + return; + } + + if (this.options.greedy) { + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents(":data(ui-droppable)").filter(function () { + return $.data(this, "ui-droppable").options.scope === scope; + }); + + if (parent.length) { + parentInstance = $.data(parent[0], "ui-droppable"); + parentInstance.greedyChild = (c === "isover"); + } + } + + // we just moved into a greedy child + if (parentInstance && c === "isover") { + parentInstance.isover = false; + parentInstance.isout = true; + parentInstance._out.call(parentInstance, event); + } + + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call(this, event); + + // we just moved out of a greedy child + if (parentInstance && c === "isout") { + parentInstance.isout = false; + parentInstance.isover = true; + parentInstance._over.call(parentInstance, event); + } + }); + + }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); + //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } +}; + +})(jQuery); + +(function( $, undefined ) { + +function num(v) { + return parseInt(v, 10) || 0; +} + +function isNumber(value) { + return !isNaN(parseInt(value, 10)); +} + +$.widget("ui.resizable", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "resize", + options: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + containment: false, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + // See #7960 + zIndex: 90, + + // callbacks + resize: null, + start: null, + stop: null + }, + _create: function() { + + var n, i, handle, axis, hname, + that = this, + o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null + }); + + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { + + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ + position: this.element.css("position"), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css("top"), + left: this.element.css("left") + }) + ); + + //Overwrite the original this.element + this.element = this.element.parent().data( + "ui-resizable", this.element.data("ui-resizable") + ); + + this.elementIsWrapper = true; + + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css("resize"); + this.originalElement.css("resize", "none"); + + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); + + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css("margin") }); + + // fix handlers offset + this._proportionallyResize(); + + } + + this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); + if(this.handles.constructor === String) { + + if ( this.handles === "all") { + this.handles = "n,e,s,w,se,sw,ne,nw"; + } + + n = this.handles.split(","); + this.handles = {}; + + for(i = 0; i < n.length; i++) { + + handle = $.trim(n[i]); + hname = "ui-resizable-"+handle; + axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); + + // Apply zIndex to all handles - see #7960 + axis.css({ zIndex: o.zIndex }); + + //TODO : What's going on here? + if ("se" === handle) { + axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); + } + + //Insert into internal handles object and append to element + this.handles[handle] = ".ui-resizable-"+handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + var i, axis, padPos, padWrapper; + + target = target || this.element; + + for(i in this.handles) { + + if(this.handles[i].constructor === String) { + this.handles[i] = $(this.handles[i], this.element).show(); + } + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + axis = $(this.handles[i], this.element); + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + padPos = [ "padding", + /ne|nw|n/.test(i) ? "Top" : + /se|sw|s/.test(i) ? "Bottom" : + /^e$/.test(i) ? "Right" : "Left" ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + + } + + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) { + continue; + } + } + }; + + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = $(".ui-resizable-handle", this.element) + .disableSelection(); + + //Matching axis name + this._handles.mouseover(function() { + if (!that.resizing) { + if (this.className) { + axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + } + //Axis, default = se + that.axis = axis && axis[1] ? axis[1] : "se"; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .mouseenter(function() { + if (o.disabled) { + return; + } + $(this).removeClass("ui-resizable-autohide"); + that._handles.show(); + }) + .mouseleave(function(){ + if (o.disabled) { + return; + } + if (!that.resizing) { + $(this).addClass("ui-resizable-autohide"); + that._handles.hide(); + } + }); + } + + //Initialize the mouse interaction + this._mouseInit(); + + }, + + _destroy: function() { + + this._mouseDestroy(); + + var wrapper, + _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + wrapper = this.element; + this.originalElement.css({ + position: wrapper.css("position"), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css("top"), + left: wrapper.css("left") + }).insertAfter( wrapper ); + wrapper.remove(); + } + + this.originalElement.css("resize", this.originalResizeStyle); + _destroy(this.originalElement); + + return this; + }, + + _mouseCapture: function(event) { + var i, handle, + capture = false; + + for (i in this.handles) { + handle = $(this.handles[i])[0]; + if (handle === event.target || $.contains(handle, event.target)) { + capture = true; + } + } + + return !this.options.disabled && capture; + }, + + _mouseStart: function(event) { + + var curleft, curtop, cursor, + o = this.options, + iniPos = this.element.position(), + el = this.element; + + this.resizing = true; + + // bugfix for http://dev.jquery.com/ticket/1749 + if ( (/absolute/).test( el.css("position") ) ) { + el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); + } else if (el.is(".ui-draggable")) { + el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); + } + + this._renderProxy(); + + curleft = num(this.helper.css("left")); + curtop = num(this.helper.css("top")); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + + cursor = $(".ui-resizable-" + this.axis).css("cursor"); + $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var data, + el = this.helper, props = {}, + smp = this.originalMousePosition, + a = this.axis, + prevTop = this.position.top, + prevLeft = this.position.left, + prevWidth = this.size.width, + prevHeight = this.size.height, + dx = (event.pageX-smp.left)||0, + dy = (event.pageY-smp.top)||0, + trigger = this._change[a]; + + if (!trigger) { + return false; + } + + // Calculate the attrs that will be change + data = trigger.apply(this, [event, dx, dy]); + + // Put this in the mouseDrag handler since the user can start pressing shift while resizing + this._updateVirtualBoundaries(event.shiftKey); + if (this._aspectRatio || event.shiftKey) { + data = this._updateRatio(data, event); + } + + data = this._respectSize(data, event); + + this._updateCache(data); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + if (this.position.top !== prevTop) { + props.top = this.position.top + "px"; + } + if (this.position.left !== prevLeft) { + props.left = this.position.left + "px"; + } + if (this.size.width !== prevWidth) { + props.width = this.size.width + "px"; + } + if (this.size.height !== prevHeight) { + props.height = this.size.height + "px"; + } + el.css(props); + + if (!this._helper && this._proportionallyResizeElements.length) { + this._proportionallyResize(); + } + + // Call the user callback if the element was resized + if ( ! $.isEmptyObject(props) ) { + this._trigger("resize", event, this.ui()); + } + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var pr, ista, soffseth, soffsetw, s, left, top, + o = this.options, that = this; + + if(this._helper) { + + pr = this._proportionallyResizeElements; + ista = pr.length && (/textarea/i).test(pr[0].nodeName); + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; + soffsetw = ista ? 0 : that.sizeDiff.width; + + s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) { + this.element.css($.extend(s, { top: top, left: left })); + } + + that.helper.height(that.size.height); + that.helper.width(that.size.width); + + if (this._helper && !o.animate) { + this._proportionallyResize(); + } + } + + $("body").css("cursor", "auto"); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) { + this.helper.remove(); + } + + return false; + + }, + + _updateVirtualBoundaries: function(forceAspectRatio) { + var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, + o = this.options; + + b = { + minWidth: isNumber(o.minWidth) ? o.minWidth : 0, + maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, + minHeight: isNumber(o.minHeight) ? o.minHeight : 0, + maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity + }; + + if(this._aspectRatio || forceAspectRatio) { + // We want to create an enclosing box whose aspect ration is the requested one + // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension + pMinWidth = b.minHeight * this.aspectRatio; + pMinHeight = b.minWidth / this.aspectRatio; + pMaxWidth = b.maxHeight * this.aspectRatio; + pMaxHeight = b.maxWidth / this.aspectRatio; + + if(pMinWidth > b.minWidth) { + b.minWidth = pMinWidth; + } + if(pMinHeight > b.minHeight) { + b.minHeight = pMinHeight; + } + if(pMaxWidth < b.maxWidth) { + b.maxWidth = pMaxWidth; + } + if(pMaxHeight < b.maxHeight) { + b.maxHeight = pMaxHeight; + } + } + this._vBoundaries = b; + }, + + _updateCache: function(data) { + this.offset = this.helper.offset(); + if (isNumber(data.left)) { + this.position.left = data.left; + } + if (isNumber(data.top)) { + this.position.top = data.top; + } + if (isNumber(data.height)) { + this.size.height = data.height; + } + if (isNumber(data.width)) { + this.size.width = data.width; + } + }, + + _updateRatio: function( data ) { + + var cpos = this.position, + csize = this.size, + a = this.axis; + + if (isNumber(data.height)) { + data.width = (data.height * this.aspectRatio); + } else if (isNumber(data.width)) { + data.height = (data.width / this.aspectRatio); + } + + if (a === "sw") { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a === "nw") { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function( data ) { + + var o = this._vBoundaries, + a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), + dw = this.originalPosition.left + this.originalSize.width, + dh = this.position.top + this.size.height, + cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + if (isminw) { + data.width = o.minWidth; + } + if (isminh) { + data.height = o.minHeight; + } + if (ismaxw) { + data.width = o.maxWidth; + } + if (ismaxh) { + data.height = o.maxHeight; + } + + if (isminw && cw) { + data.left = dw - o.minWidth; + } + if (ismaxw && cw) { + data.left = dw - o.maxWidth; + } + if (isminh && ch) { + data.top = dh - o.minHeight; + } + if (ismaxh && ch) { + data.top = dh - o.maxHeight; + } + + // fixing jump error on top/left - bug #2330 + if (!data.width && !data.height && !data.left && data.top) { + data.top = null; + } else if (!data.width && !data.height && !data.top && data.left) { + data.left = null; + } + + return data; + }, + + _proportionallyResize: function() { + + if (!this._proportionallyResizeElements.length) { + return; + } + + var i, j, borders, paddings, prel, + element = this.helper || this.element; + + for ( i=0; i < this._proportionallyResizeElements.length; i++) { + + prel = this._proportionallyResizeElements[i]; + + if (!this.borderDif) { + this.borderDif = []; + borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; + paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; + + for ( j = 0; j < borders.length; j++ ) { + this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); + } + } + + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); + + } + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(this._helper) { + + this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: "absolute", + left: this.elementOffset.left +"px", + top: this.elementOffset.top +"px", + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx) { + var cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n !== "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "animate", { + + stop: function( event ) { + var that = $(this).data("ui-resizable"), + o = that.options, + pr = that._proportionallyResizeElements, + ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width, + style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + that.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(that.element.css("width"), 10), + height: parseInt(that.element.css("height"), 10), + top: parseInt(that.element.css("top"), 10), + left: parseInt(that.element.css("left"), 10) + }; + + if (pr && pr.length) { + $(pr[0]).css({ width: data.width, height: data.height }); + } + + // propagating resize, and updating values for each animation step + that._updateCache(data); + that._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "containment", { + + start: function() { + var element, p, co, ch, cw, width, height, + that = $(this).data("ui-resizable"), + o = that.options, + el = that.element, + oc = o.containment, + ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + + if (!ce) { + return; + } + + that.containerElement = $(ce); + + if (/document/.test(oc) || oc === document) { + that.containerOffset = { left: 0, top: 0 }; + that.containerPosition = { left: 0, top: 0 }; + + that.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + // i'm a node, so compute top, left, right, bottom + else { + element = $(ce); + p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); + + that.containerOffset = element.offset(); + that.containerPosition = element.position(); + that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + co = that.containerOffset; + ch = that.containerSize.height; + cw = that.containerSize.width; + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); + height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + that.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function( event ) { + var woset, hoset, isParent, isOffsetRelative, + that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, + cop = { top:0, left:0 }, ce = that.containerElement; + + if (ce[0] !== document && (/static/).test(ce.css("position"))) { + cop = co; + } + + if (cp.left < (that._helper ? co.left : 0)) { + that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + that.position.left = o.helper ? co.left : 0; + } + + if (cp.top < (that._helper ? co.top : 0)) { + that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + that.position.top = that._helper ? co.top : 0; + } + + that.offset.left = that.parentData.left+that.position.left; + that.offset.top = that.parentData.top+that.position.top; + + woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); + hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); + + isParent = that.containerElement.get(0) === that.element.parent().get(0); + isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); + + if(isParent && isOffsetRelative) { + woset -= that.parentData.left; + } + + if (woset + that.size.width >= that.parentData.width) { + that.size.width = that.parentData.width - woset; + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + } + + if (hoset + that.size.height >= that.parentData.height) { + that.size.height = that.parentData.height - hoset; + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + } + }, + + stop: function(){ + var that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, + cop = that.containerPosition, + ce = that.containerElement, + helper = $(that.helper), + ho = helper.offset(), + w = helper.outerWidth() - that.sizeDiff.width, + h = helper.outerHeight() - that.sizeDiff.height; + + if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + } +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function () { + var that = $(this).data("ui-resizable"), + o = that.options, + _store = function (exp) { + $(exp).each(function() { + var el = $(this); + el.data("ui-resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) + }); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function (exp) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function (event, ui) { + var that = $(this).data("ui-resizable"), + o = that.options, + os = that.originalSize, + op = that.originalPosition, + delta = { + height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 + }, + + _alsoResize = function (exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, + css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; + + $.each(css, function (i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) { + style[prop] = sum || null; + } + }); + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function () { + $(this).removeData("resizable-alsoresize"); + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function() { + + var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; + + that.ghost = that.originalElement.clone(); + that.ghost + .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass("ui-resizable-ghost") + .addClass(typeof o.ghost === "string" ? o.ghost : ""); + + that.ghost.appendTo(that.helper); + + }, + + resize: function(){ + var that = $(this).data("ui-resizable"); + if (that.ghost) { + that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); + } + }, + + stop: function() { + var that = $(this).data("ui-resizable"); + if (that.ghost && that.helper) { + that.helper.get(0).removeChild(that.ghost.get(0)); + } + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function() { + var that = $(this).data("ui-resizable"), + o = that.options, + cs = that.size, + os = that.originalSize, + op = that.originalPosition, + a = that.axis, + grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, + gridX = (grid[0]||1), + gridY = (grid[1]||1), + ox = Math.round((cs.width - os.width) / gridX) * gridX, + oy = Math.round((cs.height - os.height) / gridY) * gridY, + newWidth = os.width + ox, + newHeight = os.height + oy, + isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), + isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), + isMinWidth = o.minWidth && (o.minWidth > newWidth), + isMinHeight = o.minHeight && (o.minHeight > newHeight); + + o.grid = grid; + + if (isMinWidth) { + newWidth = newWidth + gridX; + } + if (isMinHeight) { + newHeight = newHeight + gridY; + } + if (isMaxWidth) { + newWidth = newWidth - gridX; + } + if (isMaxHeight) { + newHeight = newHeight - gridY; + } + + if (/^(se|s|e)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + } else if (/^(ne)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + } else if (/^(sw)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.left = op.left - ox; + } else { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + that.position.left = op.left - ox; + } + } + +}); + +})(jQuery); + +(function( $, undefined ) { + +$.widget("ui.selectable", $.ui.mouse, { + version: "1.10.2", + options: { + appendTo: "body", + autoRefresh: true, + distance: 0, + filter: "*", + tolerance: "touch", + + // callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null + }, + _create: function() { + var selectees, + that = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + this.refresh = function() { + selectees = $(that.options.filter, that.element[0]); + selectees.addClass("ui-selectee"); + selectees.each(function() { + var $this = $(this), + pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass("ui-selected"), + selecting: $this.hasClass("ui-selecting"), + unselecting: $this.hasClass("ui-unselecting") + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $("<div class='ui-selectable-helper'></div>"); + }, + + _destroy: function() { + this.selectees + .removeClass("ui-selectee") + .removeData("selectable-item"); + this.element + .removeClass("ui-selectable ui-selectable-disabled"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var that = this, + options = this.options; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) { + return; + } + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "left": event.pageX, + "top": event.pageY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter(".ui-selected").each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey && !event.ctrlKey) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().addBack().each(function() { + var doSelect, + selectee = $.data(this, "selectable-item"); + if (selectee) { + doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); + selectee.$element + .removeClass(doSelect ? "ui-unselecting" : "ui-selected") + .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + // selectable (UN)SELECTING callback + if (doSelect) { + that._trigger("selecting", event, { + selecting: selectee.element + }); + } else { + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + return false; + } + }); + + }, + + _mouseDrag: function(event) { + + this.dragged = true; + + if (this.options.disabled) { + return; + } + + var tmp, + that = this, + options = this.options, + x1 = this.opos[0], + y1 = this.opos[1], + x2 = event.pageX, + y2 = event.pageY; + + if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"), + hit = false; + + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element === that.element[0]) { + return; + } + + if (options.tolerance === "touch") { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance === "fit") { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass("ui-selecting"); + selectee.selecting = true; + // selectable SELECTING callback + that._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if ((event.metaKey || event.ctrlKey) && selectee.startselected) { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + selectee.$element.addClass("ui-selected"); + selectee.selected = true; + } else { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var that = this; + + this.dragged = false; + + $(".ui-unselecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $(".ui-selecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +}); + +})(jQuery); + +(function( $, undefined ) { + +/*jshint loopfunc: true */ + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +function isFloating(item) { + return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); +} + +$.widget("ui.sortable", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "sort", + ready: false, + options: { + appendTo: "parent", + axis: false, + connectWith: false, + containment: false, + cursor: "auto", + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: "> *", + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000, + + // callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null + }, + _create: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are being displayed horizontally + this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + //We're ready to go + this.ready = true; + + }, + + _destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) { + this.items[i].item.removeData(this.widgetName + "-item"); + } + + return this; + }, + + _setOption: function(key, value){ + if ( key === "disabled" ) { + this.options[ key ] = value; + + this.widget().toggleClass( "ui-sortable-disabled", !!value ); + } else { + // Don't call widget base _setOption for disable as it adds ui-state-disabled class + $.Widget.prototype._setOption.apply(this, arguments); + } + }, + + _mouseCapture: function(event, overrideHandle) { + var currentItem = null, + validHandle = false, + that = this; + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type === "static") { + return false; + } + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + $(event.target).parents().each(function() { + if($.data(this, that.widgetName + "-item") === that) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, that.widgetName + "-item") === that) { + currentItem = $(event.target); + } + + if(!currentItem) { + return false; + } + if(this.options.handle && !overrideHandle) { + $(this.options.handle, currentItem).find("*").addBack().each(function() { + if(this === event.target) { + validHandle = true; + } + }); + if(!validHandle) { + return false; + } + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var i, body, + o = this.options; + + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] !== this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + if( o.cursor && o.cursor !== "auto" ) { // cursor option + body = this.document.find( "body" ); + + // support: IE + this.storedCursor = body.css( "cursor" ); + body.css( "cursor", o.cursor ); + + this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) { + this._storedOpacity = this.helper.css("opacity"); + } + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) { + this._storedZIndex = this.helper.css("zIndex"); + } + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + this.overflowOffset = this.scrollParent.offset(); + } + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) { + this._cacheHelperProportions(); + } + + + //Post "activate" events to possible containers + if( !noActivation ) { + for ( i = this.containers.length - 1; i >= 0; i-- ) { + this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); + } + } + + //Prepare possible droppables + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + var i, item, itemElement, intersection, + o = this.options, + scrolled = false; + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + + //Rearrange + for (i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } + + // Only put the placeholder inside the current Container, skip all + // items form other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this moving items in "sub-sortables" can cause the placeholder to jitter + // beetween the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } + + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection === 1 ? "down" : "up"; + + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + //Call callbacks + this._trigger("sort", event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) { + return; + } + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) { + $.ui.ddmanager.drop(this, event); + } + + if(this.options.revert) { + var that = this, + cur = this.placeholder.offset(), + axis = this.options.axis, + animation = {}; + + if ( !axis || axis === "x" ) { + animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); + } + if ( !axis || axis === "y" ) { + animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); + } + this.reverting = true; + $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { + that._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + if(this.dragging) { + + this._mouseUp({ target: null }); + + if(this.options.helper === "original") { + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, this._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + if (this.placeholder) { + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { + this.helper.remove(); + } + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); + } + }); + + if(!str.length && o.key) { + str.push(o.key + "="); + } + + return str.join("&"); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height, + l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if ( this.options.tolerance === "pointer" || + this.options.forcePointerForContainers || + (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) && // Right Half + x2 - (this.helperProportions.width / 2) < r && // Left Half + t < y1 + (this.helperProportions.height / 2) && // Bottom Half + y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) { + return false; + } + + return this.floating ? + ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta !== 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta !== 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + return this; + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var i, j, cur, inst, + items = [], + queries = [], + connectWith = this._connectWith(); + + if(connectWith && connected) { + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for ( j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); + } + } + } + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); + + for (i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + } + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); + + this.items = $.grep(this.items, function (item) { + for (var j=0; j < list.length; j++) { + if(list[j] === item.item[0]) { + return false; + } + } + return true; + }); + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + + var i, j, cur, inst, targetData, _queries, item, queriesLength, + items = this.items, + queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], + connectWith = this._connectWith(); + + if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for (j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + } + } + } + + for (i = queries.length - 1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; + + for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); + + item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + } + } + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + var i, item, t, p; + + for (i = this.items.length - 1; i >= 0; i--){ + item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { + continue; + } + + t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + p = t.offset(); + item.left = p.left; + item.top = p.top; + } + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (i = this.containers.length - 1; i >= 0; i--){ + p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + } + } + + return this; + }, + + _createPlaceholder: function(that) { + that = that || this; + var className, + o = that.options; + + if(!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; + o.placeholder = { + element: function() { + + var nodeName = that.currentItem[0].nodeName.toLowerCase(), + element = $( that.document[0].createElement( nodeName ) ) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper"); + + if ( nodeName === "tr" ) { + // Use a high colspan to force the td to expand the full + // width of the table (browsers are smart enough to + // handle this properly) + element.append( "<td colspan='99'> </td>" ); + } else if ( nodeName === "img" ) { + element.attr( "src", that.currentItem.attr( "src" ) ); + } + + if ( !className ) { + element.css( "visibility", "hidden" ); + } + + return element; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) { + return; + } + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } + } + }; + } + + //Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + //Append it after the actual current item + that.currentItem.after(that.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); + + }, + + _contactContainers: function(event) { + var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, + innermostContainer = null, + innermostIndex = null; + + // get innermost container that intersects with item + for (i = this.containers.length - 1; i >= 0; i--) { + + // never consider a container that's located within the item itself + if($.contains(this.currentItem[0], this.containers[i].element[0])) { + continue; + } + + if(this._intersectsWith(this.containers[i].containerCache)) { + + // if we've already found a container and it's more "inner" than this, then continue + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { + continue; + } + + innermostContainer = this.containers[i]; + innermostIndex = i; + + } else { + // container doesn't intersect. trigger "out" event if necessary + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + // if no intersecting containers found, return + if(!innermostContainer) { + return; + } + + // move the item into the container if it's not there already + if(this.containers.length === 1) { + if (!this.containers[innermostIndex].containerCache.over) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + } else { + + //When entering a new container, we will find the item with the least distance and append our item near it + dist = 10000; + itemWithLeastDistance = null; + floating = innermostContainer.floating || isFloating(this.currentItem); + posProperty = floating ? "left" : "top"; + sizeProperty = floating ? "width" : "height"; + base = this.positionAbs[posProperty] + this.offset.click[posProperty]; + for (j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { + continue; + } + if(this.items[j].item[0] === this.currentItem[0]) { + continue; + } + if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { + continue; + } + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; + if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ + nearBottom = true; + cur += this.items[j][sizeProperty]; + } + + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + this.direction = nearBottom ? "up": "down"; + } + } + + //Check if dropOnEmpty is enabled + if(!itemWithLeastDistance && !this.options.dropOnEmpty) { + return; + } + + if(this.currentContainer === this.containers[innermostIndex]) { + return; + } + + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); + this.currentContainer = this.containers[innermostIndex]; + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + + + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); + + //Add the helper to the DOM if that didn't happen already + if(!helper.parents("body").length) { + $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + } + + if(helper[0] === this.currentItem[0]) { + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + } + + if(!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if(!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + // This needs to be actually done for all browsers, since pageX/pageY includes this information + // with an ugly IE fix + if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var ce, co, over, + o = this.options; + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment)) { + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var top, left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) { + pageX = this.containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < this.containment[1]) { + pageY = this.containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > this.containment[2]) { + pageX = this.containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > this.containment[3]) { + pageY = this.containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if(counter === this.counter) { + this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + } + }); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var i, + delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } + this._noFinalSort = null; + + if(this.helper[0] === this.currentItem[0]) { + for(i in this._storedCSS) { + if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { + this._storedCSS[i] = ""; + } + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + } + if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + } + + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if(!noPropagation) { + delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + } + } + + + //Post events to containers + for (i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + } + if(this.containers[i].containerCache.over) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if ( this.storedCursor ) { + this.document.find( "body" ).css( "cursor", this.storedCursor ); + this.storedStylesheet.remove(); + } + if(this._storedOpacity) { + this.helper.css("opacity", this._storedOpacity); + } + if(this._storedZIndex) { + this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); + } + + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return false; + } + + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] !== this.currentItem[0]) { + this.helper.remove(); + } + this.helper = null; + + if(!noPropagation) { + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return true; + + }, + + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null + }; + } + +}); + +})(jQuery); + +(function($, undefined) { + +var dataSpace = "ui-effects-"; + +$.effects = { + effect: {} +}; + +/*! + * jQuery Color Animations v2.1.2 + * https://github.com/jquery/jquery-color + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Wed Jan 16 08:47:09 2013 -0600 + */ +(function( jQuery, undefined ) { + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + // a set of RE's that can match strings and generate color tuples. + stringParsers = [{ + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ) + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + }], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, + + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + support = color.support = {}, + + // element for support tests + supportElem = jQuery( "<p>" )[ 0 ], + + // colors = jQuery.Color.names + colors, + + // local aliases of functions called often + each = jQuery.each; + +// determine rgba support immediately +supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; +support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; + +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +}); + +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + + if ( value == null ) { + return (allowEmpty || !prop.def) ? null : prop.def; + } + + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); + + // IE will pass in empty strings as value for alpha, + // which will hit this case + if ( isNaN( value ) ) { + return prop.def; + } + + if ( type.mod ) { + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return (value + type.mod) % type.mod; + } + + // for now all property types without mod have min and max + return 0 > value ? 0 : type.max < value ? type.max : value; +} + +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; + + string = string.toLowerCase(); + + each( stringParsers, function( i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; + } + }); + + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } + + // named colors + return colors[ string ]; +} + +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } + + var inst = this, + type = jQuery.type( red ), + rgba = this._rgba = []; + + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; + } + + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } + + if ( type === "array" ) { + each( spaces.rgba.props, function( key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + }); + return this; + } + + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + }); + } else { + each( spaces, function( spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { + + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + }); + + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + // use the default of 1 + inst[ cache ][ 3 ] = 1; + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + }); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if (isCache) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + }); + } + return same; + }); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + }); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + }); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } + + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; + + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + })); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + return v == null ? ( i > 2 ? 1 : 0 ) : v; + }); + + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + + return prefix + rgba.join() + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } + + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + }); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join() + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); + + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } + + return "#" + jQuery.map( rgba, function( v ) { + + // default to 0 when nulls exist + v = ( v || 0 ).toString( 16 ); + return v.length === 1 ? "0" + v : v; + }).join(""); + }, + toString: function() { + return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); + } +}); +color.fn.parse.prototype = color.fn; + +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 + +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + (q - p) * h * 6; + } + if ( h * 2 < 1) { + return q; + } + if ( h * 3 < 2 ) { + return p + (q - p) * ((2/3) - h) * 6; + } + return p; +} + +spaces.hsla.to = function ( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } + + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; +}; + +spaces.hsla.from = function ( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; + + +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } + + var ret, + type = jQuery.type( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + }); + + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; + + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var vtype = jQuery.type( value ), + fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), + local = this[ fn ](), + cur = local[ prop.idx ], + match; + + if ( vtype === "undefined" ) { + return cur; + } + + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = jQuery.type( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + }); +}); + +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + + if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + (backgroundColor === "" || backgroundColor === "transparent") && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } + } + + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); + } + + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch( e ) { + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + } + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + }); + +}; + +color.hook( stepHooks ); + +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; + + each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { + expanded[ "border" + part + "Color" ] = value; + }); + return expanded; + } +}; + +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" +}; + +})( jQuery ); + + +/******************************************************************************/ +/****************************** CLASS ANIMATIONS ******************************/ +/******************************************************************************/ +(function() { + +var classAnimationActions = [ "add", "remove", "toggle" ], + shorthandStyles = { + border: 1, + borderBottom: 1, + borderColor: 1, + borderLeft: 1, + borderRight: 1, + borderTop: 1, + borderWidth: 1, + margin: 1, + padding: 1 + }; + +$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { + $.fx.step[ prop ] = function( fx ) { + if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { + jQuery.style( fx.elem, prop, fx.end ); + fx.setAttr = true; + } + }; +}); + +function getElementStyles( elem ) { + var key, len, + style = elem.ownerDocument.defaultView ? + elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : + elem.currentStyle, + styles = {}; + + if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { + len = style.length; + while ( len-- ) { + key = style[ len ]; + if ( typeof style[ key ] === "string" ) { + styles[ $.camelCase( key ) ] = style[ key ]; + } + } + // support: Opera, IE <9 + } else { + for ( key in style ) { + if ( typeof style[ key ] === "string" ) { + styles[ key ] = style[ key ]; + } + } + } + + return styles; +} + + +function styleDifference( oldStyle, newStyle ) { + var diff = {}, + name, value; + + for ( name in newStyle ) { + value = newStyle[ name ]; + if ( oldStyle[ name ] !== value ) { + if ( !shorthandStyles[ name ] ) { + if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { + diff[ name ] = value; + } + } + } + } + + return diff; +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +$.effects.animateClass = function( value, duration, easing, callback ) { + var o = $.speed( duration, easing, callback ); + + return this.queue( function() { + var animated = $( this ), + baseClass = animated.attr( "class" ) || "", + applyClassChange, + allAnimations = o.children ? animated.find( "*" ).addBack() : animated; + + // map the animated objects to store the original styles. + allAnimations = allAnimations.map(function() { + var el = $( this ); + return { + el: el, + start: getElementStyles( this ) + }; + }); + + // apply class change + applyClassChange = function() { + $.each( classAnimationActions, function(i, action) { + if ( value[ action ] ) { + animated[ action + "Class" ]( value[ action ] ); + } + }); + }; + applyClassChange(); + + // map all animated objects again - calculate new styles and diff + allAnimations = allAnimations.map(function() { + this.end = getElementStyles( this.el[ 0 ] ); + this.diff = styleDifference( this.start, this.end ); + return this; + }); + + // apply original class + animated.attr( "class", baseClass ); + + // map all animated objects again - this time collecting a promise + allAnimations = allAnimations.map(function() { + var styleInfo = this, + dfd = $.Deferred(), + opts = $.extend({}, o, { + queue: false, + complete: function() { + dfd.resolve( styleInfo ); + } + }); + + this.el.animate( this.diff, opts ); + return dfd.promise(); + }); + + // once all animations have completed: + $.when.apply( $, allAnimations.get() ).done(function() { + + // set the final class + applyClassChange(); + + // for each animated element, + // clear all css properties that were animated + $.each( arguments, function() { + var el = this.el; + $.each( this.diff, function(key) { + el.css( key, "" ); + }); + }); + + // this is guarnteed to be there if you use jQuery.speed() + // it also handles dequeuing the next anim... + o.complete.call( animated[ 0 ] ); + }); + }); +}; + +$.fn.extend({ + addClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.addClass ), + + removeClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return arguments.length > 1 ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.removeClass ), + + toggleClass: (function( orig ) { + return function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { + if ( !speed ) { + // without speed parameter + return orig.apply( this, arguments ); + } else { + return $.effects.animateClass.call( this, + (force ? { add: classNames } : { remove: classNames }), + speed, easing, callback ); + } + } else { + // without force parameter + return $.effects.animateClass.call( this, + { toggle: classNames }, force, speed, easing ); + } + }; + })( $.fn.toggleClass ), + + switchClass: function( remove, add, speed, easing, callback) { + return $.effects.animateClass.call( this, { + add: add, + remove: remove + }, speed, easing, callback ); + } +}); + +})(); + +/******************************************************************************/ +/*********************************** EFFECTS **********************************/ +/******************************************************************************/ + +(function() { + +$.extend( $.effects, { + version: "1.10.2", + + // Saves a set of properties in a data storage + save: function( element, set ) { + for( var i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); + } + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function( element, set ) { + var val, i; + for( i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + val = element.data( dataSpace + set[ i ] ); + // support: jQuery 1.6.2 + // http://bugs.jquery.com/ticket/9917 + // jQuery 1.6.2 incorrectly returns undefined for any falsy value. + // We can't differentiate between "" and 0 here, so we just assume + // empty string since it's likely to be a more common value... + if ( val === undefined ) { + val = ""; + } + element.css( set[ i ], val ); + } + } + }, + + setMode: function( el, mode ) { + if (mode === "toggle") { + mode = el.is( ":hidden" ) ? "show" : "hide"; + } + return mode; + }, + + // Translates a [top,left] array into a baseline value + // this should be a little more flexible in the future to handle a string & hash + getBaseline: function( origin, original ) { + var y, x; + switch ( origin[ 0 ] ) { + case "top": y = 0; break; + case "middle": y = 0.5; break; + case "bottom": y = 1; break; + default: y = origin[ 0 ] / original.height; + } + switch ( origin[ 1 ] ) { + case "left": x = 0; break; + case "center": x = 0.5; break; + case "right": x = 1; break; + default: x = origin[ 1 ] / original.width; + } + return { + x: x, + y: y + }; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function( element ) { + + // if the element is already wrapped, return it + if ( element.parent().is( ".ui-effects-wrapper" )) { + return element.parent(); + } + + // wrap the element + var props = { + width: element.outerWidth(true), + height: element.outerHeight(true), + "float": element.css( "float" ) + }, + wrapper = $( "<div></div>" ) + .addClass( "ui-effects-wrapper" ) + .css({ + fontSize: "100%", + background: "transparent", + border: "none", + margin: 0, + padding: 0 + }), + // Store the size in case width/height are defined in % - Fixes #5245 + size = { + width: element.width(), + height: element.height() + }, + active = document.activeElement; + + // support: Firefox + // Firefox incorrectly exposes anonymous content + // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 + try { + active.id; + } catch( e ) { + active = document.body; + } + + element.wrap( wrapper ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + + wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element + + // transfer positioning properties to the wrapper + if ( element.css( "position" ) === "static" ) { + wrapper.css({ position: "relative" }); + element.css({ position: "relative" }); + } else { + $.extend( props, { + position: element.css( "position" ), + zIndex: element.css( "z-index" ) + }); + $.each([ "top", "left", "bottom", "right" ], function(i, pos) { + props[ pos ] = element.css( pos ); + if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { + props[ pos ] = "auto"; + } + }); + element.css({ + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto" + }); + } + element.css(size); + + return wrapper.css( props ).show(); + }, + + removeWrapper: function( element ) { + var active = document.activeElement; + + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + element.parent().replaceWith( element ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + } + + + return element; + }, + + setTransition: function( element, list, factor, value ) { + value = value || {}; + $.each( list, function( i, x ) { + var unit = element.cssUnit( x ); + if ( unit[ 0 ] > 0 ) { + value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; + } + }); + return value; + } +}); + +// return an effect options object for the given parameters: +function _normalizeArguments( effect, options, speed, callback ) { + + // allow passing all options as the first parameter + if ( $.isPlainObject( effect ) ) { + options = effect; + effect = effect.effect; + } + + // convert to an object + effect = { effect: effect }; + + // catch (effect, null, ...) + if ( options == null ) { + options = {}; + } + + // catch (effect, callback) + if ( $.isFunction( options ) ) { + callback = options; + speed = null; + options = {}; + } + + // catch (effect, speed, ?) + if ( typeof options === "number" || $.fx.speeds[ options ] ) { + callback = speed; + speed = options; + options = {}; + } + + // catch (effect, options, callback) + if ( $.isFunction( speed ) ) { + callback = speed; + speed = null; + } + + // add options to effect + if ( options ) { + $.extend( effect, options ); + } + + speed = speed || options.duration; + effect.duration = $.fx.off ? 0 : + typeof speed === "number" ? speed : + speed in $.fx.speeds ? $.fx.speeds[ speed ] : + $.fx.speeds._default; + + effect.complete = callback || options.complete; + + return effect; +} + +function standardAnimationOption( option ) { + // Valid standard speeds (nothing, number, named speed) + if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { + return true; + } + + // Invalid strings - treat as "normal" speed + if ( typeof option === "string" && !$.effects.effect[ option ] ) { + return true; + } + + // Complete callback + if ( $.isFunction( option ) ) { + return true; + } + + // Options hash (but not naming an effect) + if ( typeof option === "object" && !option.effect ) { + return true; + } + + // Didn't match any standard API + return false; +} + +$.fn.extend({ + effect: function( /* effect, options, speed, callback */ ) { + var args = _normalizeArguments.apply( this, arguments ), + mode = args.mode, + queue = args.queue, + effectMethod = $.effects.effect[ args.effect ]; + + if ( $.fx.off || !effectMethod ) { + // delegate to the original method (e.g., .show()) if possible + if ( mode ) { + return this[ mode ]( args.duration, args.complete ); + } else { + return this.each( function() { + if ( args.complete ) { + args.complete.call( this ); + } + }); + } + } + + function run( next ) { + var elem = $( this ), + complete = args.complete, + mode = args.mode; + + function done() { + if ( $.isFunction( complete ) ) { + complete.call( elem[0] ); + } + if ( $.isFunction( next ) ) { + next(); + } + } + + // If the element already has the correct final state, delegate to + // the core methods so the internal tracking of "olddisplay" works. + if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + elem[ mode ](); + done(); + } else { + effectMethod.call( elem[0], args, done ); + } + } + + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); + }, + + show: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "show"; + return this.effect.call( this, args ); + } + }; + })( $.fn.show ), + + hide: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "hide"; + return this.effect.call( this, args ); + } + }; + })( $.fn.hide ), + + toggle: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) || typeof option === "boolean" ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "toggle"; + return this.effect.call( this, args ); + } + }; + })( $.fn.toggle ), + + // helper functions + cssUnit: function(key) { + var style = this.css( key ), + val = []; + + $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { + if ( style.indexOf( unit ) > 0 ) { + val = [ parseFloat( style ), unit ]; + } + }); + return val; + } +}); + +})(); + +/******************************************************************************/ +/*********************************** EASING ***********************************/ +/******************************************************************************/ + +(function() { + +// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) + +var baseEasings = {}; + +$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { + baseEasings[ name ] = function( p ) { + return Math.pow( p, i + 2 ); + }; +}); + +$.extend( baseEasings, { + Sine: function ( p ) { + return 1 - Math.cos( p * Math.PI / 2 ); + }, + Circ: function ( p ) { + return 1 - Math.sqrt( 1 - p * p ); + }, + Elastic: function( p ) { + return p === 0 || p === 1 ? p : + -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); + }, + Back: function( p ) { + return p * p * ( 3 * p - 2 ); + }, + Bounce: function ( p ) { + var pow2, + bounce = 4; + + while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} + return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); + } +}); + +$.each( baseEasings, function( name, easeIn ) { + $.easing[ "easeIn" + name ] = easeIn; + $.easing[ "easeOut" + name ] = function( p ) { + return 1 - easeIn( 1 - p ); + }; + $.easing[ "easeInOut" + name ] = function( p ) { + return p < 0.5 ? + easeIn( p * 2 ) / 2 : + 1 - easeIn( p * -2 + 2 ) / 2; + }; +}); + +})(); + +})(jQuery); + +(function( $, undefined ) { + +var uid = 0, + hideProps = {}, + showProps = {}; + +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; + +$.widget( "ui.accordion", { + version: "1.10.2", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + _create: function() { + var options = this.options; + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + + this._processPanels(); + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next(), + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "<span>" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter(":not(.ui-accordion-content-active)") + .hide(); + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(), + accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) + .removeClass( "ui-corner-all" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } + + this._trigger( "activate", null, data ); + } +}); + +})( jQuery ); + +(function( $, undefined ) { + +// used to prevent race conditions with remote data sources +var requestIndex = 0; + +$.widget( "ui.autocomplete", { + version: "1.10.2", + defaultElement: "<input>", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + pending: 0, + + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[0].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + this.isMultiLine = + // Textareas are always multi-line + isTextarea ? true : + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + isInput ? false : + // All other element types are determined by whether or not they're contentEditable + this.element.prop( "isContentEditable" ); + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + case keyCode.NUMPAD_ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + this._value( this.term ); + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + event.preventDefault(); + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + }); + + this._initSource(); + this.menu = $( "<ul>" ) + .addClass( "ui-autocomplete ui-front" ) + .appendTo( this._appendTo() ) + .menu({ + // custom key handling for now + input: $(), + // disable ARIA support, the live region takes care of that + role: null + }) + .hide() + .data( "ui-menu" ); + + this._on( this.menu.element, { + mousedown: function( event ) { + // prevent moving focus out of the text field + event.preventDefault(); + + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + }); + + // clicking on the scrollbar causes focus to shift to the body + // but we can't detect a mouseup or a click immediately afterward + // so we have to track the next mousedown and close the menu if + // the user clicks somewhere outside of the autocomplete + var menuElement = this.menu.element[ 0 ]; + if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { + this._delay(function() { + var that = this; + this.document.one( "mousedown", function( event ) { + if ( event.target !== that.element[ 0 ] && + event.target !== menuElement && + !$.contains( menuElement, event.target ) ) { + that.close(); + } + }); + }); + } + }, + menufocus: function( event, ui ) { + // support: Firefox + // Prevent accidental activation of menu items in Firefox (#7024 #9118) + if ( this.isNewMenu ) { + this.isNewMenu = false; + if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { + this.menu.blur(); + + this.document.one( "mousemove", function() { + $( event.target ).trigger( event.originalEvent ); + }); + + return; + } + } + + var item = ui.item.data( "ui-autocomplete-item" ); + if ( false !== this._trigger( "focus", event, { item: item } ) ) { + // use value to match what will end up in the input, if it was a key event + if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { + this._value( item.value ); + } + } else { + // Normally the input is populated with the item's value as the + // menu is navigated, causing screen readers to notice a change and + // announce the item. Since the focus event was canceled, this doesn't + // happen, so we update the live region so that screen readers can + // still notice the change and announce it. + this.liveRegion.text( item.value ); + } + }, + menuselect: function( event, ui ) { + var item = ui.item.data( "ui-autocomplete-item" ), + previous = this.previous; + + // only trigger when focus was lost (click on menu) + if ( this.element[0] !== this.document[0].activeElement ) { + this.element.focus(); + this.previous = previous; + // #6109 - IE triggers two focus events and the second + // is asynchronous, so we need to reset the previous + // term synchronously and asynchronously :-( + this._delay(function() { + this.previous = previous; + this.selectedItem = item; + }); + } + + if ( false !== this._trigger( "select", event, { item: item } ) ) { + this._value( item.value ); + } + // reset the term after the select event + // this allows custom select handling to work properly + this.term = this._value(); + + this.close( event ); + this.selectedItem = item; + } + }); + + this.liveRegion = $( "<span>", { + role: "status", + "aria-live": "polite" + }) + .addClass( "ui-helper-hidden-accessible" ) + .insertAfter( this.element ); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _destroy: function() { + clearTimeout( this.searching ); + this.element + .removeClass( "ui-autocomplete-input" ) + .removeAttr( "autocomplete" ); + this.menu.element.remove(); + this.liveRegion.remove(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "source" ) { + this._initSource(); + } + if ( key === "appendTo" ) { + this.menu.element.appendTo( this._appendTo() ); + } + if ( key === "disabled" && value && this.xhr ) { + this.xhr.abort(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); + } + + if ( !element ) { + element = this.element.closest( ".ui-front" ); + } + + if ( !element.length ) { + element = this.document[0].body; + } + + return element; + }, + + _initSource: function() { + var array, url, + that = this; + if ( $.isArray(this.options.source) ) { + array = this.options.source; + this.source = function( request, response ) { + response( $.ui.autocomplete.filter( array, request.term ) ); + }; + } else if ( typeof this.options.source === "string" ) { + url = this.options.source; + this.source = function( request, response ) { + if ( that.xhr ) { + that.xhr.abort(); + } + that.xhr = $.ajax({ + url: url, + data: request, + dataType: "json", + success: function( data ) { + response( data ); + }, + error: function() { + response( [] ); + } + }); + }; + } else { + this.source = this.options.source; + } + }, + + _searchTimeout: function( event ) { + clearTimeout( this.searching ); + this.searching = this._delay(function() { + // only search if the value has changed + if ( this.term !== this._value() ) { + this.selectedItem = null; + this.search( null, event ); + } + }, this.options.delay ); + }, + + search: function( value, event ) { + value = value != null ? value : this._value(); + + // always save the actual value, not the one passed as an argument + this.term = this._value(); + + if ( value.length < this.options.minLength ) { + return this.close( event ); + } + + if ( this._trigger( "search", event ) === false ) { + return; + } + + return this._search( value ); + }, + + _search: function( value ) { + this.pending++; + this.element.addClass( "ui-autocomplete-loading" ); + this.cancelSearch = false; + + this.source( { term: value }, this._response() ); + }, + + _response: function() { + var that = this, + index = ++requestIndex; + + return function( content ) { + if ( index === requestIndex ) { + that.__response( content ); + } + + that.pending--; + if ( !that.pending ) { + that.element.removeClass( "ui-autocomplete-loading" ); + } + }; + }, + + __response: function( content ) { + if ( content ) { + content = this._normalize( content ); + } + this._trigger( "response", null, { content: content } ); + if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { + this._suggest( content ); + this._trigger( "open" ); + } else { + // use ._close() instead of .close() so we don't cancel future searches + this._close(); + } + }, + + close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, + + _close: function( event ) { + if ( this.menu.element.is( ":visible" ) ) { + this.menu.element.hide(); + this.menu.blur(); + this.isNewMenu = true; + this._trigger( "close", event ); + } + }, + + _change: function( event ) { + if ( this.previous !== this._value() ) { + this._trigger( "change", event, { item: this.selectedItem } ); + } + }, + + _normalize: function( items ) { + // assume all items have the right format when the first item is complete + if ( items.length && items[0].label && items[0].value ) { + return items; + } + return $.map( items, function( item ) { + if ( typeof item === "string" ) { + return { + label: item, + value: item + }; + } + return $.extend({ + label: item.label || item.value, + value: item.value || item.label + }, item ); + }); + }, + + _suggest: function( items ) { + var ul = this.menu.element.empty(); + this._renderMenu( ul, items ); + this.isNewMenu = true; + this.menu.refresh(); + + // size and position menu + ul.show(); + this._resizeMenu(); + ul.position( $.extend({ + of: this.element + }, this.options.position )); + + if ( this.options.autoFocus ) { + this.menu.next(); + } + }, + + _resizeMenu: function() { + var ul = this.menu.element; + ul.outerWidth( Math.max( + // Firefox wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping (#7513) + ul.width( "" ).outerWidth() + 1, + this.element.outerWidth() + ) ); + }, + + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ); + }); + }, + + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); + }, + + _renderItem: function( ul, item ) { + return $( "<li>" ) + .append( $( "<a>" ).text( item.label ) ) + .appendTo( ul ); + }, + + _move: function( direction, event ) { + if ( !this.menu.element.is( ":visible" ) ) { + this.search( null, event ); + return; + } + if ( this.menu.isFirstItem() && /^previous/.test( direction ) || + this.menu.isLastItem() && /^next/.test( direction ) ) { + this._value( this.term ); + this.menu.blur(); + return; + } + this.menu[ direction ]( event ); + }, + + widget: function() { + return this.menu.element; + }, + + _value: function() { + return this.valueMethod.apply( this.element, arguments ); + }, + + _keyEvent: function( keyEvent, event ) { + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + this._move( keyEvent, event ); + + // prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); + } + } +}); + +$.extend( $.ui.autocomplete, { + escapeRegex: function( value ) { + return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); + }, + filter: function(array, term) { + var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); + return $.grep( array, function(value) { + return matcher.test( value.label || value.value || value ); + }); + } +}); + + +// live region extension, adding a `messages` option +// NOTE: This is an experimental API. We are still investigating +// a full solution for string manipulation and internationalization. +$.widget( "ui.autocomplete", $.ui.autocomplete, { + options: { + messages: { + noResults: "No search results.", + results: function( amount ) { + return amount + ( amount > 1 ? " results are" : " result is" ) + + " available, use up and down arrow keys to navigate."; + } + } + }, + + __response: function( content ) { + var message; + this._superApply( arguments ); + if ( this.options.disabled || this.cancelSearch ) { + return; + } + if ( content && content.length ) { + message = this.options.messages.results( content.length ); + } else { + message = this.options.messages.noResults; + } + this.liveRegion.text( message ); + } +}); + +}( jQuery )); + +(function( $, undefined ) { + +var lastActive, startXPos, startYPos, clickDragged, + baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", + stateClasses = "ui-state-hover ui-state-active ", + typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", + formResetHandler = function() { + var buttons = $( this ).find( ":ui-button" ); + setTimeout(function() { + buttons.button( "refresh" ); + }, 1 ); + }, + radioGroup = function( radio ) { + var name = radio.name, + form = radio.form, + radios = $( [] ); + if ( name ) { + name = name.replace( /'/g, "\\'" ); + if ( form ) { + radios = $( form ).find( "[name='" + name + "']" ); + } else { + radios = $( "[name='" + name + "']", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } + } + return radios; + }; + +$.widget( "ui.button", { + version: "1.10.2", + defaultElement: "<button>", + options: { + disabled: null, + text: true, + label: null, + icons: { + primary: null, + secondary: null + } + }, + _create: function() { + this.element.closest( "form" ) + .unbind( "reset" + this.eventNamespace ) + .bind( "reset" + this.eventNamespace, formResetHandler ); + + if ( typeof this.options.disabled !== "boolean" ) { + this.options.disabled = !!this.element.prop( "disabled" ); + } else { + this.element.prop( "disabled", this.options.disabled ); + } + + this._determineButtonType(); + this.hasTitle = !!this.buttonElement.attr( "title" ); + + var that = this, + options = this.options, + toggleButton = this.type === "checkbox" || this.type === "radio", + activeClass = !toggleButton ? "ui-state-active" : "", + focusClass = "ui-state-focus"; + + if ( options.label === null ) { + options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); + } + + this._hoverable( this.buttonElement ); + + this.buttonElement + .addClass( baseClasses ) + .attr( "role", "button" ) + .bind( "mouseenter" + this.eventNamespace, function() { + if ( options.disabled ) { + return; + } + if ( this === lastActive ) { + $( this ).addClass( "ui-state-active" ); + } + }) + .bind( "mouseleave" + this.eventNamespace, function() { + if ( options.disabled ) { + return; + } + $( this ).removeClass( activeClass ); + }) + .bind( "click" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + }); + + this.element + .bind( "focus" + this.eventNamespace, function() { + // no need to check disabled, focus won't be triggered anyway + that.buttonElement.addClass( focusClass ); + }) + .bind( "blur" + this.eventNamespace, function() { + that.buttonElement.removeClass( focusClass ); + }); + + if ( toggleButton ) { + this.element.bind( "change" + this.eventNamespace, function() { + if ( clickDragged ) { + return; + } + that.refresh(); + }); + // if mouse moves between mousedown and mouseup (drag) set clickDragged flag + // prevents issue where button state changes but checkbox/radio checked state + // does not in Firefox (see ticket #6970) + this.buttonElement + .bind( "mousedown" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + return; + } + clickDragged = false; + startXPos = event.pageX; + startYPos = event.pageY; + }) + .bind( "mouseup" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + return; + } + if ( startXPos !== event.pageX || startYPos !== event.pageY ) { + clickDragged = true; + } + }); + } + + if ( this.type === "checkbox" ) { + this.buttonElement.bind( "click" + this.eventNamespace, function() { + if ( options.disabled || clickDragged ) { + return false; + } + }); + } else if ( this.type === "radio" ) { + this.buttonElement.bind( "click" + this.eventNamespace, function() { + if ( options.disabled || clickDragged ) { + return false; + } + $( this ).addClass( "ui-state-active" ); + that.buttonElement.attr( "aria-pressed", "true" ); + + var radio = that.element[ 0 ]; + radioGroup( radio ) + .not( radio ) + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + }); + } else { + this.buttonElement + .bind( "mousedown" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).addClass( "ui-state-active" ); + lastActive = this; + that.document.one( "mouseup", function() { + lastActive = null; + }); + }) + .bind( "mouseup" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).removeClass( "ui-state-active" ); + }) + .bind( "keydown" + this.eventNamespace, function(event) { + if ( options.disabled ) { + return false; + } + if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { + $( this ).addClass( "ui-state-active" ); + } + }) + // see #8559, we bind to blur here in case the button element loses + // focus between keydown and keyup, it would be left in an "active" state + .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { + $( this ).removeClass( "ui-state-active" ); + }); + + if ( this.buttonElement.is("a") ) { + this.buttonElement.keyup(function(event) { + if ( event.keyCode === $.ui.keyCode.SPACE ) { + // TODO pass through original event correctly (just as 2nd argument doesn't work) + $( this ).click(); + } + }); + } + } + + // TODO: pull out $.Widget's handling for the disabled option into + // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can + // be overridden by individual plugins + this._setOption( "disabled", options.disabled ); + this._resetButton(); + }, + + _determineButtonType: function() { + var ancestor, labelSelector, checked; + + if ( this.element.is("[type=checkbox]") ) { + this.type = "checkbox"; + } else if ( this.element.is("[type=radio]") ) { + this.type = "radio"; + } else if ( this.element.is("input") ) { + this.type = "input"; + } else { + this.type = "button"; + } + + if ( this.type === "checkbox" || this.type === "radio" ) { + // we don't search against the document in case the element + // is disconnected from the DOM + ancestor = this.element.parents().last(); + labelSelector = "label[for='" + this.element.attr("id") + "']"; + this.buttonElement = ancestor.find( labelSelector ); + if ( !this.buttonElement.length ) { + ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); + this.buttonElement = ancestor.filter( labelSelector ); + if ( !this.buttonElement.length ) { + this.buttonElement = ancestor.find( labelSelector ); + } + } + this.element.addClass( "ui-helper-hidden-accessible" ); + + checked = this.element.is( ":checked" ); + if ( checked ) { + this.buttonElement.addClass( "ui-state-active" ); + } + this.buttonElement.prop( "aria-pressed", checked ); + } else { + this.buttonElement = this.element; + } + }, + + widget: function() { + return this.buttonElement; + }, + + _destroy: function() { + this.element + .removeClass( "ui-helper-hidden-accessible" ); + this.buttonElement + .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) + .removeAttr( "role" ) + .removeAttr( "aria-pressed" ) + .html( this.buttonElement.find(".ui-button-text").html() ); + + if ( !this.hasTitle ) { + this.buttonElement.removeAttr( "title" ); + } + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "disabled" ) { + if ( value ) { + this.element.prop( "disabled", true ); + } else { + this.element.prop( "disabled", false ); + } + return; + } + this._resetButton(); + }, + + refresh: function() { + //See #8237 & #8828 + var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); + + if ( isDisabled !== this.options.disabled ) { + this._setOption( "disabled", isDisabled ); + } + if ( this.type === "radio" ) { + radioGroup( this.element[0] ).each(function() { + if ( $( this ).is( ":checked" ) ) { + $( this ).button( "widget" ) + .addClass( "ui-state-active" ) + .attr( "aria-pressed", "true" ); + } else { + $( this ).button( "widget" ) + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + } + }); + } else if ( this.type === "checkbox" ) { + if ( this.element.is( ":checked" ) ) { + this.buttonElement + .addClass( "ui-state-active" ) + .attr( "aria-pressed", "true" ); + } else { + this.buttonElement + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + } + } + }, + + _resetButton: function() { + if ( this.type === "input" ) { + if ( this.options.label ) { + this.element.val( this.options.label ); + } + return; + } + var buttonElement = this.buttonElement.removeClass( typeClasses ), + buttonText = $( "<span></span>", this.document[0] ) + .addClass( "ui-button-text" ) + .html( this.options.label ) + .appendTo( buttonElement.empty() ) + .text(), + icons = this.options.icons, + multipleIcons = icons.primary && icons.secondary, + buttonClasses = []; + + if ( icons.primary || icons.secondary ) { + if ( this.options.text ) { + buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); + } + + if ( icons.primary ) { + buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); + } + + if ( icons.secondary ) { + buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); + } + + if ( !this.options.text ) { + buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); + + if ( !this.hasTitle ) { + buttonElement.attr( "title", $.trim( buttonText ) ); + } + } + } else { + buttonClasses.push( "ui-button-text-only" ); + } + buttonElement.addClass( buttonClasses.join( " " ) ); + } +}); + +$.widget( "ui.buttonset", { + version: "1.10.2", + options: { + items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" + }, + + _create: function() { + this.element.addClass( "ui-buttonset" ); + }, + + _init: function() { + this.refresh(); + }, + + _setOption: function( key, value ) { + if ( key === "disabled" ) { + this.buttons.button( "option", key, value ); + } + + this._super( key, value ); + }, + + refresh: function() { + var rtl = this.element.css( "direction" ) === "rtl"; + + this.buttons = this.element.find( this.options.items ) + .filter( ":ui-button" ) + .button( "refresh" ) + .end() + .not( ":ui-button" ) + .button() + .end() + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) + .filter( ":first" ) + .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) + .end() + .filter( ":last" ) + .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) + .end() + .end(); + }, + + _destroy: function() { + this.element.removeClass( "ui-buttonset" ); + this.buttons + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-corner-left ui-corner-right" ) + .end() + .button( "destroy" ); + } +}); + +}( jQuery ) ); + +(function( $, undefined ) { + +$.extend($.ui, { datepicker: { version: "1.10.2" } }); + +var PROP_NAME = "datepicker", + dpuuid = new Date().getTime(), + instActive; + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division + this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class + this._appendClass = "ui-datepicker-append"; // The name of the append marker class + this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class + this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class + this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class + this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class + this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class + this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[""] = { // Default regional settings + closeText: "Done", // Display text for close link + prevText: "Prev", // Display text for previous month link + nextText: "Next", // Display text for next month link + currentText: "Today", // Display text for current month link + monthNames: ["January","February","March","April","May","June", + "July","August","September","October","November","December"], // Names of months for drop-down and formatting + monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting + dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday + weekHeader: "Wk", // Column header for week of the year + dateFormat: "mm/dd/yy", // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false, // True if right-to-left language, false if left-to-right + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearSuffix: "" // Additional text to append to the year in the month headers + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: "focus", // "focus" for popup on focus, + // "button" for trigger button, or "both" for either + showAnim: "fadeIn", // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: "", // Display text following the input box, e.g. showing the format + buttonText: "...", // Text for trigger button + buttonImage: "", // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + yearRange: "c-10:c+10", // Range of years to display in drop-down, + // either relative to today's year (-nn:+nn), relative to currently displayed year + // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) + showOtherMonths: false, // True to show dates in other months, false to leave blank + selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable + showWeek: false, // True to show week of the year, false to not show it + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: "+10", // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with "+" for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: "fast", // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: "", // Selector for an alternate field to store selected dates into + altFormat: "", // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false, // True to show button panel, false to not show it + autoSize: false, // True to size the input for the date format, false to leave as is + disabled: false // The initial disabled state + }; + $.extend(this._defaults, this.regional[""]); + this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: "hasDatepicker", + + //Keep track of the maximum number of rows displayed (see #7043) + maxRows: 4, + + // TODO rename to "widget" when switching to widget factory + _widgetDatepicker: function() { + return this.dpDiv; + }, + + /* Override the default settings for all instances of the date picker. + * @param settings object - the new settings to use as defaults (anonymous object) + * @return the manager object + */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + * @param target element - the target input field or division or span + * @param settings object - the new settings to use for this date picker instance (anonymous) + */ + _attachDatepicker: function(target, settings) { + var nodeName, inline, inst; + nodeName = target.nodeName.toLowerCase(); + inline = (nodeName === "div" || nodeName === "span"); + if (!target.id) { + this.uuid += 1; + target.id = "dp" + this.uuid; + } + inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}); + if (nodeName === "input") { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) { + return; + } + this._attachments(input, inst); + input.addClass(this.markerClassName).keydown(this._doKeyDown). + keypress(this._doKeyPress).keyup(this._doKeyUp); + this._autoSize(inst); + $.data(target, PROP_NAME, inst); + //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + }, + + /* Make attachments based on settings. */ + _attachments: function(input, inst) { + var showOn, buttonText, buttonImage, + appendText = this._get(inst, "appendText"), + isRTL = this._get(inst, "isRTL"); + + if (inst.append) { + inst.append.remove(); + } + if (appendText) { + inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); + input[isRTL ? "before" : "after"](inst.append); + } + + input.unbind("focus", this._showDatepicker); + + if (inst.trigger) { + inst.trigger.remove(); + } + + showOn = this._get(inst, "showOn"); + if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + } + if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked + buttonText = this._get(inst, "buttonText"); + buttonImage = this._get(inst, "buttonImage"); + inst.trigger = $(this._get(inst, "buttonImageOnly") ? + $("<img/>").addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $("<button type='button'></button>").addClass(this._triggerClass). + html(!buttonImage ? buttonText : $("<img/>").attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? "before" : "after"](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { + $.datepicker._hideDatepicker(); + } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { + $.datepicker._hideDatepicker(); + $.datepicker._showDatepicker(input[0]); + } else { + $.datepicker._showDatepicker(input[0]); + } + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, "autoSize") && !inst.inline) { + var findMax, max, maxI, i, + date = new Date(2009, 12 - 1, 20), // Ensure double digits + dateFormat = this._get(inst, "dateFormat"); + + if (dateFormat.match(/[DM]/)) { + findMax = function(names) { + max = 0; + maxI = 0; + for (i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + "monthNames" : "monthNamesShort")))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); + } + inst.input.attr("size", this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) { + return; + } + divSpan.addClass(this.markerClassName).append(inst.dpDiv); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + //If disabled option is true, disable the datepicker before showing it (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements + // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height + inst.dpDiv.css( "display", "block" ); + }, + + /* Pop-up the date picker in a "dialog" box. + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var id, browserWidth, browserHeight, scrollX, scrollY, + inst = this._dialogInst; // internal instance + + if (!inst) { + this.uuid += 1; + id = "dp" + this.uuid; + this._dialogInput = $("<input type='text' id='" + id + + "' style='position: absolute; top: -100px; width: 0px;'/>"); + this._dialogInput.keydown(this._doKeyDown); + $("body").append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + browserWidth = document.documentElement.clientWidth; + browserHeight = document.documentElement.clientHeight; + scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) { + $.blockUI(this.dpDiv); + } + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + * @param target element - the target input field or division or span + */ + _destroyDatepicker: function(target) { + var nodeName, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName === "input") { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind("focus", this._showDatepicker). + unbind("keydown", this._doKeyDown). + unbind("keypress", this._doKeyPress). + unbind("keyup", this._doKeyUp); + } else if (nodeName === "div" || nodeName === "span") { + $target.removeClass(this.markerClassName).empty(); + } + }, + + /* Enable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _enableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img").css({opacity: "1.0", cursor: ""}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().removeClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", false); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _disableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img").css({opacity: "0.5", cursor: "default"}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().addClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", true); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] === target) { + return true; + } + } + return false; + }, + + /* Retrieve the instance data for the target control. + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw "Missing instance data for this datepicker"; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also "all" for all instance settings or + * "defaults" for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ + _optionDatepicker: function(target, name, value) { + var settings, date, minDate, maxDate, + inst = this._getInst(target); + + if (arguments.length === 2 && typeof name === "string") { + return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : + (inst ? (name === "all" ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + + settings = name || {}; + if (typeof name === "string") { + settings = {}; + settings[name] = value; + } + + if (inst) { + if (this._curInst === inst) { + this._hideDatepicker(); + } + + date = this._getDateDatepicker(target, true); + minDate = this._getMinMaxDate(inst, "min"); + maxDate = this._getMinMaxDate(inst, "max"); + extendRemove(inst.settings, settings); + // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { + inst.settings.minDate = this._formatDate(inst, minDate); + } + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { + inst.settings.maxDate = this._formatDate(inst, maxDate); + } + if ( "disabled" in settings ) { + if ( settings.disabled ) { + this._disableDatepicker(target); + } else { + this._enableDatepicker(target); + } + } + this._attachments($(target), inst); + this._autoSize(inst); + this._setDate(inst, date); + this._updateAlternate(inst); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + * @param target element - the target input field or division or span + */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + * @param target element - the target input field or division or span + * @param date Date - the new date + */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) { + this._setDateFromField(inst, noDefault); + } + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var onSelect, dateStr, sel, + inst = $.datepicker._getInst(event.target), + handled = true, + isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); + + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) { + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + + $.datepicker._currentClass + ")", inst.dpDiv); + if (sel[0]) { + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + } + + onSelect = $.datepicker._get(inst, "onSelect"); + if (onSelect) { + dateStr = $.datepicker._formatDate(inst); + + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } else { + $.datepicker._hideDatepicker(); + } + + return false; // don't submit the form + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) { + $.datepicker._clearDate(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) { + $.datepicker._gotoToday(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, -7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, +7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + } else { + handled = false; + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var chars, chr, + inst = $.datepicker._getInst(event.target); + + if ($.datepicker._get(inst, "constrainInput")) { + chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); + chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var date, + inst = $.datepicker._getInst(event.target); + + if (inst.input.val() !== inst.lastVal) { + try { + date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (err) { + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger + input = $("input", input.parentNode)[0]; + } + + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here + return; + } + + var inst, beforeShow, beforeShowSettings, isFixed, + offset, showAnim, duration; + + inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst !== inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + if ( inst && $.datepicker._datepickerShowing ) { + $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); + } + } + + beforeShow = $.datepicker._get(inst, "beforeShow"); + beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + if(beforeShowSettings === false){ + return; + } + extendRemove(inst.settings, beforeShowSettings); + + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + + if ($.datepicker._inDialog) { // hide cursor + input.value = ""; + } + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + + isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css("position") === "fixed"; + return !isFixed; + }); + + offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + //to avoid flashes on Firefox + inst.dpDiv.empty(); + // determine sizing offscreen + inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + "static" : (isFixed ? "fixed" : "absolute")), display: "none", + left: offset.left + "px", top: offset.top + "px"}); + + if (!inst.inline) { + showAnim = $.datepicker._get(inst, "showAnim"); + duration = $.datepicker._get(inst, "duration"); + inst.dpDiv.zIndex($(input).zIndex()+1); + $.datepicker._datepickerShowing = true; + + if ( $.effects && $.effects.effect[ showAnim ] ) { + inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); + } else { + inst.dpDiv[showAnim || "show"](showAnim ? duration : null); + } + + if (inst.input.is(":visible") && !inst.input.is(":disabled")) { + inst.input.focus(); + } + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) + instActive = inst; // for delegate hover events + inst.dpDiv.empty().append(this._generateHTML(inst)); + this._attachHandlers(inst); + inst.dpDiv.find("." + this._dayOverClass + " a").mouseover(); + + var origyearshtml, + numMonths = this._getNumberOfMonths(inst), + cols = numMonths[1], + width = 17; + + inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); + if (cols > 1) { + inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); + } + inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + + "Class"]("ui-datepicker-multi"); + inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + + "Class"]("ui-datepicker-rtl"); + + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && + inst.input.is(":visible") && !inst.input.is(":disabled") && inst.input[0] !== document.activeElement) { + inst.input.focus(); + } + + // deffered render of the years select (to avoid flashes on Firefox) + if( inst.yearshtml ){ + origyearshtml = inst.yearshtml; + setTimeout(function(){ + //assure that inst.yearshtml didn't change. + if( origyearshtml === inst.yearshtml && inst.yearshtml ){ + inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); + } + origyearshtml = inst.yearshtml = null; + }, 0); + } + }, + + /* Retrieve the size of left and top borders for an element. + * @param elem (jQuery object) the element of interest + * @return (number[2]) the left and top borders + */ + _getBorders: function(elem) { + var convert = function(value) { + return {thin: 1, medium: 2, thick: 3}[value] || value; + }; + return [parseFloat(convert(elem.css("border-left-width"))), + parseFloat(convert(elem.css("border-top-width")))]; + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(), + dpHeight = inst.dpDiv.outerHeight(), + inputWidth = inst.input ? inst.input.outerWidth() : 0, + inputHeight = inst.input ? inst.input.outerHeight() : 0, + viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), + viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); + + offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var position, + inst = this._getInst(obj), + isRTL = this._get(inst, "isRTL"); + + while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? "previousSibling" : "nextSibling"]; + } + + position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + * @param input element - the input field attached to the date picker + */ + _hideDatepicker: function(input) { + var showAnim, duration, postProcess, onClose, + inst = this._curInst; + + if (!inst || (input && inst !== $.data(input, PROP_NAME))) { + return; + } + + if (this._datepickerShowing) { + showAnim = this._get(inst, "showAnim"); + duration = this._get(inst, "duration"); + postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); + } else { + inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : + (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); + } + + if (!showAnim) { + postProcess(); + } + this._datepickerShowing = false; + + onClose = this._get(inst, "onClose"); + if (onClose) { + onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); + } + + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); + if ($.blockUI) { + $.unblockUI(); + $("body").append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) { + return; + } + + var $target = $(event.target), + inst = $.datepicker._getInst($target[0]); + + if ( ( ( $target[0].id !== $.datepicker._mainDivId && + $target.parents("#" + $.datepicker._mainDivId).length === 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.closest("." + $.datepicker._triggerClass).length && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { + $.datepicker._hideDatepicker(); + } + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id), + inst = this._getInst(target[0]); + + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var date, + target = $(id), + inst = this._getInst(target[0]); + + if (this._get(inst, "gotoCurrent") && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } else { + date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id), + inst = this._getInst(target[0]); + + inst["selected" + (period === "M" ? "Month" : "Year")] = + inst["draw" + (period === "M" ? "Month" : "Year")] = + parseInt(select.options[select.selectedIndex].value,10); + + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var inst, + target = $(id); + + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + + inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $("a", td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + this._selectDate(target, ""); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var onSelect, + target = $(id), + inst = this._getInst(target[0]); + + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) { + inst.input.val(dateStr); + } + this._updateAlternate(inst); + + onSelect = this._get(inst, "onSelect"); + if (onSelect) { + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + } else if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + + if (inst.inline){ + this._updateDatepicker(inst); + } else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) !== "object") { + inst.input.focus(); // restore focus + } + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altFormat, date, dateStr, + altField = this._get(inst, "altField"); + + if (altField) { // update alternate field too + altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); + date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), ""]; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ + iso8601Week: function(date) { + var time, + checkDate = new Date(date.getTime()); + + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + + time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ + parseDate: function (format, value, settings) { + if (format == null || value == null) { + throw "Invalid arguments"; + } + + value = (typeof value === "object" ? value.toString() : value + ""); + if (value === "") { + return null; + } + + var iFormat, dim, extra, + iValue = 0, + shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, + shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : + new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Extract a number from the string value + getNumber = function(match) { + var isDoubled = lookAhead(match), + size = (match === "@" ? 14 : (match === "!" ? 20 : + (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), + digits = new RegExp("^\\d{1," + size + "}"), + num = value.substring(iValue).match(digits); + if (!num) { + throw "Missing number at position " + iValue; + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + // Extract a name from the string value and convert to an index + getName = function(match, shortNames, longNames) { + var index = -1, + names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index !== -1) { + return index + 1; + } else { + throw "Unknown name at position " + iValue; + } + }, + // Confirm that a literal character matches the string value + checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw "Unexpected literal at position " + iValue; + } + iValue++; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + checkLiteral(); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + day = getNumber("d"); + break; + case "D": + getName("D", dayNamesShort, dayNames); + break; + case "o": + doy = getNumber("o"); + break; + case "m": + month = getNumber("m"); + break; + case "M": + month = getName("M", monthNamesShort, monthNames); + break; + case "y": + year = getNumber("y"); + break; + case "@": + date = new Date(getNumber("@")); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "!": + date = new Date((getNumber("!") - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")){ + checkLiteral(); + } else { + literal = true; + } + break; + default: + checkLiteral(); + } + } + } + + if (iValue < value.length){ + extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw "Extra/unparsed characters found in date: " + extra; + } + } + + if (year === -1) { + year = new Date().getFullYear(); + } else if (year < 100) { + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + } + + if (doy > -1) { + month = 1; + day = doy; + do { + dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) { + break; + } + month++; + day -= dim; + } while (true); + } + + date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw "Invalid date"; // E.g. 31/02/00 + } + return date; + }, + + /* Standard date formats. */ + ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) + COOKIE: "D, dd M yy", + ISO_8601: "yy-mm-dd", + RFC_822: "D, d M y", + RFC_850: "DD, dd-M-y", + RFC_1036: "D, d M y", + RFC_1123: "D, d M yy", + RFC_2822: "D, d M yy", + RSS: "D, d M y", // RFC 822 + TICKS: "!", + TIMESTAMP: "@", + W3C: "yy-mm-dd", // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * "..." - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ + formatDate: function (format, date, settings) { + if (!date) { + return ""; + } + + var iFormat, + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Format a number, with leading zero if necessary + formatNumber = function(match, value, len) { + var num = "" + value; + if (lookAhead(match)) { + while (num.length < len) { + num = "0" + num; + } + } + return num; + }, + // Format a name, short or long as requested + formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }, + output = "", + literal = false; + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + output += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + output += formatNumber("d", date.getDate(), 2); + break; + case "D": + output += formatName("D", date.getDay(), dayNamesShort, dayNames); + break; + case "o": + output += formatNumber("o", + Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case "m": + output += formatNumber("m", date.getMonth() + 1, 2); + break; + case "M": + output += formatName("M", date.getMonth(), monthNamesShort, monthNames); + break; + case "y": + output += (lookAhead("y") ? date.getFullYear() : + (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); + break; + case "@": + output += date.getTime(); + break; + case "!": + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) { + output += "'"; + } else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); + } + } + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var iFormat, + chars = "", + literal = false, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + chars += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": case "m": case "y": case "@": + chars += "0123456789"; + break; + case "D": case "M": + return null; // Accept anything + case "'": + if (lookAhead("'")) { + chars += "'"; + } else { + literal = true; + } + break; + default: + chars += format.charAt(iFormat); + } + } + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() === inst.lastVal) { + return; + } + + var dateFormat = this._get(inst, "dateFormat"), + dates = inst.lastVal = inst.input ? inst.input.val() : null, + defaultDate = this._getDefaultDate(inst), + date = defaultDate, + settings = this._getFormatConfig(inst); + + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + dates = (noDefault ? "" : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }, + offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(), + year = date.getFullYear(), + month = date.getMonth(), + day = date.getDate(), + pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, + matches = pattern.exec(offset); + + while (matches) { + switch (matches[2] || "d") { + case "d" : case "D" : + day += parseInt(matches[1],10); break; + case "w" : case "W" : + day += parseInt(matches[1],10) * 7; break; + case "m" : case "M" : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case "y": case "Y" : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }, + newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : + (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + + newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); + if (newDate) { + newDate.setHours(0); + newDate.setMinutes(0); + newDate.setSeconds(0); + newDate.setMilliseconds(0); + } + return this._daylightSavingAdjust(newDate); + }, + + /* Handle switch to/from daylight saving. + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ + _daylightSavingAdjust: function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !date, + origMonth = inst.selectedMonth, + origYear = inst.selectedYear, + newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + + inst.selectedDay = inst.currentDay = newDate.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); + if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { + this._notifyChange(inst); + } + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? "" : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Attach the onxxx handlers. These are declared statically so + * they work with static code transformers like Caja. + */ + _attachHandlers: function(inst) { + var stepMonths = this._get(inst, "stepMonths"), + id = "#" + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find("[data-handler]").map(function () { + var handler = { + prev: function () { + window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, -stepMonths, "M"); + }, + next: function () { + window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, +stepMonths, "M"); + }, + hide: function () { + window["DP_jQuery_" + dpuuid].datepicker._hideDatepicker(); + }, + today: function () { + window["DP_jQuery_" + dpuuid].datepicker._gotoToday(id); + }, + selectDay: function () { + window["DP_jQuery_" + dpuuid].datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); + return false; + }, + selectMonth: function () { + window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "M"); + return false; + }, + selectYear: function () { + window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "Y"); + return false; + } + }; + $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); + }); + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, + controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, + monthNames, monthNamesShort, beforeShowDay, showOtherMonths, + selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, + cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, + printDate, dRow, tbody, daySettings, otherMonth, unselectable, + tempDate = new Date(), + today = this._daylightSavingAdjust( + new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time + isRTL = this._get(inst, "isRTL"), + showButtonPanel = this._get(inst, "showButtonPanel"), + hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), + navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), + numMonths = this._getNumberOfMonths(inst), + showCurrentAtPos = this._get(inst, "showCurrentAtPos"), + stepMonths = this._get(inst, "stepMonths"), + isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), + currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + drawMonth = inst.drawMonth - showCurrentAtPos, + drawYear = inst.drawYear; + + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + + prevText = this._get(inst, "prevText"); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + + prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + + " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>")); + + nextText = this._get(inst, "nextText"); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + + next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + + " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>")); + + currentText = this._get(inst, "currentText"); + gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + + controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + + this._get(inst, "closeText") + "</button>" : ""); + + buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") + + (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + + ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : ""; + + firstDay = parseInt(this._get(inst, "firstDay"),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + + showWeek = this._get(inst, "showWeek"); + dayNames = this._get(inst, "dayNames"); + dayNamesMin = this._get(inst, "dayNamesMin"); + monthNames = this._get(inst, "monthNames"); + monthNamesShort = this._get(inst, "monthNamesShort"); + beforeShowDay = this._get(inst, "beforeShowDay"); + showOtherMonths = this._get(inst, "showOtherMonths"); + selectOtherMonths = this._get(inst, "selectOtherMonths"); + defaultDate = this._getDefaultDate(inst); + html = ""; + dow; + for (row = 0; row < numMonths[0]; row++) { + group = ""; + this.maxRows = 4; + for (col = 0; col < numMonths[1]; col++) { + selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + cornerClass = " ui-corner-all"; + calender = ""; + if (isMultiMonth) { + calender += "<div class='ui-datepicker-group"; + if (numMonths[1] > 1) { + switch (col) { + case 0: calender += " ui-datepicker-group-first"; + cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break; + case numMonths[1]-1: calender += " ui-datepicker-group-last"; + cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break; + default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; + } + } + calender += "'>"; + } + calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + "</div><table class='ui-datepicker-calendar'><thead>" + + "<tr>"; + thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>"; + } + calender += thead + "</tr></thead><tbody>"; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += "<tr>"; + tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" + + this._get(inst, "calculateWeek")(printDate) + "</td>"); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += "<td class='" + + ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends + (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months + ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key + (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ? + // or defaultDate is current printedDate and defaultDate is selectedDate + " " + this._dayOverClass : "") + // highlight selected day + (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days + (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates + (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day + (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different) + ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title + (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + + (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") + + (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day + (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months + "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + "</tr>"; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += "</tbody></table>" + (isMultiMonth ? "</div>" + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : ""); + group += calender; + } + html += group; + } + html += buttonPanel; + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "<div class='ui-datepicker-title'>", + monthHtml = ""; + + // month selection + if (secondary || !changeMonth) { + monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>"; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; + for ( month = 0; month < 12; month++) { + if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) { + monthHtml += "<option value='" + month + "'" + + (month === drawMonth ? " selected='selected'" : "") + + ">" + monthNamesShort[month] + "</option>"; + } + } + monthHtml += "</select>"; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; + } else { + // determine range of years to display + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; + for (; year <= endYear; year++) { + inst.yearshtml += "<option value='" + year + "'" + + (year === drawYear ? " selected='selected'" : "") + + ">" + year + "</option>"; + } + inst.yearshtml += "</select>"; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "</div>"; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period === "M" || period === "Y") { + this._notifyChange(inst); + } + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + } + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + + if (offset < 0) { + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10); + maxYear = parseInt(yearSplit[1], 10); + if ( yearSplit[0].match(/[+\-].*/) ) { + minYear += currentYear; + } + if ( yearSplit[1].match(/[+\-].*/) ) { + maxYear += currentYear; + } + } + + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day === "object" ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function bindHover(dpDiv) { + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } + }) + .delegate(selector, "mouseover", function(){ + if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } + } + }); +} + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) { + if (props[name] == null) { + target[name] = props[name]; + } + } + return target; +} + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + return this.each(function() { + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.10.2"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window["DP_jQuery_" + dpuuid] = $; + +})(jQuery); + +(function( $, undefined ) { + +var sizeRelatedOptions = { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + resizableRelatedOptions = { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }; + +$.widget( "ui.dialog", { + version: "1.10.2", + options: { + appendTo: "body", + autoOpen: true, + buttons: [], + closeOnEscape: true, + closeText: "close", + dialogClass: "", + draggable: true, + hide: null, + height: "auto", + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + // Ensure the titlebar is always visible + using: function( pos ) { + var topOffset = $( this ).css( pos ).offset().top; + if ( topOffset < 0 ) { + $( this ).css( "top", pos.top - topOffset ); + } + } + }, + resizable: true, + show: null, + title: null, + width: 300, + + // callbacks + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + }, + + _create: function() { + this.originalCss = { + display: this.element[0].style.display, + width: this.element[0].style.width, + minHeight: this.element[0].style.minHeight, + maxHeight: this.element[0].style.maxHeight, + height: this.element[0].style.height + }; + this.originalPosition = { + parent: this.element.parent(), + index: this.element.parent().children().index( this.element ) + }; + this.originalTitle = this.element.attr("title"); + this.options.title = this.options.title || this.originalTitle; + + this._createWrapper(); + + this.element + .show() + .removeAttr("title") + .addClass("ui-dialog-content ui-widget-content") + .appendTo( this.uiDialog ); + + this._createTitlebar(); + this._createButtonPane(); + + if ( this.options.draggable && $.fn.draggable ) { + this._makeDraggable(); + } + if ( this.options.resizable && $.fn.resizable ) { + this._makeResizable(); + } + + this._isOpen = false; + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + if ( element && (element.jquery || element.nodeType) ) { + return $( element ); + } + return this.document.find( element || "body" ).eq( 0 ); + }, + + _destroy: function() { + var next, + originalPosition = this.originalPosition; + + this._destroyOverlay(); + + this.element + .removeUniqueId() + .removeClass("ui-dialog-content ui-widget-content") + .css( this.originalCss ) + // Without detaching first, the following becomes really slow + .detach(); + + this.uiDialog.stop( true, true ).remove(); + + if ( this.originalTitle ) { + this.element.attr( "title", this.originalTitle ); + } + + next = originalPosition.parent.children().eq( originalPosition.index ); + // Don't try to place the dialog next to itself (#8613) + if ( next.length && next[0] !== this.element[0] ) { + next.before( this.element ); + } else { + originalPosition.parent.append( this.element ); + } + }, + + widget: function() { + return this.uiDialog; + }, + + disable: $.noop, + enable: $.noop, + + close: function( event ) { + var that = this; + + if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { + return; + } + + this._isOpen = false; + this._destroyOverlay(); + + if ( !this.opener.filter(":focusable").focus().length ) { + // Hiding a focused element doesn't trigger blur in WebKit + // so in case we have nothing to focus on, explicitly blur the active element + // https://bugs.webkit.org/show_bug.cgi?id=47182 + $( this.document[0].activeElement ).blur(); + } + + this._hide( this.uiDialog, this.options.hide, function() { + that._trigger( "close", event ); + }); + }, + + isOpen: function() { + return this._isOpen; + }, + + moveToTop: function() { + this._moveToTop(); + }, + + _moveToTop: function( event, silent ) { + var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length; + if ( moved && !silent ) { + this._trigger( "focus", event ); + } + return moved; + }, + + open: function() { + var that = this; + if ( this._isOpen ) { + if ( this._moveToTop() ) { + this._focusTabbable(); + } + return; + } + + this._isOpen = true; + this.opener = $( this.document[0].activeElement ); + + this._size(); + this._position(); + this._createOverlay(); + this._moveToTop( null, true ); + this._show( this.uiDialog, this.options.show, function() { + that._focusTabbable(); + that._trigger("focus"); + }); + + this._trigger("open"); + }, + + _focusTabbable: function() { + // Set focus to the first match: + // 1. First element inside the dialog matching [autofocus] + // 2. Tabbable element inside the content element + // 3. Tabbable element inside the buttonpane + // 4. The close button + // 5. The dialog itself + var hasFocus = this.element.find("[autofocus]"); + if ( !hasFocus.length ) { + hasFocus = this.element.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogButtonPane.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogTitlebarClose.filter(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialog; + } + hasFocus.eq( 0 ).focus(); + }, + + _keepFocus: function( event ) { + function checkFocus() { + var activeElement = this.document[0].activeElement, + isActive = this.uiDialog[0] === activeElement || + $.contains( this.uiDialog[0], activeElement ); + if ( !isActive ) { + this._focusTabbable(); + } + } + event.preventDefault(); + checkFocus.call( this ); + // support: IE + // IE <= 8 doesn't prevent moving focus even with event.preventDefault() + // so we check again later + this._delay( checkFocus ); + }, + + _createWrapper: function() { + this.uiDialog = $("<div>") + .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + + this.options.dialogClass ) + .hide() + .attr({ + // Setting tabIndex makes the div focusable + tabIndex: -1, + role: "dialog" + }) + .appendTo( this._appendTo() ); + + this._on( this.uiDialog, { + keydown: function( event ) { + if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + event.preventDefault(); + this.close( event ); + return; + } + + // prevent tabbing out of dialogs + if ( event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + var tabbables = this.uiDialog.find(":tabbable"), + first = tabbables.filter(":first"), + last = tabbables.filter(":last"); + + if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { + first.focus( 1 ); + event.preventDefault(); + } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { + last.focus( 1 ); + event.preventDefault(); + } + }, + mousedown: function( event ) { + if ( this._moveToTop( event ) ) { + this._focusTabbable(); + } + } + }); + + // We assume that any existing aria-describedby attribute means + // that the dialog content is marked up properly + // otherwise we brute force the content as the description + if ( !this.element.find("[aria-describedby]").length ) { + this.uiDialog.attr({ + "aria-describedby": this.element.uniqueId().attr("id") + }); + } + }, + + _createTitlebar: function() { + var uiDialogTitle; + + this.uiDialogTitlebar = $("<div>") + .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix") + .prependTo( this.uiDialog ); + this._on( this.uiDialogTitlebar, { + mousedown: function( event ) { + // Don't prevent click on close button (#8838) + // Focusing a dialog that is partially scrolled out of view + // causes the browser to scroll it into view, preventing the click event + if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) { + // Dialog isn't getting focus when dragging (#8063) + this.uiDialog.focus(); + } + } + }); + + this.uiDialogTitlebarClose = $("<button></button>") + .button({ + label: this.options.closeText, + icons: { + primary: "ui-icon-closethick" + }, + text: false + }) + .addClass("ui-dialog-titlebar-close") + .appendTo( this.uiDialogTitlebar ); + this._on( this.uiDialogTitlebarClose, { + click: function( event ) { + event.preventDefault(); + this.close( event ); + } + }); + + uiDialogTitle = $("<span>") + .uniqueId() + .addClass("ui-dialog-title") + .prependTo( this.uiDialogTitlebar ); + this._title( uiDialogTitle ); + + this.uiDialog.attr({ + "aria-labelledby": uiDialogTitle.attr("id") + }); + }, + + _title: function( title ) { + if ( !this.options.title ) { + title.html(" "); + } + title.text( this.options.title ); + }, + + _createButtonPane: function() { + this.uiDialogButtonPane = $("<div>") + .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"); + + this.uiButtonSet = $("<div>") + .addClass("ui-dialog-buttonset") + .appendTo( this.uiDialogButtonPane ); + + this._createButtons(); + }, + + _createButtons: function() { + var that = this, + buttons = this.options.buttons; + + // if we already have a button pane, remove it + this.uiDialogButtonPane.remove(); + this.uiButtonSet.empty(); + + if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { + this.uiDialog.removeClass("ui-dialog-buttons"); + return; + } + + $.each( buttons, function( name, props ) { + var click, buttonOptions; + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + // Change the context for the click callback to be the main element + click = props.click; + props.click = function() { + click.apply( that.element[0], arguments ); + }; + buttonOptions = { + icons: props.icons, + text: props.showText + }; + delete props.icons; + delete props.showText; + $( "<button></button>", props ) + .button( buttonOptions ) + .appendTo( that.uiButtonSet ); + }); + this.uiDialog.addClass("ui-dialog-buttons"); + this.uiDialogButtonPane.appendTo( this.uiDialog ); + }, + + _makeDraggable: function() { + var that = this, + options = this.options; + + function filteredUi( ui ) { + return { + position: ui.position, + offset: ui.offset + }; + } + + this.uiDialog.draggable({ + cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", + handle: ".ui-dialog-titlebar", + containment: "document", + start: function( event, ui ) { + $( this ).addClass("ui-dialog-dragging"); + that._blockFrames(); + that._trigger( "dragStart", event, filteredUi( ui ) ); + }, + drag: function( event, ui ) { + that._trigger( "drag", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.position = [ + ui.position.left - that.document.scrollLeft(), + ui.position.top - that.document.scrollTop() + ]; + $( this ).removeClass("ui-dialog-dragging"); + that._unblockFrames(); + that._trigger( "dragStop", event, filteredUi( ui ) ); + } + }); + }, + + _makeResizable: function() { + var that = this, + options = this.options, + handles = options.resizable, + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = this.uiDialog.css("position"), + resizeHandles = typeof handles === "string" ? + handles : + "n,e,s,w,se,sw,ne,nw"; + + function filteredUi( ui ) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + this.uiDialog.resizable({ + cancel: ".ui-dialog-content", + containment: "document", + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: this._minHeight(), + handles: resizeHandles, + start: function( event, ui ) { + $( this ).addClass("ui-dialog-resizing"); + that._blockFrames(); + that._trigger( "resizeStart", event, filteredUi( ui ) ); + }, + resize: function( event, ui ) { + that._trigger( "resize", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.height = $( this ).height(); + options.width = $( this ).width(); + $( this ).removeClass("ui-dialog-resizing"); + that._unblockFrames(); + that._trigger( "resizeStop", event, filteredUi( ui ) ); + } + }) + .css( "position", position ); + }, + + _minHeight: function() { + var options = this.options; + + return options.height === "auto" ? + options.minHeight : + Math.min( options.minHeight, options.height ); + }, + + _position: function() { + // Need to show the dialog to get the actual offset in the position plugin + var isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( this.options.position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var that = this, + resize = false, + resizableOptions = {}; + + $.each( options, function( key, value ) { + that._setOption( key, value ); + + if ( key in sizeRelatedOptions ) { + resize = true; + } + if ( key in resizableRelatedOptions ) { + resizableOptions[ key ] = value; + } + }); + + if ( resize ) { + this._size(); + this._position(); + } + if ( this.uiDialog.is(":data(ui-resizable)") ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function( key, value ) { + /*jshint maxcomplexity:15*/ + var isDraggable, isResizable, + uiDialog = this.uiDialog; + + if ( key === "dialogClass" ) { + uiDialog + .removeClass( this.options.dialogClass ) + .addClass( value ); + } + + if ( key === "disabled" ) { + return; + } + + this._super( key, value ); + + if ( key === "appendTo" ) { + this.uiDialog.appendTo( this._appendTo() ); + } + + if ( key === "buttons" ) { + this._createButtons(); + } + + if ( key === "closeText" ) { + this.uiDialogTitlebarClose.button({ + // Ensure that we always pass a string + label: "" + value + }); + } + + if ( key === "draggable" ) { + isDraggable = uiDialog.is(":data(ui-draggable)"); + if ( isDraggable && !value ) { + uiDialog.draggable("destroy"); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + } + + if ( key === "position" ) { + this._position(); + } + + if ( key === "resizable" ) { + // currently resizable, becoming non-resizable + isResizable = uiDialog.is(":data(ui-resizable)"); + if ( isResizable && !value ) { + uiDialog.resizable("destroy"); + } + + // currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable(); + } + } + + if ( key === "title" ) { + this._title( this.uiDialogTitlebar.find(".ui-dialog-title") ); + } + }, + + _size: function() { + // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + // divs will both have width and height set, so we need to reset them + var nonContentHeight, minContentHeight, maxContentHeight, + options = this.options; + + // Reset content sizing + this.element.show().css({ + width: "auto", + minHeight: 0, + maxHeight: "none", + height: 0 + }); + + if ( options.minWidth > options.width ) { + options.width = options.minWidth; + } + + // reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css({ + height: "auto", + width: options.width + }) + .outerHeight(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + maxContentHeight = typeof options.maxHeight === "number" ? + Math.max( 0, options.maxHeight - nonContentHeight ) : + "none"; + + if ( options.height === "auto" ) { + this.element.css({ + minHeight: minContentHeight, + maxHeight: maxContentHeight, + height: "auto" + }); + } else { + this.element.height( Math.max( 0, options.height - nonContentHeight ) ); + } + + if (this.uiDialog.is(":data(ui-resizable)") ) { + this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); + } + }, + + _blockFrames: function() { + this.iframeBlocks = this.document.find( "iframe" ).map(function() { + var iframe = $( this ); + + return $( "<div>" ) + .css({ + position: "absolute", + width: iframe.outerWidth(), + height: iframe.outerHeight() + }) + .appendTo( iframe.parent() ) + .offset( iframe.offset() )[0]; + }); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; + } + }, + + _allowInteraction: function( event ) { + if ( $( event.target ).closest(".ui-dialog").length ) { + return true; + } + + // TODO: Remove hack when datepicker implements + // the .ui-front logic (#8989) + return !!$( event.target ).closest(".ui-datepicker").length; + }, + + _createOverlay: function() { + if ( !this.options.modal ) { + return; + } + + var that = this, + widgetFullName = this.widgetFullName; + if ( !$.ui.dialog.overlayInstances ) { + // Prevent use of anchors and inputs. + // We use a delay in case the overlay is created from an + // event that we're going to be cancelling. (#2804) + this._delay(function() { + // Handle .dialog().dialog("close") (#4065) + if ( $.ui.dialog.overlayInstances ) { + this.document.bind( "focusin.dialog", function( event ) { + if ( !that._allowInteraction( event ) ) { + event.preventDefault(); + $(".ui-dialog:visible:last .ui-dialog-content") + .data( widgetFullName )._focusTabbable(); + } + }); + } + }); + } + + this.overlay = $("<div>") + .addClass("ui-widget-overlay ui-front") + .appendTo( this._appendTo() ); + this._on( this.overlay, { + mousedown: "_keepFocus" + }); + $.ui.dialog.overlayInstances++; + }, + + _destroyOverlay: function() { + if ( !this.options.modal ) { + return; + } + + if ( this.overlay ) { + $.ui.dialog.overlayInstances--; + + if ( !$.ui.dialog.overlayInstances ) { + this.document.unbind( "focusin.dialog" ); + } + this.overlay.remove(); + this.overlay = null; + } + } +}); + +$.ui.dialog.overlayInstances = 0; + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // position option with array notation + // just override with old implementation + $.widget( "ui.dialog", $.ui.dialog, { + _position: function() { + var position = this.options.position, + myAt = [], + offset = [ 0, 0 ], + isVisible; + + if ( position ) { + if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { + myAt = position.split ? position.split(" ") : [ position[0], position[1] ]; + if ( myAt.length === 1 ) { + myAt[1] = myAt[0]; + } + + $.each( [ "left", "top" ], function( i, offsetPosition ) { + if ( +myAt[ i ] === myAt[ i ] ) { + offset[ i ] = myAt[ i ]; + myAt[ i ] = offsetPosition; + } + }); + + position = { + my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + + myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), + at: myAt.join(" ") + }; + } + + position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); + } else { + position = $.ui.dialog.prototype.options.position; + } + + // need to show the dialog to get the actual offset in the position plugin + isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + } + }); +} + +}( jQuery ) ); + +(function( $, undefined ) { + +var rvertical = /up|down|vertical/, + rpositivemotion = /up|left|vertical|horizontal/; + +$.effects.effect.blind = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + direction = o.direction || "up", + vertical = rvertical.test( direction ), + ref = vertical ? "height" : "width", + ref2 = vertical ? "top" : "left", + motion = rpositivemotion.test( direction ), + animation = {}, + show = mode === "show", + wrapper, distance, margin; + + // if already wrapped, the wrapper's properties are my property. #6245 + if ( el.parent().is( ".ui-effects-wrapper" ) ) { + $.effects.save( el.parent(), props ); + } else { + $.effects.save( el, props ); + } + el.show(); + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + distance = wrapper[ ref ](); + margin = parseFloat( wrapper.css( ref2 ) ) || 0; + + animation[ ref ] = show ? distance : 0; + if ( !motion ) { + el + .css( vertical ? "bottom" : "right", 0 ) + .css( vertical ? "top" : "left", "auto" ) + .css({ position: "absolute" }); + + animation[ ref2 ] = show ? margin : distance + margin; + } + + // start at 0 if we are showing + if ( show ) { + wrapper.css( ref, 0 ); + if ( ! motion ) { + wrapper.css( ref2, margin + distance ); + } + } + + // Animate + wrapper.animate( animation, { + duration: o.duration, + easing: o.easing, + queue: false, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.bounce = function( o, done ) { + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + + // defaults: + mode = $.effects.setMode( el, o.mode || "effect" ), + hide = mode === "hide", + show = mode === "show", + direction = o.direction || "up", + distance = o.distance, + times = o.times || 5, + + // number of internal animations + anims = times * 2 + ( show || hide ? 1 : 0 ), + speed = o.duration / anims, + easing = o.easing, + + // utility: + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ), + i, + upAnim, + downAnim, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + // Avoid touching opacity to prevent clearType and PNG issues in IE + if ( show || hide ) { + props.push( "opacity" ); + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); // Create Wrapper + + // default distance for the BIGGEST bounce is the outer Distance / 3 + if ( !distance ) { + distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; + } + + if ( show ) { + downAnim = { opacity: 1 }; + downAnim[ ref ] = 0; + + // if we are showing, force opacity 0 and set the initial position + // then do the "first" animation + el.css( "opacity", 0 ) + .css( ref, motion ? -distance * 2 : distance * 2 ) + .animate( downAnim, speed, easing ); + } + + // start at the smallest distance if we are hiding + if ( hide ) { + distance = distance / Math.pow( 2, times - 1 ); + } + + downAnim = {}; + downAnim[ ref ] = 0; + // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here + for ( i = 0; i < times; i++ ) { + upAnim = {}; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ) + .animate( downAnim, speed, easing ); + + distance = hide ? distance * 2 : distance / 2; + } + + // Last Bounce when Hiding + if ( hide ) { + upAnim = { opacity: 0 }; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ); + } + + el.queue(function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.clip = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "vertical", + vert = direction === "vertical", + size = vert ? "height" : "width", + position = vert ? "top" : "left", + animation = {}, + wrapper, animate, distance; + + // Save & Show + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + animate = ( el[0].tagName === "IMG" ) ? wrapper : el; + distance = animate[ size ](); + + // Shift + if ( show ) { + animate.css( size, 0 ); + animate.css( position, distance / 2 ); + } + + // Create Animation Object: + animation[ size ] = show ? distance : 0; + animation[ position ] = show ? 0 : distance / 2; + + // Animate + animate.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( !show ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.drop = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "left", + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", + animation = { + opacity: show ? 1 : 0 + }, + distance; + + // Adjust + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2; + + if ( show ) { + el + .css( "opacity", 0 ) + .css( ref, motion === "pos" ? -distance : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( motion === "pos" ? "+=" : "-=" ) : + ( motion === "pos" ? "-=" : "+=" ) ) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.explode = function( o, done ) { + + var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, + cells = rows, + el = $( this ), + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + + // show and then visibility:hidden the element before calculating offset + offset = el.show().css( "visibility", "hidden" ).offset(), + + // width and height of a piece + width = Math.ceil( el.outerWidth() / cells ), + height = Math.ceil( el.outerHeight() / rows ), + pieces = [], + + // loop + i, j, left, top, mx, my; + + // children animate complete: + function childComplete() { + pieces.push( this ); + if ( pieces.length === rows * cells ) { + animComplete(); + } + } + + // clone the element for each row and cell. + for( i = 0; i < rows ; i++ ) { // ===> + top = offset.top + i * height; + my = i - ( rows - 1 ) / 2 ; + + for( j = 0; j < cells ; j++ ) { // ||| + left = offset.left + j * width; + mx = j - ( cells - 1 ) / 2 ; + + // Create a clone of the now hidden main element that will be absolute positioned + // within a wrapper div off the -left and -top equal to size of our pieces + el + .clone() + .appendTo( "body" ) + .wrap( "<div></div>" ) + .css({ + position: "absolute", + visibility: "visible", + left: -j * width, + top: -i * height + }) + + // select the wrapper - make it overflow: hidden and absolute positioned based on + // where the original was located +left and +top equal to the size of pieces + .parent() + .addClass( "ui-effects-explode" ) + .css({ + position: "absolute", + overflow: "hidden", + width: width, + height: height, + left: left + ( show ? mx * width : 0 ), + top: top + ( show ? my * height : 0 ), + opacity: show ? 0 : 1 + }).animate({ + left: left + ( show ? 0 : mx * width ), + top: top + ( show ? 0 : my * height ), + opacity: show ? 1 : 0 + }, o.duration || 500, o.easing, childComplete ); + } + } + + function animComplete() { + el.css({ + visibility: "visible" + }); + $( pieces ).remove(); + if ( !show ) { + el.hide(); + } + done(); + } +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.fade = function( o, done ) { + var el = $( this ), + mode = $.effects.setMode( el, o.mode || "toggle" ); + + el.animate({ + opacity: mode + }, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: done + }); +}; + +})( jQuery ); + +(function( $, undefined ) { + +$.effects.effect.fold = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + hide = mode === "hide", + size = o.size || 15, + percent = /([0-9]+)%/.exec( size ), + horizFirst = !!o.horizFirst, + widthFirst = show !== horizFirst, + ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], + duration = o.duration / 2, + wrapper, distance, + animation1 = {}, + animation2 = {}; + + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + distance = widthFirst ? + [ wrapper.width(), wrapper.height() ] : + [ wrapper.height(), wrapper.width() ]; + + if ( percent ) { + size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; + } + if ( show ) { + wrapper.css( horizFirst ? { + height: 0, + width: size + } : { + height: size, + width: 0 + }); + } + + // Animation + animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; + animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; + + // Animate + wrapper + .animate( animation1, duration, o.easing ) + .animate( animation2, duration, o.easing, function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.highlight = function( o, done ) { + var elem = $( this ), + props = [ "backgroundImage", "backgroundColor", "opacity" ], + mode = $.effects.setMode( elem, o.mode || "show" ), + animation = { + backgroundColor: elem.css( "backgroundColor" ) + }; + + if (mode === "hide") { + animation.opacity = 0; + } + + $.effects.save( elem, props ); + + elem + .show() + .css({ + backgroundImage: "none", + backgroundColor: o.color || "#ffff99" + }) + .animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + elem.hide(); + } + $.effects.restore( elem, props ); + done(); + } + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.pulsate = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "show" ), + show = mode === "show", + hide = mode === "hide", + showhide = ( show || mode === "hide" ), + + // showing or hiding leaves of the "last" animation + anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), + duration = o.duration / anims, + animateTo = 0, + queue = elem.queue(), + queuelen = queue.length, + i; + + if ( show || !elem.is(":visible")) { + elem.css( "opacity", 0 ).show(); + animateTo = 1; + } + + // anims - 1 opacity "toggles" + for ( i = 1; i < anims; i++ ) { + elem.animate({ + opacity: animateTo + }, duration, o.easing ); + animateTo = 1 - animateTo; + } + + elem.animate({ + opacity: animateTo + }, duration, o.easing); + + elem.queue(function() { + if ( hide ) { + elem.hide(); + } + done(); + }); + + // We just queued up "anims" animations, we need to put them next in the queue + if ( queuelen > 1 ) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + elem.dequeue(); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.puff = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "hide" ), + hide = mode === "hide", + percent = parseInt( o.percent, 10 ) || 150, + factor = percent / 100, + original = { + height: elem.height(), + width: elem.width(), + outerHeight: elem.outerHeight(), + outerWidth: elem.outerWidth() + }; + + $.extend( o, { + effect: "scale", + queue: false, + fade: true, + mode: mode, + complete: done, + percent: hide ? percent : 100, + from: hide ? + original : + { + height: original.height * factor, + width: original.width * factor, + outerHeight: original.outerHeight * factor, + outerWidth: original.outerWidth * factor + } + }); + + elem.effect( o ); +}; + +$.effects.effect.scale = function( o, done ) { + + // Create element + var el = $( this ), + options = $.extend( true, {}, o ), + mode = $.effects.setMode( el, o.mode || "effect" ), + percent = parseInt( o.percent, 10 ) || + ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), + direction = o.direction || "both", + origin = o.origin, + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }, + factor = { + y: direction !== "horizontal" ? (percent / 100) : 1, + x: direction !== "vertical" ? (percent / 100) : 1 + }; + + // We are going to pass this effect to the size effect: + options.effect = "size"; + options.queue = false; + options.complete = done; + + // Set default origin and restore for show/hide + if ( mode !== "effect" ) { + options.origin = origin || ["middle","center"]; + options.restore = true; + } + + options.from = o.from || ( mode === "show" ? { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + } : original ); + options.to = { + height: original.height * factor.y, + width: original.width * factor.x, + outerHeight: original.outerHeight * factor.y, + outerWidth: original.outerWidth * factor.x + }; + + // Fade option to support puff + if ( options.fade ) { + if ( mode === "show" ) { + options.from.opacity = 0; + options.to.opacity = 1; + } + if ( mode === "hide" ) { + options.from.opacity = 1; + options.to.opacity = 0; + } + } + + // Animate + el.effect( options ); + +}; + +$.effects.effect.size = function( o, done ) { + + // Create element + var original, baseline, factor, + el = $( this ), + props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], + + // Always restore + props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], + + // Copy for children + props2 = [ "width", "height", "overflow" ], + cProps = [ "fontSize" ], + vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], + hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], + + // Set options + mode = $.effects.setMode( el, o.mode || "effect" ), + restore = o.restore || mode !== "effect", + scale = o.scale || "both", + origin = o.origin || [ "middle", "center" ], + position = el.css( "position" ), + props = restore ? props0 : props1, + zero = { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + }; + + if ( mode === "show" ) { + el.show(); + } + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }; + + if ( o.mode === "toggle" && mode === "show" ) { + el.from = o.to || zero; + el.to = o.from || original; + } else { + el.from = o.from || ( mode === "show" ? zero : original ); + el.to = o.to || ( mode === "hide" ? zero : original ); + } + + // Set scaling factor + factor = { + from: { + y: el.from.height / original.height, + x: el.from.width / original.width + }, + to: { + y: el.to.height / original.height, + x: el.to.width / original.width + } + }; + + // Scale the css box + if ( scale === "box" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( vProps ); + el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + props = props.concat( hProps ); + el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); + el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); + } + } + + // Scale the content + if ( scale === "content" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( cProps ).concat( props2 ); + el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); + } + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + el.css( "overflow", "hidden" ).css( el.from ); + + // Adjust + if (origin) { // Calculate baseline shifts + baseline = $.effects.getBaseline( origin, original ); + el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; + el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; + el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; + el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; + } + el.css( el.from ); // set top & left + + // Animate + if ( scale === "content" || scale === "both" ) { // Scale the children + + // Add margins/font-size + vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); + hProps = hProps.concat([ "marginLeft", "marginRight" ]); + props2 = props0.concat(vProps).concat(hProps); + + el.find( "*[width]" ).each( function(){ + var child = $( this ), + c_original = { + height: child.height(), + width: child.width(), + outerHeight: child.outerHeight(), + outerWidth: child.outerWidth() + }; + if (restore) { + $.effects.save(child, props2); + } + + child.from = { + height: c_original.height * factor.from.y, + width: c_original.width * factor.from.x, + outerHeight: c_original.outerHeight * factor.from.y, + outerWidth: c_original.outerWidth * factor.from.x + }; + child.to = { + height: c_original.height * factor.to.y, + width: c_original.width * factor.to.x, + outerHeight: c_original.height * factor.to.y, + outerWidth: c_original.width * factor.to.x + }; + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); + child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); + child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); + } + + // Animate children + child.css( child.from ); + child.animate( child.to, o.duration, o.easing, function() { + + // Restore children + if ( restore ) { + $.effects.restore( child, props2 ); + } + }); + }); + } + + // Animate + el.animate( el.to, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( el.to.opacity === 0 ) { + el.css( "opacity", el.from.opacity ); + } + if( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + if ( !restore ) { + + // we need to calculate our new positioning based on the scaling + if ( position === "static" ) { + el.css({ + position: "relative", + top: el.to.top, + left: el.to.left + }); + } else { + $.each([ "top", "left" ], function( idx, pos ) { + el.css( pos, function( _, str ) { + var val = parseInt( str, 10 ), + toRef = idx ? el.to.left : el.to.top; + + // if original was "auto", recalculate the new value from wrapper + if ( str === "auto" ) { + return toRef + "px"; + } + + return val + toRef + "px"; + }); + }); + } + } + + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.shake = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "effect" ), + direction = o.direction || "left", + distance = o.distance || 20, + times = o.times || 3, + anims = times * 2 + 1, + speed = Math.round(o.duration/anims), + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + animation = {}, + animation1 = {}, + animation2 = {}, + i, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + // Animation + animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; + animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; + animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; + + // Animate + el.animate( animation, speed, o.easing ); + + // Shakes + for ( i = 1; i < times; i++ ) { + el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); + } + el + .animate( animation1, speed, o.easing ) + .animate( animation, speed / 2, o.easing ) + .queue(function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.slide = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "width", "height" ], + mode = $.effects.setMode( el, o.mode || "show" ), + show = mode === "show", + direction = o.direction || "left", + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + distance, + animation = {}; + + // Adjust + $.effects.save( el, props ); + el.show(); + distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); + + $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + if ( show ) { + el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( positiveMotion ? "+=" : "-=") : + ( positiveMotion ? "-=" : "+=")) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.transfer = function( o, done ) { + var elem = $( this ), + target = $( o.to ), + targetFixed = target.css( "position" ) === "fixed", + body = $("body"), + fixTop = targetFixed ? body.scrollTop() : 0, + fixLeft = targetFixed ? body.scrollLeft() : 0, + endPosition = target.offset(), + animation = { + top: endPosition.top - fixTop , + left: endPosition.left - fixLeft , + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = elem.offset(), + transfer = $( "<div class='ui-effects-transfer'></div>" ) + .appendTo( document.body ) + .addClass( o.className ) + .css({ + top: startPosition.top - fixTop , + left: startPosition.left - fixLeft , + height: elem.innerHeight(), + width: elem.innerWidth(), + position: targetFixed ? "fixed" : "absolute" + }) + .animate( animation, o.duration, o.easing, function() { + transfer.remove(); + done(); + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.widget( "ui.menu", { + version: "1.10.2", + defaultElement: "<ul>", + delay: 300, + options: { + icons: { + submenu: "ui-icon-carat-1-e" + }, + menus: "ul", + position: { + my: "left top", + at: "right top" + }, + role: "menu", + + // callbacks + blur: null, + focus: null, + select: null + }, + + _create: function() { + this.activeMenu = this.element; + // flag used to prevent firing of the click handler + // as the event bubbles up through nested menus + this.mouseHandled = false; + this.element + .uniqueId() + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) + .attr({ + role: this.options.role, + tabIndex: 0 + }) + // need to catch all clicks on disabled menu + // not possible through _on + .bind( "click" + this.eventNamespace, $.proxy(function( event ) { + if ( this.options.disabled ) { + event.preventDefault(); + } + }, this )); + + if ( this.options.disabled ) { + this.element + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } + + this._on({ + // Prevent focus from sticking to links inside menu after clicking + // them (focus should always stay on UL during navigation). + "mousedown .ui-menu-item > a": function( event ) { + event.preventDefault(); + }, + "click .ui-state-disabled > a": function( event ) { + event.preventDefault(); + }, + "click .ui-menu-item:has(a)": function( event ) { + var target = $( event.target ).closest( ".ui-menu-item" ); + if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { + this.mouseHandled = true; + + this.select( event ); + // Open submenu on click + if ( target.has( ".ui-menu" ).length ) { + this.expand( event ); + } else if ( !this.element.is( ":focus" ) ) { + // Redirect focus to the menu + this.element.trigger( "focus", [ true ] ); + + // If the active item is on the top level, let it stay active. + // Otherwise, blur the active item since it is no longer visible. + if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { + clearTimeout( this.timer ); + } + } + } + }, + "mouseenter .ui-menu-item": function( event ) { + var target = $( event.currentTarget ); + // Remove ui-state-active class from siblings of the newly focused menu item + // to avoid a jump caused by adjacent elements both having a class with a border + target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); + this.focus( event, target ); + }, + mouseleave: "collapseAll", + "mouseleave .ui-menu": "collapseAll", + focus: function( event, keepActiveItem ) { + // If there's already an active item, keep it active + // If not, activate the first item + var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 ); + + if ( !keepActiveItem ) { + this.focus( event, item ); + } + }, + blur: function( event ) { + this._delay(function() { + if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { + this.collapseAll( event ); + } + }); + }, + keydown: "_keydown" + }); + + this.refresh(); + + // Clicks outside of a menu collapse any open menus + this._on( this.document, { + click: function( event ) { + if ( !$( event.target ).closest( ".ui-menu" ).length ) { + this.collapseAll( event ); + } + + // Reset the mouseHandled flag + this.mouseHandled = false; + } + }); + }, + + _destroy: function() { + // Destroy (sub)menus + this.element + .removeAttr( "aria-activedescendant" ) + .find( ".ui-menu" ).addBack() + .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-disabled" ) + .removeUniqueId() + .show(); + + // Destroy menu items + this.element.find( ".ui-menu-item" ) + .removeClass( "ui-menu-item" ) + .removeAttr( "role" ) + .removeAttr( "aria-disabled" ) + .children( "a" ) + .removeUniqueId() + .removeClass( "ui-corner-all ui-state-hover" ) + .removeAttr( "tabIndex" ) + .removeAttr( "role" ) + .removeAttr( "aria-haspopup" ) + .children().each( function() { + var elem = $( this ); + if ( elem.data( "ui-menu-submenu-carat" ) ) { + elem.remove(); + } + }); + + // Destroy menu dividers + this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); + }, + + _keydown: function( event ) { + /*jshint maxcomplexity:20*/ + var match, prev, character, skip, regex, + preventDefault = true; + + function escape( value ) { + return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + this.previousPage( event ); + break; + case $.ui.keyCode.PAGE_DOWN: + this.nextPage( event ); + break; + case $.ui.keyCode.HOME: + this._move( "first", "first", event ); + break; + case $.ui.keyCode.END: + this._move( "last", "last", event ); + break; + case $.ui.keyCode.UP: + this.previous( event ); + break; + case $.ui.keyCode.DOWN: + this.next( event ); + break; + case $.ui.keyCode.LEFT: + this.collapse( event ); + break; + case $.ui.keyCode.RIGHT: + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + this.expand( event ); + } + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate( event ); + break; + case $.ui.keyCode.ESCAPE: + this.collapse( event ); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + character = String.fromCharCode( event.keyCode ); + skip = false; + + clearTimeout( this.filterTimer ); + + if ( character === prev ) { + skip = true; + } else { + character = prev + character; + } + + regex = new RegExp( "^" + escape( character ), "i" ); + match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { + return regex.test( $( this ).children( "a" ).text() ); + }); + match = skip && match.index( this.active.next() ) !== -1 ? + this.active.nextAll( ".ui-menu-item" ) : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if ( !match.length ) { + character = String.fromCharCode( event.keyCode ); + regex = new RegExp( "^" + escape( character ), "i" ); + match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { + return regex.test( $( this ).children( "a" ).text() ); + }); + } + + if ( match.length ) { + this.focus( event, match ); + if ( match.length > 1 ) { + this.previousFilter = character; + this.filterTimer = this._delay(function() { + delete this.previousFilter; + }, 1000 ); + } else { + delete this.previousFilter; + } + } else { + delete this.previousFilter; + } + } + + if ( preventDefault ) { + event.preventDefault(); + } + }, + + _activate: function( event ) { + if ( !this.active.is( ".ui-state-disabled" ) ) { + if ( this.active.children( "a[aria-haspopup='true']" ).length ) { + this.expand( event ); + } else { + this.select( event ); + } + } + }, + + refresh: function() { + var menus, + icon = this.options.icons.submenu, + submenus = this.element.find( this.options.menus ); + + // Initialize nested menus + submenus.filter( ":not(.ui-menu)" ) + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .hide() + .attr({ + role: this.options.role, + "aria-hidden": "true", + "aria-expanded": "false" + }) + .each(function() { + var menu = $( this ), + item = menu.prev( "a" ), + submenuCarat = $( "<span>" ) + .addClass( "ui-menu-icon ui-icon " + icon ) + .data( "ui-menu-submenu-carat", true ); + + item + .attr( "aria-haspopup", "true" ) + .prepend( submenuCarat ); + menu.attr( "aria-labelledby", item.attr( "id" ) ); + }); + + menus = submenus.add( this.element ); + + // Don't refresh list items that are already adapted + menus.children( ":not(.ui-menu-item):has(a)" ) + .addClass( "ui-menu-item" ) + .attr( "role", "presentation" ) + .children( "a" ) + .uniqueId() + .addClass( "ui-corner-all" ) + .attr({ + tabIndex: -1, + role: this._itemRole() + }); + + // Initialize unlinked menu-items containing spaces and/or dashes only as dividers + menus.children( ":not(.ui-menu-item)" ).each(function() { + var item = $( this ); + // hyphen, em dash, en dash + if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) { + item.addClass( "ui-widget-content ui-menu-divider" ); + } + }); + + // Add aria-disabled attribute to any disabled menu item + menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); + + // If the active item has been removed, blur the menu + if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + this.blur(); + } + }, + + _itemRole: function() { + return { + menu: "menuitem", + listbox: "option" + }[ this.options.role ]; + }, + + _setOption: function( key, value ) { + if ( key === "icons" ) { + this.element.find( ".ui-menu-icon" ) + .removeClass( this.options.icons.submenu ) + .addClass( value.submenu ); + } + this._super( key, value ); + }, + + focus: function( event, item ) { + var nested, focused; + this.blur( event, event && event.type === "focus" ); + + this._scrollIntoView( item ); + + this.active = item.first(); + focused = this.active.children( "a" ).addClass( "ui-state-focus" ); + // Only update aria-activedescendant if there's a role + // otherwise we assume focus is managed elsewhere + if ( this.options.role ) { + this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); + } + + // Highlight active parent menu item, if any + this.active + .parent() + .closest( ".ui-menu-item" ) + .children( "a:first" ) + .addClass( "ui-state-active" ); + + if ( event && event.type === "keydown" ) { + this._close(); + } else { + this.timer = this._delay(function() { + this._close(); + }, this.delay ); + } + + nested = item.children( ".ui-menu" ); + if ( nested.length && ( /^mouse/.test( event.type ) ) ) { + this._startOpening(nested); + } + this.activeMenu = item.parent(); + + this._trigger( "focus", event, { item: item } ); + }, + + _scrollIntoView: function( item ) { + var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; + if ( this._hasScroll() ) { + borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; + paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; + offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; + scroll = this.activeMenu.scrollTop(); + elementHeight = this.activeMenu.height(); + itemHeight = item.height(); + + if ( offset < 0 ) { + this.activeMenu.scrollTop( scroll + offset ); + } else if ( offset + itemHeight > elementHeight ) { + this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); + } + } + }, + + blur: function( event, fromFocus ) { + if ( !fromFocus ) { + clearTimeout( this.timer ); + } + + if ( !this.active ) { + return; + } + + this.active.children( "a" ).removeClass( "ui-state-focus" ); + this.active = null; + + this._trigger( "blur", event, { item: this.active } ); + }, + + _startOpening: function( submenu ) { + clearTimeout( this.timer ); + + // Don't open if already open fixes a Firefox bug that caused a .5 pixel + // shift in the submenu position when mousing over the carat icon + if ( submenu.attr( "aria-hidden" ) !== "true" ) { + return; + } + + this.timer = this._delay(function() { + this._close(); + this._open( submenu ); + }, this.delay ); + }, + + _open: function( submenu ) { + var position = $.extend({ + of: this.active + }, this.options.position ); + + clearTimeout( this.timer ); + this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) + .hide() + .attr( "aria-hidden", "true" ); + + submenu + .show() + .removeAttr( "aria-hidden" ) + .attr( "aria-expanded", "true" ) + .position( position ); + }, + + collapseAll: function( event, all ) { + clearTimeout( this.timer ); + this.timer = this._delay(function() { + // If we were passed an event, look for the submenu that contains the event + var currentMenu = all ? this.element : + $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); + + // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway + if ( !currentMenu.length ) { + currentMenu = this.element; + } + + this._close( currentMenu ); + + this.blur( event ); + this.activeMenu = currentMenu; + }, this.delay ); + }, + + // With no arguments, closes the currently active menu - if nothing is active + // it closes all menus. If passed an argument, it will search for menus BELOW + _close: function( startMenu ) { + if ( !startMenu ) { + startMenu = this.active ? this.active.parent() : this.element; + } + + startMenu + .find( ".ui-menu" ) + .hide() + .attr( "aria-hidden", "true" ) + .attr( "aria-expanded", "false" ) + .end() + .find( "a.ui-state-active" ) + .removeClass( "ui-state-active" ); + }, + + collapse: function( event ) { + var newItem = this.active && + this.active.parent().closest( ".ui-menu-item", this.element ); + if ( newItem && newItem.length ) { + this._close(); + this.focus( event, newItem ); + } + }, + + expand: function( event ) { + var newItem = this.active && + this.active + .children( ".ui-menu " ) + .children( ".ui-menu-item" ) + .first(); + + if ( newItem && newItem.length ) { + this._open( newItem.parent() ); + + // Delay so Firefox will not hide activedescendant change in expanding submenu from AT + this._delay(function() { + this.focus( event, newItem ); + }); + } + }, + + next: function( event ) { + this._move( "next", "first", event ); + }, + + previous: function( event ) { + this._move( "prev", "last", event ); + }, + + isFirstItem: function() { + return this.active && !this.active.prevAll( ".ui-menu-item" ).length; + }, + + isLastItem: function() { + return this.active && !this.active.nextAll( ".ui-menu-item" ).length; + }, + + _move: function( direction, filter, event ) { + var next; + if ( this.active ) { + if ( direction === "first" || direction === "last" ) { + next = this.active + [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) + .eq( -1 ); + } else { + next = this.active + [ direction + "All" ]( ".ui-menu-item" ) + .eq( 0 ); + } + } + if ( !next || !next.length || !this.active ) { + next = this.activeMenu.children( ".ui-menu-item" )[ filter ](); + } + + this.focus( event, next ); + }, + + nextPage: function( event ) { + var item, base, height; + + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isLastItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.nextAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base - height < 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.children( ".ui-menu-item" ) + [ !this.active ? "first" : "last" ]() ); + } + }, + + previousPage: function( event ) { + var item, base, height; + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isFirstItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.prevAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base + height > 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); + } + }, + + _hasScroll: function() { + return this.element.outerHeight() < this.element.prop( "scrollHeight" ); + }, + + select: function( event ) { + // TODO: It should never be possible to not have an active item at this + // point, but the tests don't trigger mouseenter before click. + this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); + var ui = { item: this.active }; + if ( !this.active.has( ".ui-menu" ).length ) { + this.collapseAll( event, true ); + } + this._trigger( "select", event, ui ); + } +}); + +}( jQuery )); + +(function( $, undefined ) { + +$.ui = $.ui || {}; + +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), + overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ); + return { + element: withinElement, + isWindow: isWindow, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: isWindow ? withinElement.width() : withinElement.outerWidth(), + height: isWindow ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !$.support.offsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem : elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } + else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { + position.top += myOffset + atOffset + offset; + } + } + else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function () { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +}( jQuery ) ); + +(function( $, undefined ) { + +$.widget( "ui.progressbar", { + version: "1.10.2", + options: { + max: 100, + value: 0, + + change: null, + complete: null + }, + + min: 0, + + _create: function() { + // Constrain initial value + this.oldValue = this.options.value = this._constrainedValue(); + + this.element + .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .attr({ + // Only set static values, aria-valuenow and aria-valuemax are + // set inside _refreshValue() + role: "progressbar", + "aria-valuemin": this.min + }); + + this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) + .appendTo( this.element ); + + this._refreshValue(); + }, + + _destroy: function() { + this.element + .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + + this.valueDiv.remove(); + }, + + value: function( newValue ) { + if ( newValue === undefined ) { + return this.options.value; + } + + this.options.value = this._constrainedValue( newValue ); + this._refreshValue(); + }, + + _constrainedValue: function( newValue ) { + if ( newValue === undefined ) { + newValue = this.options.value; + } + + this.indeterminate = newValue === false; + + // sanitize value + if ( typeof newValue !== "number" ) { + newValue = 0; + } + + return this.indeterminate ? false : + Math.min( this.options.max, Math.max( this.min, newValue ) ); + }, + + _setOptions: function( options ) { + // Ensure "value" option is set after other values (like max) + var value = options.value; + delete options.value; + + this._super( options ); + + this.options.value = this._constrainedValue( value ); + this._refreshValue(); + }, + + _setOption: function( key, value ) { + if ( key === "max" ) { + // Don't allow a max less than min + value = Math.max( this.min, value ); + } + + this._super( key, value ); + }, + + _percentage: function() { + return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); + }, + + _refreshValue: function() { + var value = this.options.value, + percentage = this._percentage(); + + this.valueDiv + .toggle( this.indeterminate || value > this.min ) + .toggleClass( "ui-corner-right", value === this.options.max ) + .width( percentage.toFixed(0) + "%" ); + + this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); + + if ( this.indeterminate ) { + this.element.removeAttr( "aria-valuenow" ); + if ( !this.overlayDiv ) { + this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv ); + } + } else { + this.element.attr({ + "aria-valuemax": this.options.max, + "aria-valuenow": value + }); + if ( this.overlayDiv ) { + this.overlayDiv.remove(); + this.overlayDiv = null; + } + } + + if ( this.oldValue !== value ) { + this.oldValue = value; + this._trigger( "change" ); + } + if ( value === this.options.max ) { + this._trigger( "complete" ); + } + } +}); + +})( jQuery ); + +(function( $, undefined ) { + +// number of pages in a slider +// (how many times can you page up/down to go through the whole range) +var numPages = 5; + +$.widget( "ui.slider", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "slide", + + options: { + animate: false, + distance: 0, + max: 100, + min: 0, + orientation: "horizontal", + range: false, + step: 1, + value: 0, + values: null, + + // callbacks + change: null, + slide: null, + start: null, + stop: null + }, + + _create: function() { + this._keySliding = false; + this._mouseSliding = false; + this._animateOff = true; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + + this.element + .addClass( "ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all"); + + this._refresh(); + this._setOption( "disabled", this.options.disabled ); + + this._animateOff = false; + }, + + _refresh: function() { + this._createRange(); + this._createHandles(); + this._setupEvents(); + this._refreshValue(); + }, + + _createHandles: function() { + var i, handleCount, + options = this.options, + existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), + handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", + handles = []; + + handleCount = ( options.values && options.values.length ) || 1; + + if ( existingHandles.length > handleCount ) { + existingHandles.slice( handleCount ).remove(); + existingHandles = existingHandles.slice( 0, handleCount ); + } + + for ( i = existingHandles.length; i < handleCount; i++ ) { + handles.push( handle ); + } + + this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); + + this.handle = this.handles.eq( 0 ); + + this.handles.each(function( i ) { + $( this ).data( "ui-slider-handle-index", i ); + }); + }, + + _createRange: function() { + var options = this.options, + classes = ""; + + if ( options.range ) { + if ( options.range === true ) { + if ( !options.values ) { + options.values = [ this._valueMin(), this._valueMin() ]; + } else if ( options.values.length && options.values.length !== 2 ) { + options.values = [ options.values[0], options.values[0] ]; + } else if ( $.isArray( options.values ) ) { + options.values = options.values.slice(0); + } + } + + if ( !this.range || !this.range.length ) { + this.range = $( "<div></div>" ) + .appendTo( this.element ); + + classes = "ui-slider-range" + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + " ui-widget-header ui-corner-all"; + } else { + this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) + // Handle range switching from true to min/max + .css({ + "left": "", + "bottom": "" + }); + } + + this.range.addClass( classes + + ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); + } else { + this.range = $([]); + } + }, + + _setupEvents: function() { + var elements = this.handles.add( this.range ).filter( "a" ); + this._off( elements ); + this._on( elements, this._handleEvents ); + this._hoverable( elements ); + this._focusable( elements ); + }, + + _destroy: function() { + this.handles.remove(); + this.range.remove(); + + this.element + .removeClass( "ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" ); + + this._mouseDestroy(); + }, + + _mouseCapture: function( event ) { + var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, + that = this, + o = this.options; + + if ( o.disabled ) { + return false; + } + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + position = { x: event.pageX, y: event.pageY }; + normValue = this._normValueFromMouse( position ); + distance = this._valueMax() - this._valueMin() + 1; + this.handles.each(function( i ) { + var thisDistance = Math.abs( normValue - that.values(i) ); + if (( distance > thisDistance ) || + ( distance === thisDistance && + (i === that._lastChangedValue || that.values(i) === o.min ))) { + distance = thisDistance; + closestHandle = $( this ); + index = i; + } + }); + + allowed = this._start( event, index ); + if ( allowed === false ) { + return false; + } + this._mouseSliding = true; + + this._handleIndex = index; + + closestHandle + .addClass( "ui-state-active" ) + .focus(); + + offset = closestHandle.offset(); + mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - ( closestHandle.width() / 2 ), + top: event.pageY - offset.top - + ( closestHandle.height() / 2 ) - + ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - + ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + + ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) + }; + + if ( !this.handles.hasClass( "ui-state-hover" ) ) { + this._slide( event, index, normValue ); + } + this._animateOff = true; + return true; + }, + + _mouseStart: function() { + return true; + }, + + _mouseDrag: function( event ) { + var position = { x: event.pageX, y: event.pageY }, + normValue = this._normValueFromMouse( position ); + + this._slide( event, this._handleIndex, normValue ); + + return false; + }, + + _mouseStop: function( event ) { + this.handles.removeClass( "ui-state-active" ); + this._mouseSliding = false; + + this._stop( event, this._handleIndex ); + this._change( event, this._handleIndex ); + + this._handleIndex = null; + this._clickOffset = null; + this._animateOff = false; + + return false; + }, + + _detectOrientation: function() { + this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; + }, + + _normValueFromMouse: function( position ) { + var pixelTotal, + pixelMouse, + percentMouse, + valueTotal, + valueMouse; + + if ( this.orientation === "horizontal" ) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); + } + + percentMouse = ( pixelMouse / pixelTotal ); + if ( percentMouse > 1 ) { + percentMouse = 1; + } + if ( percentMouse < 0 ) { + percentMouse = 0; + } + if ( this.orientation === "vertical" ) { + percentMouse = 1 - percentMouse; + } + + valueTotal = this._valueMax() - this._valueMin(); + valueMouse = this._valueMin() + percentMouse * valueTotal; + + return this._trimAlignValue( valueMouse ); + }, + + _start: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + return this._trigger( "start", event, uiHash ); + }, + + _slide: function( event, index, newVal ) { + var otherVal, + newValues, + allowed; + + if ( this.options.values && this.options.values.length ) { + otherVal = this.values( index ? 0 : 1 ); + + if ( ( this.options.values.length === 2 && this.options.range === true ) && + ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) + ) { + newVal = otherVal; + } + + if ( newVal !== this.values( index ) ) { + newValues = this.values(); + newValues[ index ] = newVal; + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal, + values: newValues + } ); + otherVal = this.values( index ? 0 : 1 ); + if ( allowed !== false ) { + this.values( index, newVal, true ); + } + } + } else { + if ( newVal !== this.value() ) { + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal + } ); + if ( allowed !== false ) { + this.value( newVal ); + } + } + } + }, + + _stop: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + this._trigger( "stop", event, uiHash ); + }, + + _change: function( event, index ) { + if ( !this._keySliding && !this._mouseSliding ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + //store the last changed value index for reference when handles overlap + this._lastChangedValue = index; + + this._trigger( "change", event, uiHash ); + } + }, + + value: function( newValue ) { + if ( arguments.length ) { + this.options.value = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, 0 ); + return; + } + + return this._value(); + }, + + values: function( index, newValue ) { + var vals, + newValues, + i; + + if ( arguments.length > 1 ) { + this.options.values[ index ] = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, index ); + return; + } + + if ( arguments.length ) { + if ( $.isArray( arguments[ 0 ] ) ) { + vals = this.options.values; + newValues = arguments[ 0 ]; + for ( i = 0; i < vals.length; i += 1 ) { + vals[ i ] = this._trimAlignValue( newValues[ i ] ); + this._change( null, i ); + } + this._refreshValue(); + } else { + if ( this.options.values && this.options.values.length ) { + return this._values( index ); + } else { + return this.value(); + } + } + } else { + return this._values(); + } + }, + + _setOption: function( key, value ) { + var i, + valsLength = 0; + + if ( key === "range" && this.options.range === true ) { + if ( value === "min" ) { + this.options.value = this._values( 0 ); + this.options.values = null; + } else if ( value === "max" ) { + this.options.value = this._values( this.options.values.length-1 ); + this.options.values = null; + } + } + + if ( $.isArray( this.options.values ) ) { + valsLength = this.options.values.length; + } + + $.Widget.prototype._setOption.apply( this, arguments ); + + switch ( key ) { + case "orientation": + this._detectOrientation(); + this.element + .removeClass( "ui-slider-horizontal ui-slider-vertical" ) + .addClass( "ui-slider-" + this.orientation ); + this._refreshValue(); + break; + case "value": + this._animateOff = true; + this._refreshValue(); + this._change( null, 0 ); + this._animateOff = false; + break; + case "values": + this._animateOff = true; + this._refreshValue(); + for ( i = 0; i < valsLength; i += 1 ) { + this._change( null, i ); + } + this._animateOff = false; + break; + case "min": + case "max": + this._animateOff = true; + this._refreshValue(); + this._animateOff = false; + break; + case "range": + this._animateOff = true; + this._refresh(); + this._animateOff = false; + break; + } + }, + + //internal value getter + // _value() returns value trimmed by min and max, aligned by step + _value: function() { + var val = this.options.value; + val = this._trimAlignValue( val ); + + return val; + }, + + //internal values getter + // _values() returns array of values trimmed by min and max, aligned by step + // _values( index ) returns single value trimmed by min and max, aligned by step + _values: function( index ) { + var val, + vals, + i; + + if ( arguments.length ) { + val = this.options.values[ index ]; + val = this._trimAlignValue( val ); + + return val; + } else if ( this.options.values && this.options.values.length ) { + // .slice() creates a copy of the array + // this copy gets trimmed by min and max and then returned + vals = this.options.values.slice(); + for ( i = 0; i < vals.length; i+= 1) { + vals[ i ] = this._trimAlignValue( vals[ i ] ); + } + + return vals; + } else { + return []; + } + }, + + // returns the step-aligned value that val is closest to, between (inclusive) min and max + _trimAlignValue: function( val ) { + if ( val <= this._valueMin() ) { + return this._valueMin(); + } + if ( val >= this._valueMax() ) { + return this._valueMax(); + } + var step = ( this.options.step > 0 ) ? this.options.step : 1, + valModStep = (val - this._valueMin()) % step, + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat( alignValue.toFixed(5) ); + }, + + _valueMin: function() { + return this.options.min; + }, + + _valueMax: function() { + return this.options.max; + }, + + _refreshValue: function() { + var lastValPercent, valPercent, value, valueMin, valueMax, + oRange = this.options.range, + o = this.options, + that = this, + animate = ( !this._animateOff ) ? o.animate : false, + _set = {}; + + if ( this.options.values && this.options.values.length ) { + this.handles.each(function( i ) { + valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; + _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + if ( that.options.range === true ) { + if ( that.orientation === "horizontal" ) { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } else { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + } + lastValPercent = valPercent; + }); + } else { + value = this.value(); + valueMin = this._valueMin(); + valueMax = this._valueMax(); + valPercent = ( valueMax !== valueMin ) ? + ( value - valueMin ) / ( valueMax - valueMin ) * 100 : + 0; + _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + + if ( oRange === "min" && this.orientation === "horizontal" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "horizontal" ) { + this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + if ( oRange === "min" && this.orientation === "vertical" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "vertical" ) { + this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + }, + + _handleEvents: { + keydown: function( event ) { + /*jshint maxcomplexity:25*/ + var allowed, curVal, newVal, step, + index = $( event.target ).data( "ui-slider-handle-index" ); + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_UP: + case $.ui.keyCode.PAGE_DOWN: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + event.preventDefault(); + if ( !this._keySliding ) { + this._keySliding = true; + $( event.target ).addClass( "ui-state-active" ); + allowed = this._start( event, index ); + if ( allowed === false ) { + return; + } + } + break; + } + + step = this.options.step; + if ( this.options.values && this.options.values.length ) { + curVal = newVal = this.values( index ); + } else { + curVal = newVal = this.value(); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + newVal = this._valueMin(); + break; + case $.ui.keyCode.END: + newVal = this._valueMax(); + break; + case $.ui.keyCode.PAGE_UP: + newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.PAGE_DOWN: + newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if ( curVal === this._valueMax() ) { + return; + } + newVal = this._trimAlignValue( curVal + step ); + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if ( curVal === this._valueMin() ) { + return; + } + newVal = this._trimAlignValue( curVal - step ); + break; + } + + this._slide( event, index, newVal ); + }, + click: function( event ) { + event.preventDefault(); + }, + keyup: function( event ) { + var index = $( event.target ).data( "ui-slider-handle-index" ); + + if ( this._keySliding ) { + this._keySliding = false; + this._stop( event, index ); + this._change( event, index ); + $( event.target ).removeClass( "ui-state-active" ); + } + } + } + +}); + +}(jQuery)); + +(function( $ ) { + +function modifier( fn ) { + return function() { + var previous = this.element.val(); + fn.apply( this, arguments ); + this._refresh(); + if ( previous !== this.element.val() ) { + this._trigger( "change" ); + } + }; +} + +$.widget( "ui.spinner", { + version: "1.10.2", + defaultElement: "<input>", + widgetEventPrefix: "spin", + options: { + culture: null, + icons: { + down: "ui-icon-triangle-1-s", + up: "ui-icon-triangle-1-n" + }, + incremental: true, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + + change: null, + spin: null, + start: null, + stop: null + }, + + _create: function() { + // handle string values that need to be parsed + this._setOption( "max", this.options.max ); + this._setOption( "min", this.options.min ); + this._setOption( "step", this.options.step ); + + // format the value, but don't constrain + this._value( this.element.val(), true ); + + this._draw(); + this._on( this._events ); + this._refresh(); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _getCreateOptions: function() { + var options = {}, + element = this.element; + + $.each( [ "min", "max", "step" ], function( i, option ) { + var value = element.attr( option ); + if ( value !== undefined && value.length ) { + options[ option ] = value; + } + }); + + return options; + }, + + _events: { + keydown: function( event ) { + if ( this._start( event ) && this._keydown( event ) ) { + event.preventDefault(); + } + }, + keyup: "_stop", + focus: function() { + this.previous = this.element.val(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + this._stop(); + this._refresh(); + if ( this.previous !== this.element.val() ) { + this._trigger( "change", event ); + } + }, + mousewheel: function( event, delta ) { + if ( !delta ) { + return; + } + if ( !this.spinning && !this._start( event ) ) { + return false; + } + + this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); + clearTimeout( this.mousewheelTimer ); + this.mousewheelTimer = this._delay(function() { + if ( this.spinning ) { + this._stop( event ); + } + }, 100 ); + event.preventDefault(); + }, + "mousedown .ui-spinner-button": function( event ) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[0] === this.document[0].activeElement ? + this.previous : this.element.val(); + function checkFocus() { + var isActive = this.element[0] === this.document[0].activeElement; + if ( !isActive ) { + this.element.focus(); + this.previous = previous; + // support: IE + // IE sets focus asynchronously, so we need to check if focus + // moved off of the input because the user clicked on the button. + this._delay(function() { + this.previous = previous; + }); + } + } + + // ensure focus is on (or stays on) the text field + event.preventDefault(); + checkFocus.call( this ); + + // support: IE + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + // and check (again) if focus moved off of the input. + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + checkFocus.call( this ); + }); + + if ( this._start( event ) === false ) { + return; + } + + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + "mouseup .ui-spinner-button": "_stop", + "mouseenter .ui-spinner-button": function( event ) { + // button will add ui-state-active if mouse was down while mouseleave and kept down + if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { + return; + } + + if ( this._start( event ) === false ) { + return false; + } + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + // TODO: do we really want to consider this a stop? + // shouldn't we just stop the repeater and wait until mouseup before + // we trigger the stop event? + "mouseleave .ui-spinner-button": "_stop" + }, + + _draw: function() { + var uiSpinner = this.uiSpinner = this.element + .addClass( "ui-spinner-input" ) + .attr( "autocomplete", "off" ) + .wrap( this._uiSpinnerHtml() ) + .parent() + // add buttons + .append( this._buttonHtml() ); + + this.element.attr( "role", "spinbutton" ); + + // button bindings + this.buttons = uiSpinner.find( ".ui-spinner-button" ) + .attr( "tabIndex", -1 ) + .button() + .removeClass( "ui-corner-all" ); + + // IE 6 doesn't understand height: 50% for the buttons + // unless the wrapper has an explicit height + if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && + uiSpinner.height() > 0 ) { + uiSpinner.height( uiSpinner.height() ); + } + + // disable spinner if element was already disabled + if ( this.options.disabled ) { + this.disable(); + } + }, + + _keydown: function( event ) { + var options = this.options, + keyCode = $.ui.keyCode; + + switch ( event.keyCode ) { + case keyCode.UP: + this._repeat( null, 1, event ); + return true; + case keyCode.DOWN: + this._repeat( null, -1, event ); + return true; + case keyCode.PAGE_UP: + this._repeat( null, options.page, event ); + return true; + case keyCode.PAGE_DOWN: + this._repeat( null, -options.page, event ); + return true; + } + + return false; + }, + + _uiSpinnerHtml: function() { + return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"; + }, + + _buttonHtml: function() { + return "" + + "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" + + "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" + + "</a>" + + "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" + + "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" + + "</a>"; + }, + + _start: function( event ) { + if ( !this.spinning && this._trigger( "start", event ) === false ) { + return false; + } + + if ( !this.counter ) { + this.counter = 1; + } + this.spinning = true; + return true; + }, + + _repeat: function( i, steps, event ) { + i = i || 500; + + clearTimeout( this.timer ); + this.timer = this._delay(function() { + this._repeat( 40, steps, event ); + }, i ); + + this._spin( steps * this.options.step, event ); + }, + + _spin: function( step, event ) { + var value = this.value() || 0; + + if ( !this.counter ) { + this.counter = 1; + } + + value = this._adjustValue( value + step * this._increment( this.counter ) ); + + if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { + this._value( value ); + this.counter++; + } + }, + + _increment: function( i ) { + var incremental = this.options.incremental; + + if ( incremental ) { + return $.isFunction( incremental ) ? + incremental( i ) : + Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 ); + } + + return 1; + }, + + _precision: function() { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); + } + return precision; + }, + + _precisionOf: function( num ) { + var str = num.toString(), + decimal = str.indexOf( "." ); + return decimal === -1 ? 0 : str.length - decimal - 1; + }, + + _adjustValue: function( value ) { + var base, aboveMin, + options = this.options; + + // make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value - base; + // - round to the nearest step + aboveMin = Math.round(aboveMin / options.step) * options.step; + // - rounding is based on 0, so adjust back to our base + value = base + aboveMin; + + // fix precision from bad JS floating point math + value = parseFloat( value.toFixed( this._precision() ) ); + + // clamp the value + if ( options.max !== null && value > options.max) { + return options.max; + } + if ( options.min !== null && value < options.min ) { + return options.min; + } + + return value; + }, + + _stop: function( event ) { + if ( !this.spinning ) { + return; + } + + clearTimeout( this.timer ); + clearTimeout( this.mousewheelTimer ); + this.counter = 0; + this.spinning = false; + this._trigger( "stop", event ); + }, + + _setOption: function( key, value ) { + if ( key === "culture" || key === "numberFormat" ) { + var prevValue = this._parse( this.element.val() ); + this.options[ key ] = value; + this.element.val( this._format( prevValue ) ); + return; + } + + if ( key === "max" || key === "min" || key === "step" ) { + if ( typeof value === "string" ) { + value = this._parse( value ); + } + } + if ( key === "icons" ) { + this.buttons.first().find( ".ui-icon" ) + .removeClass( this.options.icons.up ) + .addClass( value.up ); + this.buttons.last().find( ".ui-icon" ) + .removeClass( this.options.icons.down ) + .addClass( value.down ); + } + + this._super( key, value ); + + if ( key === "disabled" ) { + if ( value ) { + this.element.prop( "disabled", true ); + this.buttons.button( "disable" ); + } else { + this.element.prop( "disabled", false ); + this.buttons.button( "enable" ); + } + } + }, + + _setOptions: modifier(function( options ) { + this._super( options ); + this._value( this.element.val() ); + }), + + _parse: function( val ) { + if ( typeof val === "string" && val !== "" ) { + val = window.Globalize && this.options.numberFormat ? + Globalize.parseFloat( val, 10, this.options.culture ) : +val; + } + return val === "" || isNaN( val ) ? null : val; + }, + + _format: function( value ) { + if ( value === "" ) { + return ""; + } + return window.Globalize && this.options.numberFormat ? + Globalize.format( value, this.options.numberFormat, this.options.culture ) : + value; + }, + + _refresh: function() { + this.element.attr({ + "aria-valuemin": this.options.min, + "aria-valuemax": this.options.max, + // TODO: what should we do with values that can't be parsed? + "aria-valuenow": this._parse( this.element.val() ) + }); + }, + + // update the value without triggering change + _value: function( value, allowAny ) { + var parsed; + if ( value !== "" ) { + parsed = this._parse( value ); + if ( parsed !== null ) { + if ( !allowAny ) { + parsed = this._adjustValue( parsed ); + } + value = this._format( parsed ); + } + } + this.element.val( value ); + this._refresh(); + }, + + _destroy: function() { + this.element + .removeClass( "ui-spinner-input" ) + .prop( "disabled", false ) + .removeAttr( "autocomplete" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + this.uiSpinner.replaceWith( this.element ); + }, + + stepUp: modifier(function( steps ) { + this._stepUp( steps ); + }), + _stepUp: function( steps ) { + if ( this._start() ) { + this._spin( (steps || 1) * this.options.step ); + this._stop(); + } + }, + + stepDown: modifier(function( steps ) { + this._stepDown( steps ); + }), + _stepDown: function( steps ) { + if ( this._start() ) { + this._spin( (steps || 1) * -this.options.step ); + this._stop(); + } + }, + + pageUp: modifier(function( pages ) { + this._stepUp( (pages || 1) * this.options.page ); + }), + + pageDown: modifier(function( pages ) { + this._stepDown( (pages || 1) * this.options.page ); + }), + + value: function( newVal ) { + if ( !arguments.length ) { + return this._parse( this.element.val() ); + } + modifier( this._value ).call( this, newVal ); + }, + + widget: function() { + return this.uiSpinner; + } +}); + +}( jQuery ) ); + +(function( $, undefined ) { + +var tabId = 0, + rhash = /#.*$/; + +function getNextTabId() { + return ++tabId; +} + +function isLocal( anchor ) { + return anchor.hash.length > 1 && + decodeURIComponent( anchor.href.replace( rhash, "" ) ) === + decodeURIComponent( location.href.replace( rhash, "" ) ); +} + +$.widget( "ui.tabs", { + version: "1.10.2", + delay: 300, + options: { + active: null, + collapsible: false, + event: "click", + heightStyle: "content", + hide: null, + show: null, + + // callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null + }, + + _create: function() { + var that = this, + options = this.options; + + this.running = false; + + this.element + .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-tabs-collapsible", options.collapsible ) + // Prevent users from focusing disabled tabs via click + .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) { + if ( $( this ).is( ".ui-state-disabled" ) ) { + event.preventDefault(); + } + }) + // support: IE <9 + // Preventing the default action in mousedown doesn't prevent IE + // from focusing the element, so if the anchor gets focused, blur. + // We don't have to worry about focusing the previously focused + // element since clicking on a non-focusable element should focus + // the body anyway. + .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { + if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { + this.blur(); + } + }); + + this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( $.isArray( options.disabled ) ) { + options.disabled = $.unique( options.disabled.concat( + $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { + return that.tabs.index( li ); + }) + ) ).sort(); + } + + // check for length avoids error when initializing empty list + if ( this.options.active !== false && this.anchors.length ) { + this.active = this._findActive( options.active ); + } else { + this.active = $(); + } + + this._refresh(); + + if ( this.active.length ) { + this.load( options.active ); + } + }, + + _initialActive: function() { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHash = location.hash.substring( 1 ); + + if ( active === null ) { + // check the fragment identifier in the URL + if ( locationHash ) { + this.tabs.each(function( i, tab ) { + if ( $( tab ).attr( "aria-controls" ) === locationHash ) { + active = i; + return false; + } + }); + } + + // check for a tab marked active via a class + if ( active === null ) { + active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); + } + + // no active tab, set to false + if ( active === null || active === -1 ) { + active = this.tabs.length ? 0 : false; + } + } + + // handle numbers: negative, out of range + if ( active !== false ) { + active = this.tabs.index( this.tabs.eq( active ) ); + if ( active === -1 ) { + active = collapsible ? false : 0; + } + } + + // don't allow collapsible: false and active: false + if ( !collapsible && active === false && this.anchors.length ) { + active = 0; + } + + return active; + }, + + _getCreateEventData: function() { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab( this.active ) + }; + }, + + _tabKeydown: function( event ) { + /*jshint maxcomplexity:15*/ + var focusedTab = $( this.document[0].activeElement ).closest( "li" ), + selectedIndex = this.tabs.index( focusedTab ), + goingForward = true; + + if ( this._handlePageNav( event ) ) { + return; + } + + switch ( event.keyCode ) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length - 1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + // Activate only, no collapsing + event.preventDefault(); + clearTimeout( this.activating ); + this._activate( selectedIndex ); + return; + case $.ui.keyCode.ENTER: + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout( this.activating ); + // Determine if we should collapse or activate + this._activate( selectedIndex === this.options.active ? false : selectedIndex ); + return; + default: + return; + } + + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout( this.activating ); + selectedIndex = this._focusNextTab( selectedIndex, goingForward ); + + // Navigating with control key will prevent automatic activation + if ( !event.ctrlKey ) { + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr( "aria-selected", "false" ); + this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); + + this.activating = this._delay(function() { + this.option( "active", selectedIndex ); + }, this.delay ); + } + }, + + _panelKeydown: function( event ) { + if ( this._handlePageNav( event ) ) { + return; + } + + // Ctrl+up moves focus to the current tab + if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { + event.preventDefault(); + this.active.focus(); + } + }, + + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function( event ) { + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { + this._activate( this._focusNextTab( this.options.active - 1, false ) ); + return true; + } + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { + this._activate( this._focusNextTab( this.options.active + 1, true ) ); + return true; + } + }, + + _findNextTab: function( index, goingForward ) { + var lastTabIndex = this.tabs.length - 1; + + function constrain() { + if ( index > lastTabIndex ) { + index = 0; + } + if ( index < 0 ) { + index = lastTabIndex; + } + return index; + } + + while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { + index = goingForward ? index + 1 : index - 1; + } + + return index; + }, + + _focusNextTab: function( index, goingForward ) { + index = this._findNextTab( index, goingForward ); + this.tabs.eq( index ).focus(); + return index; + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "disabled" ) { + // don't use the widget factory's disabled handling + this._setupDisabled( value ); + return; + } + + this._super( key, value); + + if ( key === "collapsible" ) { + this.element.toggleClass( "ui-tabs-collapsible", value ); + // Setting collapsible: false while collapsed; open first panel + if ( !value && this.options.active === false ) { + this._activate( 0 ); + } + } + + if ( key === "event" ) { + this._setupEvents( value ); + } + + if ( key === "heightStyle" ) { + this._setupHeightStyle( value ); + } + }, + + _tabId: function( tab ) { + return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId(); + }, + + _sanitizeSelector: function( hash ) { + return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; + }, + + refresh: function() { + var options = this.options, + lis = this.tablist.children( ":has(a[href])" ); + + // get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { + return lis.index( tab ); + }); + + this._processTabs(); + + // was collapsed or no tabs + if ( options.active === false || !this.anchors.length ) { + options.active = false; + this.active = $(); + // was active, but active tab is gone + } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { + // all remaining tabs are disabled + if ( this.tabs.length === options.disabled.length ) { + options.active = false; + this.active = $(); + // activate previous tab + } else { + this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); + } + // was active, active tab still exists + } else { + // make sure active index is correct + options.active = this.tabs.index( this.active ); + } + + this._refresh(); + }, + + _refresh: function() { + this._setupDisabled( this.options.disabled ); + this._setupEvents( this.options.event ); + this._setupHeightStyle( this.options.heightStyle ); + + this.tabs.not( this.active ).attr({ + "aria-selected": "false", + tabIndex: -1 + }); + this.panels.not( this._getPanelForTab( this.active ) ) + .hide() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + + // Make sure one tab is in the tab order + if ( !this.active.length ) { + this.tabs.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active + .addClass( "ui-tabs-active ui-state-active" ) + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + this._getPanelForTab( this.active ) + .show() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + }, + + _processTabs: function() { + var that = this; + + this.tablist = this._getList() + .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .attr( "role", "tablist" ); + + this.tabs = this.tablist.find( "> li:has(a[href])" ) + .addClass( "ui-state-default ui-corner-top" ) + .attr({ + role: "tab", + tabIndex: -1 + }); + + this.anchors = this.tabs.map(function() { + return $( "a", this )[ 0 ]; + }) + .addClass( "ui-tabs-anchor" ) + .attr({ + role: "presentation", + tabIndex: -1 + }); + + this.panels = $(); + + this.anchors.each(function( i, anchor ) { + var selector, panel, panelId, + anchorId = $( anchor ).uniqueId().attr( "id" ), + tab = $( anchor ).closest( "li" ), + originalAriaControls = tab.attr( "aria-controls" ); + + // inline tab + if ( isLocal( anchor ) ) { + selector = anchor.hash; + panel = that.element.find( that._sanitizeSelector( selector ) ); + // remote tab + } else { + panelId = that._tabId( tab ); + selector = "#" + panelId; + panel = that.element.find( selector ); + if ( !panel.length ) { + panel = that._createPanel( panelId ); + panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); + } + panel.attr( "aria-live", "polite" ); + } + + if ( panel.length) { + that.panels = that.panels.add( panel ); + } + if ( originalAriaControls ) { + tab.data( "ui-tabs-aria-controls", originalAriaControls ); + } + tab.attr({ + "aria-controls": selector.substring( 1 ), + "aria-labelledby": anchorId + }); + panel.attr( "aria-labelledby", anchorId ); + }); + + this.panels + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .attr( "role", "tabpanel" ); + }, + + // allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function() { + return this.element.find( "ol,ul" ).eq( 0 ); + }, + + _createPanel: function( id ) { + return $( "<div>" ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "ui-tabs-destroy", true ); + }, + + _setupDisabled: function( disabled ) { + if ( $.isArray( disabled ) ) { + if ( !disabled.length ) { + disabled = false; + } else if ( disabled.length === this.anchors.length ) { + disabled = true; + } + } + + // disable tabs + for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { + if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { + $( li ) + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } else { + $( li ) + .removeClass( "ui-state-disabled" ) + .removeAttr( "aria-disabled" ); + } + } + + this.options.disabled = disabled; + }, + + _setupEvents: function( event ) { + var events = { + click: function( event ) { + event.preventDefault(); + } + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.anchors.add( this.tabs ).add( this.panels ) ); + this._on( this.anchors, events ); + this._on( this.tabs, { keydown: "_tabKeydown" } ); + this._on( this.panels, { keydown: "_panelKeydown" } ); + + this._focusable( this.tabs ); + this._hoverable( this.tabs ); + }, + + _setupHeightStyle: function( heightStyle ) { + var maxHeight, + parent = this.element.parent(); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + maxHeight -= this.element.outerHeight() - this.element.height(); + + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.element.children().not( this.panels ).each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.panels.each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.panels.each(function() { + maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); + }).height( maxHeight ); + } + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + anchor = $( event.currentTarget ), + tab = anchor.closest( "li" ), + clickedIsActive = tab[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab( tab ), + toHide = !active.length ? $() : this._getPanelForTab( active ), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow + }; + + event.preventDefault(); + + if ( tab.hasClass( "ui-state-disabled" ) || + // tab is already loading + tab.hasClass( "ui-tabs-loading" ) || + // can't switch durning an animation + this.running || + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.tabs.index( tab ); + + this.active = clickedIsActive ? $() : tab; + if ( this.xhr ) { + this.xhr.abort(); + } + + if ( !toHide.length && !toShow.length ) { + $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); + } + + if ( toShow.length ) { + this.load( this.tabs.index( tab ), event ); + } + this._toggle( event, eventData ); + }, + + // handles show/hide for selecting tabs + _toggle: function( event, eventData ) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; + + this.running = true; + + function complete() { + that.running = false; + that._trigger( "activate", event, eventData ); + } + + function show() { + eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); + + if ( toShow.length && that.options.show ) { + that._show( toShow, that.options.show, complete ); + } else { + toShow.show(); + complete(); + } + } + + // start out by hiding, then showing, then completing + if ( toHide.length && this.options.hide ) { + this._hide( toHide, this.options.hide, function() { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + show(); + }); + } else { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + toHide.hide(); + show(); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + eventData.oldTab.attr( "aria-selected", "false" ); + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if ( toShow.length && toHide.length ) { + eventData.oldTab.attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.tabs.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow.attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + eventData.newTab.attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _activate: function( index ) { + var anchor, + active = this._findActive( index ); + + // trying to activate the already active panel + if ( active[ 0 ] === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the current active header + if ( !active.length ) { + active = this.active; + } + + anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; + this._eventHandler({ + target: anchor, + currentTarget: anchor, + preventDefault: $.noop + }); + }, + + _findActive: function( index ) { + return index === false ? $() : this.tabs.eq( index ); + }, + + _getIndex: function( index ) { + // meta-function to give users option to provide a href string instead of a numerical index. + if ( typeof index === "string" ) { + index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); + } + + return index; + }, + + _destroy: function() { + if ( this.xhr ) { + this.xhr.abort(); + } + + this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); + + this.tablist + .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .removeAttr( "role" ); + + this.anchors + .removeClass( "ui-tabs-anchor" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeUniqueId(); + + this.tabs.add( this.panels ).each(function() { + if ( $.data( this, "ui-tabs-destroy" ) ) { + $( this ).remove(); + } else { + $( this ) + .removeClass( "ui-state-default ui-state-active ui-state-disabled " + + "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-live" ) + .removeAttr( "aria-busy" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "role" ); + } + }); + + this.tabs.each(function() { + var li = $( this ), + prev = li.data( "ui-tabs-aria-controls" ); + if ( prev ) { + li + .attr( "aria-controls", prev ) + .removeData( "ui-tabs-aria-controls" ); + } else { + li.removeAttr( "aria-controls" ); + } + }); + + this.panels.show(); + + if ( this.options.heightStyle !== "content" ) { + this.panels.css( "height", "" ); + } + }, + + enable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === false ) { + return; + } + + if ( index === undefined ) { + disabled = false; + } else { + index = this._getIndex( index ); + if ( $.isArray( disabled ) ) { + disabled = $.map( disabled, function( num ) { + return num !== index ? num : null; + }); + } else { + disabled = $.map( this.tabs, function( li, num ) { + return num !== index ? num : null; + }); + } + } + this._setupDisabled( disabled ); + }, + + disable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === true ) { + return; + } + + if ( index === undefined ) { + disabled = true; + } else { + index = this._getIndex( index ); + if ( $.inArray( index, disabled ) !== -1 ) { + return; + } + if ( $.isArray( disabled ) ) { + disabled = $.merge( [ index ], disabled ).sort(); + } else { + disabled = [ index ]; + } + } + this._setupDisabled( disabled ); + }, + + load: function( index, event ) { + index = this._getIndex( index ); + var that = this, + tab = this.tabs.eq( index ), + anchor = tab.find( ".ui-tabs-anchor" ), + panel = this._getPanelForTab( tab ), + eventData = { + tab: tab, + panel: panel + }; + + // not remote + if ( isLocal( anchor[ 0 ] ) ) { + return; + } + + this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); + + // support: jQuery <1.8 + // jQuery <1.8 returns false if the request is canceled in beforeSend, + // but as of 1.8, $.ajax() always returns a jqXHR object. + if ( this.xhr && this.xhr.statusText !== "canceled" ) { + tab.addClass( "ui-tabs-loading" ); + panel.attr( "aria-busy", "true" ); + + this.xhr + .success(function( response ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + panel.html( response ); + that._trigger( "load", event, eventData ); + }, 1 ); + }) + .complete(function( jqXHR, status ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + if ( status === "abort" ) { + that.panels.stop( false, true ); + } + + tab.removeClass( "ui-tabs-loading" ); + panel.removeAttr( "aria-busy" ); + + if ( jqXHR === that.xhr ) { + delete that.xhr; + } + }, 1 ); + }); + } + }, + + _ajaxSettings: function( anchor, event, eventData ) { + var that = this; + return { + url: anchor.attr( "href" ), + beforeSend: function( jqXHR, settings ) { + return that._trigger( "beforeLoad", event, + $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) ); + } + }; + }, + + _getPanelForTab: function( tab ) { + var id = $( tab ).attr( "aria-controls" ); + return this.element.find( this._sanitizeSelector( "#" + id ) ); + } +}); + +})( jQuery ); + +(function( $ ) { + +var increments = 0; + +function addDescribedBy( elem, id ) { + var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); + describedby.push( id ); + elem + .data( "ui-tooltip-id", id ) + .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); +} + +function removeDescribedBy( elem ) { + var id = elem.data( "ui-tooltip-id" ), + describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), + index = $.inArray( id, describedby ); + if ( index !== -1 ) { + describedby.splice( index, 1 ); + } + + elem.removeData( "ui-tooltip-id" ); + describedby = $.trim( describedby.join( " " ) ); + if ( describedby ) { + elem.attr( "aria-describedby", describedby ); + } else { + elem.removeAttr( "aria-describedby" ); + } +} + +$.widget( "ui.tooltip", { + version: "1.10.2", + options: { + content: function() { + // support: IE<9, Opera in jQuery <1.7 + // .text() can't accept undefined, so coerce to a string + var title = $( this ).attr( "title" ) || ""; + // Escape title, since we're going from an attribute to raw HTML + return $( "<a>" ).text( title ).html(); + }, + hide: true, + // Disabled elements have inconsistent behavior across browsers (#8661) + items: "[title]:not([disabled])", + position: { + my: "left top+15", + at: "left bottom", + collision: "flipfit flip" + }, + show: true, + tooltipClass: null, + track: false, + + // callbacks + close: null, + open: null + }, + + _create: function() { + this._on({ + mouseover: "open", + focusin: "open" + }); + + // IDs of generated tooltips, needed for destroy + this.tooltips = {}; + // IDs of parent tooltips where we removed the title attribute + this.parents = {}; + + if ( this.options.disabled ) { + this._disable(); + } + }, + + _setOption: function( key, value ) { + var that = this; + + if ( key === "disabled" ) { + this[ value ? "_disable" : "_enable" ](); + this.options[ key ] = value; + // disable element style changes + return; + } + + this._super( key, value ); + + if ( key === "content" ) { + $.each( this.tooltips, function( id, element ) { + that._updateContent( element ); + }); + } + }, + + _disable: function() { + var that = this; + + // close open tooltips + $.each( this.tooltips, function( id, element ) { + var event = $.Event( "blur" ); + event.target = event.currentTarget = element[0]; + that.close( event, true ); + }); + + // remove title attributes to prevent native tooltips + this.element.find( this.options.items ).addBack().each(function() { + var element = $( this ); + if ( element.is( "[title]" ) ) { + element + .data( "ui-tooltip-title", element.attr( "title" ) ) + .attr( "title", "" ); + } + }); + }, + + _enable: function() { + // restore title attributes + this.element.find( this.options.items ).addBack().each(function() { + var element = $( this ); + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + }); + }, + + open: function( event ) { + var that = this, + target = $( event ? event.target : this.element ) + // we need closest here due to mouseover bubbling, + // but always pointing at the same event target + .closest( this.options.items ); + + // No element to show a tooltip for or the tooltip is already open + if ( !target.length || target.data( "ui-tooltip-id" ) ) { + return; + } + + if ( target.attr( "title" ) ) { + target.data( "ui-tooltip-title", target.attr( "title" ) ); + } + + target.data( "ui-tooltip-open", true ); + + // kill parent tooltips, custom or native, for hover + if ( event && event.type === "mouseover" ) { + target.parents().each(function() { + var parent = $( this ), + blurEvent; + if ( parent.data( "ui-tooltip-open" ) ) { + blurEvent = $.Event( "blur" ); + blurEvent.target = blurEvent.currentTarget = this; + that.close( blurEvent, true ); + } + if ( parent.attr( "title" ) ) { + parent.uniqueId(); + that.parents[ this.id ] = { + element: this, + title: parent.attr( "title" ) + }; + parent.attr( "title", "" ); + } + }); + } + + this._updateContent( target, event ); + }, + + _updateContent: function( target, event ) { + var content, + contentOption = this.options.content, + that = this, + eventType = event ? event.type : null; + + if ( typeof contentOption === "string" ) { + return this._open( event, target, contentOption ); + } + + content = contentOption.call( target[0], function( response ) { + // ignore async response if tooltip was closed already + if ( !target.data( "ui-tooltip-open" ) ) { + return; + } + // IE may instantly serve a cached response for ajax requests + // delay this call to _open so the other call to _open runs first + that._delay(function() { + // jQuery creates a special event for focusin when it doesn't + // exist natively. To improve performance, the native event + // object is reused and the type is changed. Therefore, we can't + // rely on the type being correct after the event finished + // bubbling, so we set it back to the previous value. (#8740) + if ( event ) { + event.type = eventType; + } + this._open( event, target, response ); + }); + }); + if ( content ) { + this._open( event, target, content ); + } + }, + + _open: function( event, target, content ) { + var tooltip, events, delayedShow, + positionOption = $.extend( {}, this.options.position ); + + if ( !content ) { + return; + } + + // Content can be updated multiple times. If the tooltip already + // exists, then just update the content and bail. + tooltip = this._find( target ); + if ( tooltip.length ) { + tooltip.find( ".ui-tooltip-content" ).html( content ); + return; + } + + // if we have a title, clear it to prevent the native tooltip + // we have to check first to avoid defining a title if none exists + // (we don't want to cause an element to start matching [title]) + // + // We use removeAttr only for key events, to allow IE to export the correct + // accessible attributes. For mouse events, set to empty string to avoid + // native tooltip showing up (happens only when removing inside mouseover). + if ( target.is( "[title]" ) ) { + if ( event && event.type === "mouseover" ) { + target.attr( "title", "" ); + } else { + target.removeAttr( "title" ); + } + } + + tooltip = this._tooltip( target ); + addDescribedBy( target, tooltip.attr( "id" ) ); + tooltip.find( ".ui-tooltip-content" ).html( content ); + + function position( event ) { + positionOption.of = event; + if ( tooltip.is( ":hidden" ) ) { + return; + } + tooltip.position( positionOption ); + } + if ( this.options.track && event && /^mouse/.test( event.type ) ) { + this._on( this.document, { + mousemove: position + }); + // trigger once to override element-relative positioning + position( event ); + } else { + tooltip.position( $.extend({ + of: target + }, this.options.position ) ); + } + + tooltip.hide(); + + this._show( tooltip, this.options.show ); + // Handle tracking tooltips that are shown with a delay (#8644). As soon + // as the tooltip is visible, position the tooltip using the most recent + // event. + if ( this.options.show && this.options.show.delay ) { + delayedShow = this.delayedShow = setInterval(function() { + if ( tooltip.is( ":visible" ) ) { + position( positionOption.of ); + clearInterval( delayedShow ); + } + }, $.fx.interval ); + } + + this._trigger( "open", event, { tooltip: tooltip } ); + + events = { + keyup: function( event ) { + if ( event.keyCode === $.ui.keyCode.ESCAPE ) { + var fakeEvent = $.Event(event); + fakeEvent.currentTarget = target[0]; + this.close( fakeEvent, true ); + } + }, + remove: function() { + this._removeTooltip( tooltip ); + } + }; + if ( !event || event.type === "mouseover" ) { + events.mouseleave = "close"; + } + if ( !event || event.type === "focusin" ) { + events.focusout = "close"; + } + this._on( true, target, events ); + }, + + close: function( event ) { + var that = this, + target = $( event ? event.currentTarget : this.element ), + tooltip = this._find( target ); + + // disabling closes the tooltip, so we need to track when we're closing + // to avoid an infinite loop in case the tooltip becomes disabled on close + if ( this.closing ) { + return; + } + + // Clear the interval for delayed tracking tooltips + clearInterval( this.delayedShow ); + + // only set title if we had one before (see comment in _open()) + if ( target.data( "ui-tooltip-title" ) ) { + target.attr( "title", target.data( "ui-tooltip-title" ) ); + } + + removeDescribedBy( target ); + + tooltip.stop( true ); + this._hide( tooltip, this.options.hide, function() { + that._removeTooltip( $( this ) ); + }); + + target.removeData( "ui-tooltip-open" ); + this._off( target, "mouseleave focusout keyup" ); + // Remove 'remove' binding only on delegated targets + if ( target[0] !== this.element[0] ) { + this._off( target, "remove" ); + } + this._off( this.document, "mousemove" ); + + if ( event && event.type === "mouseleave" ) { + $.each( this.parents, function( id, parent ) { + $( parent.element ).attr( "title", parent.title ); + delete that.parents[ id ]; + }); + } + + this.closing = true; + this._trigger( "close", event, { tooltip: tooltip } ); + this.closing = false; + }, + + _tooltip: function( element ) { + var id = "ui-tooltip-" + increments++, + tooltip = $( "<div>" ) + .attr({ + id: id, + role: "tooltip" + }) + .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + + ( this.options.tooltipClass || "" ) ); + $( "<div>" ) + .addClass( "ui-tooltip-content" ) + .appendTo( tooltip ); + tooltip.appendTo( this.document[0].body ); + this.tooltips[ id ] = element; + return tooltip; + }, + + _find: function( target ) { + var id = target.data( "ui-tooltip-id" ); + return id ? $( "#" + id ) : $(); + }, + + _removeTooltip: function( tooltip ) { + tooltip.remove(); + delete this.tooltips[ tooltip.attr( "id" ) ]; + }, + + _destroy: function() { + var that = this; + + // close open tooltips + $.each( this.tooltips, function( id, element ) { + // Delegate to close method to handle common cleanup + var event = $.Event( "blur" ); + event.target = event.currentTarget = element[0]; + that.close( event, true ); + + // Remove immediately; destroying an open tooltip doesn't use the + // hide animation + $( "#" + id ).remove(); + + // Restore the title + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + element.removeData( "ui-tooltip-title" ); + } + }); + } +}); + +}( jQuery ) ); diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.min.js b/winery/org.eclipse.winery.repository/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.min.js new file mode 100644 index 0000000..629f140 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.min.js @@ -0,0 +1,12 @@ +/*! jQuery UI - v1.10.2 - 2013-03-14 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ +(function(t,e){function i(e,i){var n,o,a,r=e.nodeName.toLowerCase();return"area"===r?(n=e.parentNode,o=n.name,e.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap=#"+o+"]")[0],!!a&&s(a)):!1):(/input|select|textarea|button|object/.test(r)?!e.disabled:"a"===r?e.href||i:i)&&s(e)}function s(e){return t.expr.filters.visible(e)&&!t(e).parents().addBack().filter(function(){return"hidden"===t.css(this,"visibility")}).length}var n=0,o=/^ui-id-\d+$/;t.ui=t.ui||{},t.extend(t.ui,{version:"1.10.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),t.fn.extend({focus:function(e){return function(i,s){return"number"==typeof i?this.each(function(){var e=this;setTimeout(function(){t(e).focus(),s&&s.call(e)},i)}):e.apply(this,arguments)}}(t.fn.focus),scrollParent:function(){var e;return e=t.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(t.css(this,"position"))&&/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!e.length?t(document):e},zIndex:function(i){if(i!==e)return this.css("zIndex",i);if(this.length)for(var s,n,o=t(this[0]);o.length&&o[0]!==document;){if(s=o.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(n=parseInt(o.css("zIndex"),10),!isNaN(n)&&0!==n))return n;o=o.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){o.test(this.id)&&t(this).removeAttr("id")})}}),t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])},focusable:function(e){return i(e,!isNaN(t.attr(e,"tabindex")))},tabbable:function(e){var s=t.attr(e,"tabindex"),n=isNaN(s);return(n||s>=0)&&i(e,!n)}}),t("<a>").outerWidth(1).jquery||t.each(["Width","Height"],function(i,s){function n(e,i,s,n){return t.each(o,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),n&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var o="Width"===s?["Left","Right"]:["Top","Bottom"],a=s.toLowerCase(),r={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+s]=function(i){return i===e?r["inner"+s].call(this):this.each(function(){t(this).css(a,n(this,i)+"px")})},t.fn["outer"+s]=function(e,i){return"number"!=typeof e?r["outer"+s].call(this,e):this.each(function(){t(this).css(a,n(this,e,!0,i)+"px")})}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(t.fn.removeData=function(e){return function(i){return arguments.length?e.call(this,t.camelCase(i)):e.call(this)}}(t.fn.removeData)),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),t.support.selectstart="onselectstart"in document.createElement("div"),t.fn.extend({disableSelection:function(){return this.bind((t.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(t){t.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),t.extend(t.ui,{plugin:{add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i){var s,n=t.plugins[e];if(n&&t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType)for(s=0;n.length>s;s++)t.options[n[s][0]]&&n[s][1].apply(t.element,i)}},hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)}})})(jQuery),function(t,e){var i=0,s=Array.prototype.slice,n=t.cleanData;t.cleanData=function(e){for(var i,s=0;null!=(i=e[s]);s++)try{t(i).triggerHandler("remove")}catch(o){}n(e)},t.widget=function(i,s,n){var o,a,r,h,l={},c=i.split(".")[0];i=i.split(".")[1],o=c+"-"+i,n||(n=s,s=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},a=t[c][i],r=t[c][i]=function(t,i){return this._createWidget?(arguments.length&&this._createWidget(t,i),e):new r(t,i)},t.extend(r,a,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),h=new s,h.options=t.widget.extend({},h.options),t.each(n,function(i,n){return t.isFunction(n)?(l[i]=function(){var t=function(){return s.prototype[i].apply(this,arguments)},e=function(t){return s.prototype[i].apply(this,t)};return function(){var i,s=this._super,o=this._superApply;return this._super=t,this._superApply=e,i=n.apply(this,arguments),this._super=s,this._superApply=o,i}}(),e):(l[i]=n,e)}),r.prototype=t.widget.extend(h,{widgetEventPrefix:a?h.widgetEventPrefix:i},l,{constructor:r,namespace:c,widgetName:i,widgetFullName:o}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,r,i._proto)}),delete a._childConstructors):s._childConstructors.push(r),t.widget.bridge(i,r)},t.widget.extend=function(i){for(var n,o,a=s.call(arguments,1),r=0,h=a.length;h>r;r++)for(n in a[r])o=a[r][n],a[r].hasOwnProperty(n)&&o!==e&&(i[n]=t.isPlainObject(o)?t.isPlainObject(i[n])?t.widget.extend({},i[n],o):t.widget.extend({},o):o);return i},t.widget.bridge=function(i,n){var o=n.prototype.widgetFullName||i;t.fn[i]=function(a){var r="string"==typeof a,h=s.call(arguments,1),l=this;return a=!r&&h.length?t.widget.extend.apply(null,[a].concat(h)):a,r?this.each(function(){var s,n=t.data(this,o);return n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(s=n[a].apply(n,h),s!==n&&s!==e?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):e):t.error("no such method '"+a+"' for "+i+" widget instance"):t.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var e=t.data(this,o);e?e.option(a||{})._init():t.data(this,o,new n(a,this))}),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this.bindings=t(),this.hoverable=t(),this.focusable=t(),s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(i,s){var n,o,a,r=i;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof i)if(r={},n=i.split("."),i=n.shift(),n.length){for(o=r[i]=t.widget.extend({},this.options[i]),a=0;n.length-1>a;a++)o[n[a]]=o[n[a]]||{},o=o[n[a]];if(i=n.pop(),s===e)return o[i]===e?null:o[i];o[i]=s}else{if(s===e)return this.options[i]===e?null:this.options[i];r[i]=s}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!e).attr("aria-disabled",e),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var o,a=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=o=t(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,o=this.widget()),t.each(n,function(n,r){function h(){return i||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?a[r]:r).apply(a,arguments):e}"string"!=typeof r&&(h.guid=r.guid=r.guid||h.guid||t.guid++);var l=n.match(/^(\w+)\s*(.*)$/),c=l[1]+a.eventNamespace,u=l[2];u?o.delegate(u,c,h):s.bind(c,h)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(e).undelegate(e)},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}})}(jQuery),function(t){var e=!1;t(document).mouseup(function(){e=!1}),t.widget("ui.mouse",{version:"1.10.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!e){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,o="string"==typeof this.options.cancel&&i.target.nodeName?t(i.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===t.data(i.target,this.widgetName+".preventClickEvent")&&t.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return s._mouseMove(t)},this._mouseUpDelegate=function(t){return s._mouseUp(t)},t(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),e=!0,!0)):!0}},_mouseMove:function(e){return t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button?this._mouseUp(e):this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})}(jQuery),function(t){t.widget("ui.draggable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(t(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){t("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(t(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),i.containment&&this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_mouseDrag:function(e,i){if(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i,s=this,n=!1,o=!1;for(t.ui.ddmanager&&!this.options.dropBehaviour&&(o=t.ui.ddmanager.drop(this,e)),this.dropped&&(o=this.dropped,this.dropped=!1),i=this.element[0];i&&(i=i.parentNode);)i===document&&(n=!0);return n||"original"!==this.options.helper?("invalid"===this.options.revert&&!o||"valid"===this.options.revert&&o||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,o)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",e)!==!1&&s._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1):!1},_mouseUp:function(e){return t("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.element.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;if("parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=["document"===n.containment?0:t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,"document"===n.containment?0:t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,("document"===n.containment?0:t(window).scrollLeft())+t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,("document"===n.containment?0:t(window).scrollTop())+(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||n.containment.constructor===Array)n.containment.constructor===Array&&(this.containment=n.containment);else{if(i=t(n.containment),s=i[0],!s)return;e="hidden"!==t(s).css("overflow"),this.containment=[(parseInt(t(s).css("borderLeftWidth"),10)||0)+(parseInt(t(s).css("paddingLeft"),10)||0),(parseInt(t(s).css("borderTopWidth"),10)||0)+(parseInt(t(s).css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(t(s).css("borderRightWidth"),10)||0)-(parseInt(t(s).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(t(s).css("borderBottomWidth"),10)||0)-(parseInt(t(s).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i}},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n,o,a=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName),l=e.pageX,c=e.pageY;return this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.left<i[0]&&(l=i[0]+this.offset.click.left),e.pageY-this.offset.click.top<i[1]&&(c=i[1]+this.offset.click.top),e.pageX-this.offset.click.left>i[2]&&(l=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(c=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((c-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,c=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,l=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o)),{top:c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s]),"drag"===e&&(this.positionAbs=this._convertPositionTo("absolute")),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i){var s=t(this).data("ui-draggable"),n=s.options,o=t.extend({},i,{item:s.element});s.sortables=[],t(n.connectToSortable).each(function(){var i=t.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",e,o))})},stop:function(e,i){var s=t(this).data("ui-draggable"),n=t.extend({},i,{item:s.element});t.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(e),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",e,n))})},drag:function(e,i){var s=t(this).data("ui-draggable"),n=this;t.each(s.sortables,function(){var o=!1,a=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(o=!0,t.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==a&&this.instance._intersectsWith(this.instance.containerCache)&&t.contains(a.instance.element[0],this.instance.element[0])&&(o=!1),o})),o?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=t(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},e.target=this.instance.currentItem[0],this.instance._mouseCapture(e,!0),this.instance._mouseStart(e,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",e),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(e)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",e,this.instance._uiHash(this.instance)),this.instance._mouseStop(e,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",e),s.dropped=!1)})}}),t.ui.plugin.add("draggable","cursor",{start:function(){var e=t("body"),i=t(this).data("ui-draggable").options;e.css("cursor")&&(i._cursor=e.css("cursor")),e.css("cursor",i.cursor)},stop:function(){var e=t(this).data("ui-draggable").options;e._cursor&&t("body").css("cursor",e._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._opacity&&t(i.helper).css("opacity",s._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(){var e=t(this).data("ui-draggable");e.scrollParent[0]!==document&&"HTML"!==e.scrollParent[0].tagName&&(e.overflowOffset=e.scrollParent.offset())},drag:function(e){var i=t(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-e.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:e.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-e.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:e.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(e.pageY-t(document).scrollTop()<s.scrollSensitivity?n=t(document).scrollTop(t(document).scrollTop()-s.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<s.scrollSensitivity&&(n=t(document).scrollTop(t(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(e.pageX-t(document).scrollLeft()<s.scrollSensitivity?n=t(document).scrollLeft(t(document).scrollLeft()-s.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<s.scrollSensitivity&&(n=t(document).scrollLeft(t(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&t.ui.ddmanager&&!s.dropBehaviour&&t.ui.ddmanager.prepareOffsets(i,e)}}),t.ui.plugin.add("draggable","snap",{start:function(){var e=t(this).data("ui-draggable"),i=e.options;e.snapElements=[],t(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=t(this),s=i.offset();this!==e.element[0]&&e.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(e,i){var s,n,o,a,r,h,l,c,u,d,p=t(this).data("ui-draggable"),f=p.options,g=f.snapTolerance,m=i.offset.left,v=m+p.helperProportions.width,_=i.offset.top,b=_+p.helperProportions.height;for(u=p.snapElements.length-1;u>=0;u--)r=p.snapElements[u].left,h=r+p.snapElements[u].width,l=p.snapElements[u].top,c=l+p.snapElements[u].height,m>r-g&&h+g>m&&_>l-g&&c+g>_||m>r-g&&h+g>m&&b>l-g&&c+g>b||v>r-g&&h+g>v&&_>l-g&&c+g>_||v>r-g&&h+g>v&&b>l-g&&c+g>b?("inner"!==f.snapMode&&(s=g>=Math.abs(l-b),n=g>=Math.abs(c-_),o=g>=Math.abs(r-v),a=g>=Math.abs(h-m),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||o||a,"outer"!==f.snapMode&&(s=g>=Math.abs(l-_),n=g>=Math.abs(c-b),o=g>=Math.abs(r-m),a=g>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c-p.helperProportions.height,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[u].snapping&&(s||n||o||a||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=s||n||o||a||d):(p.snapElements[u].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=!1)}}),t.ui.plugin.add("draggable","stack",{start:function(){var e,i=this.data("ui-draggable").options,s=t.makeArray(t(i.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});s.length&&(e=parseInt(t(s[0]).css("zIndex"),10)||0,t(s).each(function(i){t(this).css("zIndex",e+i)}),this.css("zIndex",e+s.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._zIndex&&t(i.helper).css("zIndex",s._zIndex)}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}t.widget("ui.droppable",{version:"1.10.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e=this.options,i=e.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(i)?i:function(t){return t.is(i)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},t.ui.ddmanager.droppables[e.scope]=t.ui.ddmanager.droppables[e.scope]||[],t.ui.ddmanager.droppables[e.scope].push(this),e.addClasses&&this.element.addClass("ui-droppable") +},_destroy:function(){for(var e=0,i=t.ui.ddmanager.droppables[this.options.scope];i.length>e;e++)i[e]===this&&i.splice(e,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(e,i){"accept"===e&&(this.accept=t.isFunction(i)?i:function(t){return t.is(i)}),t.Widget.prototype._setOption.apply(this,arguments)},_activate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var e=t.data(this,"ui-droppable");return e.options.greedy&&!e.options.disabled&&e.options.scope===s.options.scope&&e.accept.call(e.element[0],s.currentItem||s.element)&&t.ui.intersect(s,t.extend(e,{offset:e.element.offset()}),e.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}}}),t.ui.intersect=function(t,i,s){if(!i.offset)return!1;var n,o,a=(t.positionAbs||t.position.absolute).left,r=a+t.helperProportions.width,h=(t.positionAbs||t.position.absolute).top,l=h+t.helperProportions.height,c=i.offset.left,u=c+i.proportions.width,d=i.offset.top,p=d+i.proportions.height;switch(s){case"fit":return a>=c&&u>=r&&h>=d&&p>=l;case"intersect":return a+t.helperProportions.width/2>c&&u>r-t.helperProportions.width/2&&h+t.helperProportions.height/2>d&&p>l-t.helperProportions.height/2;case"pointer":return n=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,o=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(o,d,i.proportions.height)&&e(n,c,i.proportions.width);case"touch":return(h>=d&&p>=h||l>=d&&p>=l||d>h&&l>p)&&(a>=c&&u>=a||r>=c&&u>=r||c>a&&r>u);default:return!1}},t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions.height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions={width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight})}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&t.ui.intersect(e,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").bind("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=t.ui.intersect(e,this,this.options.tolerance),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t.data(this,"ui-droppable").options.scope===n}),o.length&&(s=t.data(o[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").unbind("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}}}(jQuery),function(t){function e(t){return parseInt(t,10)||0}function i(t){return!isNaN(parseInt(t,10))}t.widget("ui.resizable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var e,i,s,n,o,a=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(t("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),o="ui-resizable-"+s,n=t("<div class='ui-resizable-handle "+o+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=t(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),t(this.handles[i]).length},this._renderAxis(this.element),this._handles=t(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){a.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),a.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),a._handles.show())}).mouseleave(function(){r.disabled||a.resizing||(t(this).addClass("ui-resizable-autohide"),a._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,o,a=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=e(this.helper.css("left")),n=e(this.helper.css("top")),a.containment&&(s+=t(a.containment).scrollLeft()||0,n+=t(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,o=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===o?this.axis+"-resize":o),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(e){var i,s=this.helper,n={},o=this.originalMousePosition,a=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,c=this.size.height,u=e.pageX-o.left||0,d=e.pageY-o.top||0,p=this._change[a];return p?(i=p.apply(this,[e,u,d]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==c&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(n)||this._trigger("resize",e,this.ui()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&t.ui.hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null,h=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(t){var e,s,n,o,a,r=this.options;a={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||t)&&(e=a.minHeight*this.aspectRatio,n=a.minWidth/this.aspectRatio,s=a.maxHeight*this.aspectRatio,o=a.maxWidth/this.aspectRatio,e>a.minWidth&&(a.minWidth=e),n>a.minHeight&&(a.minHeight=n),a.maxWidth>s&&(a.maxWidth=s),a.maxHeight>o&&(a.maxHeight=o)),this._vBoundaries=a},_updateCache:function(t){this.offset=this.helper.offset(),i(t.left)&&(this.position.left=t.left),i(t.top)&&(this.position.top=t.top),i(t.height)&&(this.size.height=t.height),i(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,s=this.size,n=this.axis;return i(t.height)?t.width=t.height*this.aspectRatio:i(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===n&&(t.left=e.left+(s.width-t.width),t.top=null),"nw"===n&&(t.top=e.top+(s.height-t.height),t.left=e.left+(s.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,s=this.axis,n=i(t.width)&&e.maxWidth&&e.maxWidth<t.width,o=i(t.height)&&e.maxHeight&&e.maxHeight<t.height,a=i(t.width)&&e.minWidth&&e.minWidth>t.width,r=i(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,c=/sw|nw|w/.test(s),u=/nw|ne|n/.test(s);return a&&(t.width=e.minWidth),r&&(t.height=e.minHeight),n&&(t.width=e.maxWidth),o&&(t.height=e.maxHeight),a&&c&&(t.left=h-e.minWidth),n&&c&&(t.left=h-e.maxWidth),r&&u&&(t.top=l-e.minHeight),o&&u&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var t,e,i,s,n,o=this.helper||this.element;for(t=0;this._proportionallyResizeElements.length>t;t++){if(n=this._proportionallyResizeElements[t],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],e=0;i.length>e;e++)this.borderDif[e]=(parseInt(i[e],10)||0)+(parseInt(s[e],10)||0);n.css({height:o.height()-this.borderDif[0]-this.borderDif[2]||0,width:o.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&t.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,c=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,o,a,r,h,l=t(this).data("ui-resizable"),c=l.options,u=l.element,d=c.containment,p=d instanceof t?d.get(0):/parent/.test(d)?u.parent().get(0):d;p&&(l.containerElement=t(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(i=t(p),s=[],t(["Top","Right","Left","Bottom"]).each(function(t,n){s[t]=e(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,o=l.containerSize.height,a=l.containerSize.width,r=t.ui.hasScroll(p,"left")?p.scrollWidth:a,h=t.ui.hasScroll(p)?p.scrollHeight:o,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(e){var i,s,n,o,a=t(this).data("ui-resizable"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio),a.position.top=a._helper?h.top:0),a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top,i=Math.abs((a._helper?a.offset.left-u.left:a.offset.left-u.left)+a.sizeDiff.width),s=Math.abs((a._helper?a.offset.top-u.top:a.offset.top-h.top)+a.sizeDiff.height),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o&&(i-=a.parentData.left),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio))},stop:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=function(e){t(e).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):t.each(i.alsoResize,function(t){s(t)})},resize:function(e,i){var s=t(this).data("ui-resizable"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0},h=function(e,s){t(e).each(function(){var e=t(this),n=t(this).data("ui-resizable-alsoresize"),o={},a=s&&s.length?s:e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(a,function(t,e){var i=(n[e]||0)+(r[e]||0);i&&i>=0&&(o[e]=i||null)}),e.css(o)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):t.each(n.alsoResize,function(t,e){h(t,e)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).data("ui-resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).data("ui-resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,a=e.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,c=Math.round((s.width-n.width)/h)*h,u=Math.round((s.height-n.height)/l)*l,d=n.width+c,p=n.height+u,f=i.maxWidth&&d>i.maxWidth,g=i.maxHeight&&p>i.maxHeight,m=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,m&&(d+=h),v&&(p+=l),f&&(d-=h),g&&(p-=l),/^(se|s|e)$/.test(a)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.top=o.top-u):/^(sw)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.left=o.left-c):(e.size.width=d,e.size.height=p,e.position.top=o.top-u,e.position.left=o.left-c)}})}(jQuery),function(t){t.widget("ui.selectable",t.ui.mouse,{version:"1.10.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e=t(i.options.filter,i.element[0]),e.addClass("ui-selectee"),e.each(function(){var e=t(this),i=e.offset();t.data(this,"selectable-item",{element:this,$element:e,left:i.left,top:i.top,right:i.left+e.outerWidth(),bottom:i.top+e.outerHeight(),startselected:!1,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=e.addClass("ui-selectee"),this._mouseInit(),this.helper=t("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||o>i.right||i.top>h||a>i.bottom):"fit"===n.tolerance&&(l=i.left>o&&r>i.right&&i.top>a&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):undefined}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("<style>*{ cursor: "+a.cursor+" !important; }</style>").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<a.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+a.scrollSpeed:e.pageY-this.overflowOffset.top<a.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-a.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<a.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+a.scrollSpeed:e.pageX-this.overflowOffset.left<a.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-a.scrollSpeed)):(e.pageY-t(document).scrollTop()<a.scrollSensitivity?r=t(document).scrollTop(t(document).scrollTop()-a.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<a.scrollSensitivity&&(r=t(document).scrollTop(t(document).scrollTop()+a.scrollSpeed)),e.pageX-t(document).scrollLeft()<a.scrollSensitivity?r=t(document).scrollLeft(t(document).scrollLeft()-a.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<a.scrollSensitivity&&(r=t(document).scrollLeft(t(document).scrollLeft()+a.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break; +this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u=s+l>r&&h>s+l&&e+c>o&&a>e+c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?u:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,o=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return n?this.floating?a&&"right"===a||"down"===o?2:1:o&&("down"===o?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return this.floating&&o?"right"===o&&s||"left"===o&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){var i,s,n,o,a=[],r=[],h=this._connectWith();if(h&&e)for(i=h.length-1;i>=0;i--)for(n=t(h[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&r.push([t.isFunction(o.options.items)?o.options.items.call(o.element):t(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(r.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=r.length-1;i>=0;i--)r[i][0].each(function(){a.push(this)});return t(a)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t(e.document[0].createElement(s)).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?n.append("<td colspan='99'> </td>"):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,o,a,r,h,l,c,u,d,p,f=null,g=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],g=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[g].containerCache.over||(this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1);else{for(a=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],o=this.items.length-1;o>=0;o--)t.contains(this.containers[g].element[0],this.items[o].item[0])&&this.items[o].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[o].top,this.items[o].height))&&(u=this.items[o].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[o][l]-c)&&(d=!0,u+=this.items[o][l]),a>Math.abs(u-c)&&(a=Math.abs(u-c),r=this.items[o],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[g])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[g].element,!0),this._trigger("change",s,this._uiHash()),this.containers[g]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[g],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(o=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(a=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)e||s.push(function(t){return function(e){t._trigger("deactivate",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(t){return function(e){t._trigger("out",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})}(jQuery),function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function s(e,i){var s,n,a={};for(s in i)n=i[s],e[s]!==n&&(o[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(a[s]=n));return a}var n=["add","remove","toggle"],o={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var e=t(this);return{el:e,start:i(this)}}),o=function(){t.each(n,function(t,i){e[i]&&a[i+"Class"](e[i])})},o(),l=l.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,o,a,r){return"boolean"==typeof n||n===e?o?t.effects.animateClass.call(this,n?{add:s}:{remove:s},o,a,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,o,a)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.2",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,o;for(o=0;s.length>o;o++)null!==s[o]&&(n=t.data(i+s[o]),n===e&&(n=""),t.css(s[o],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(o)&&o.call(n[0]),t.isFunction(e)&&e()}var n=t(this),o=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):a.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,o=i.queue,a=t.effects.effect[i.effect];return t.fx.off||!a?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):o===!1?this.each(e):this.queue(o||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()}(jQuery),function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("<span>").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove() +},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),o.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),(e.active===!1&&e.collapsible===!0||!this.headers.length)&&(e.active=!1,this.active=t()),e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,o=this.element.parent(),a=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),o=n.attr("id");s||(s=a+"-header-"+e,i.attr("id",s)),o||(o=a+"-panel-"+e,n.attr("id",o)),i.attr("aria-controls",o),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=o.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n[0]===s[0],a=o&&i.collapsible,r=a?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:a?t():n,newPanel:r};e.preventDefault(),o&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=a?!1:this.headers.index(n),this.active=o?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),o||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-expanded":"false","aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr("tabIndex",-1):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(t,e,n){var o,a,r,h=this,l=0,c=t.length&&(!e.length||t.index()<e.index()),u=this.options.animate||{},d=c&&u.down||u,p=function(){h._toggleComplete(n)};return"number"==typeof d&&(r=d),"string"==typeof d&&(a=d),a=a||d.easing||u.easing,r=r||d.duration||u.duration,e.length?t.length?(o=t.show().outerHeight(),e.animate(i,{duration:r,easing:a,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(s,{duration:r,easing:a,complete:p,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?l+=i.now:"content"!==h.options.heightStyle&&(i.now=Math.round(o-e.outerHeight()-l),l=0)}}),undefined):e.animate(i,r,a,p):t.animate(s,r,a,p)},_toggleComplete:function(t){var e=t.oldPanel;e.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}})}(jQuery),function(t){var e=0;t.widget("ui.autocomplete",{version:"1.10.2",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n;this.isMultiLine=o?!0:a?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,undefined;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:case o.NUMPAD_ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,s.preventDefault(),undefined;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),undefined):(this._searchTimeout(t),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(t),this._change(t),undefined)}}),this._initSource(),this.menu=t("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({input:t(),role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];t(e.target).closest(".ui-menu-item").length||this._delay(function(){var e=this;this.document.one("mousedown",function(s){s.target===e.element[0]||s.target===i||t.contains(i,s.target)||e.close()})})},menufocus:function(e,i){if(this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",e,{item:s})?e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=t("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertAfter(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e||(e=this.element.closest(".ui-front")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):undefined},_search:function(t){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var t=this,i=++e;return function(s){i===e&&t.__response(s),t.pending--,t.pending||t.element.removeClass("ui-autocomplete-loading")}},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({label:e.label||e.value,value:e.value||e.label},e)})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<a>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[t](e),undefined):(this.search(null,e),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.text(e))}})}(jQuery),function(t){var e,i,s,n,o="ui-button ui-widget ui-state-default ui-corner-all",a="ui-state-hover ui-state-active ",r="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",h=function(){var e=t(this).find(":ui-button");setTimeout(function(){e.button("refresh")},1)},l=function(e){var i=e.name,s=e.form,n=t([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?t(s).find("[name='"+i+"']"):t("[name='"+i+"']",e.ownerDocument).filter(function(){return!this.form})),n};t.widget("ui.button",{version:"1.10.2",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,h),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var a=this,r=this.options,c="checkbox"===this.type||"radio"===this.type,u=c?"":"ui-state-active",d="ui-state-focus";null===r.label&&(r.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(o).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){r.disabled||this===e&&t(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){r.disabled||t(this).removeClass(u)}).bind("click"+this.eventNamespace,function(t){r.disabled&&(t.preventDefault(),t.stopImmediatePropagation())}),this.element.bind("focus"+this.eventNamespace,function(){a.buttonElement.addClass(d)}).bind("blur"+this.eventNamespace,function(){a.buttonElement.removeClass(d)}),c&&(this.element.bind("change"+this.eventNamespace,function(){n||a.refresh()}),this.buttonElement.bind("mousedown"+this.eventNamespace,function(t){r.disabled||(n=!1,i=t.pageX,s=t.pageY)}).bind("mouseup"+this.eventNamespace,function(t){r.disabled||(i!==t.pageX||s!==t.pageY)&&(n=!0)})),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return r.disabled||n?!1:undefined}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(r.disabled||n)return!1;t(this).addClass("ui-state-active"),a.buttonElement.attr("aria-pressed","true");var e=a.element[0];l(e).not(e).map(function(){return t(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return r.disabled?!1:(t(this).addClass("ui-state-active"),e=this,a.document.one("mouseup",function(){e=null}),undefined)}).bind("mouseup"+this.eventNamespace,function(){return r.disabled?!1:(t(this).removeClass("ui-state-active"),undefined)}).bind("keydown"+this.eventNamespace,function(e){return r.disabled?!1:((e.keyCode===t.ui.keyCode.SPACE||e.keyCode===t.ui.keyCode.ENTER)&&t(this).addClass("ui-state-active"),undefined)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){t(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===t.ui.keyCode.SPACE&&t(this).click()})),this._setOption("disabled",r.disabled),this._resetButton()},_determineButtonType:function(){var t,e,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(t=this.element.parents().last(),e="label[for='"+this.element.attr("id")+"']",this.buttonElement=t.find(e),this.buttonElement.length||(t=t.length?t.siblings():this.element.siblings(),this.buttonElement=t.filter(e),this.buttonElement.length||(this.buttonElement=t.find(e))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(o+" "+a+" "+r).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(t,e){return this._super(t,e),"disabled"===t?(e?this.element.prop("disabled",!0):this.element.prop("disabled",!1),undefined):(this._resetButton(),undefined)},refresh:function(){var e=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");e!==this.options.disabled&&this._setOption("disabled",e),"radio"===this.type?l(this.element[0]).each(function(){t(this).is(":checked")?t(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):t(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),undefined;var e=this.buttonElement.removeClass(r),i=t("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,o=[];s.primary||s.secondary?(this.options.text&&o.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&e.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&e.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(o.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||e.attr("title",t.trim(i)))):o.push("ui-button-text-only"),e.addClass(o.join(" "))}}),t.widget("ui.buttonset",{version:"1.10.2",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(t,e){"disabled"===t&&this.buttons.button("option",t,e),this._super(t,e)},refresh:function(){var e="rtl"===this.element.css("direction");this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(e?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(e?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})}(jQuery),function(t,e){function i(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.dpDiv=s(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function s(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(i,"mouseout",function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",function(){t.datepicker._isDisabledDatepicker(o.inline?e.parent()[0]:o.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))})}function n(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}t.extend(t.ui,{datepicker:{version:"1.10.2"}});var o,a="datepicker",r=(new Date).getTime();t.extend(i.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return n(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,o;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),o=this._newInst(t(e),n),o.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,o):n&&this._inlineDatepicker(e,o)},_newInst:function(e,i){var n=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?s(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),t.data(e,a,i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,o,a=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),a&&(i.append=t("<span class='"+this._appendClass+"'>"+a+"</span>"),e[r?"before":"after"](i.append)),e.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),o=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:o,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(o?t("<img/>").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.click(function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,a,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,o,r){var h,l,c,u,d,p=this._dialogInst;return p||(this.uuid+=1,h="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+h+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),t("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},t.data(this._dialogInput[0],a,p)),n(p.settings,o||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=r?r.length?r:[r.pageX,r.pageY]:null,this._pos||(l=document.documentElement.clientWidth,c=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[l/2-100+u,c/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],a,p),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,a);s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,a),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty())},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,a)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,s,o){var a,r,h,l,c=this._getInst(i);return 2===arguments.length&&"string"==typeof s?"defaults"===s?t.extend({},t.datepicker._defaults):c?"all"===s?t.extend({},c.settings):this._get(c,s):null:(a=s||{},"string"==typeof s&&(a={},a[s]=o),c&&(this._curInst===c&&this._hideDatepicker(),r=this._getDateDatepicker(i,!0),h=this._getMinMaxDate(c,"min"),l=this._getMinMaxDate(c,"max"),n(c.settings,a),null!==h&&a.dateFormat!==e&&a.minDate===e&&(c.settings.minDate=this._formatDate(c,h)),null!==l&&a.dateFormat!==e&&a.maxDate===e&&(c.settings.maxDate=this._formatDate(c,l)),"disabled"in a&&(a.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(t(i),c),this._autoSize(c),this._setDate(c,r),this._updateAlternate(c),this._updateDatepicker(c)),e)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M"); +break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(i){var s,n,o=t.datepicker._getInst(i.target);return t.datepicker._get(o,"constrainInput")?(s=t.datepicker._possibleChars(t.datepicker._get(o,"dateFormat")),n=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">n||!s||s.indexOf(n)>-1):e},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var i,s,o,a,r,h,l;i=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==i&&(t.datepicker._curInst.dpDiv.stop(!0,!0),i&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),s=t.datepicker._get(i,"beforeShow"),o=s?s.apply(e,[e,i]):{},o!==!1&&(n(i.settings,o),i.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(i),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),a=!1,t(e).parents().each(function(){return a|="fixed"===t(this).css("position"),!a}),r={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(i),r=t.datepicker._checkOffset(i,r,a),i.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":a?"fixed":"absolute",display:"none",left:r.left+"px",top:r.top+"px"}),i.inline||(h=t.datepicker._get(i,"showAnim"),l=t.datepicker._get(i,"duration"),i.dpDiv.zIndex(t(e).zIndex()+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[h]?i.dpDiv.show(h,t.datepicker._get(i,"showOptions"),l):i.dpDiv[h||"show"](h?l:null),i.input.is(":visible")&&!i.input.is(":disabled")&&i.input.focus(),t.datepicker._curInst=i))}},_updateDatepicker:function(e){this.maxRows=4,o=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,s=this._getNumberOfMonths(e),n=s[1],a=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&e.input[0]!==document.activeElement&&e.input.focus(),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_getBorders:function(t){var e=function(t){return{thin:1,medium:2,thick:3}[t]||t};return[parseFloat(e(t.css("border-left-width"))),parseFloat(e(t.css("border-top-width")))]},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,r=this._curInst;!r||e&&r!==t.data(e,a)||this._datepickerShowing&&(i=this._get(r,"showAnim"),s=this._get(r,"duration"),n=function(){t.datepicker._tidyDialog(r)},t.effects&&(t.effects.effect[i]||t.effects[i])?r.dpDiv.hide(i,t.datepicker._get(r,"showOptions"),s,n):r.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(r,"onClose"),o&&o.apply(r.input?r.input[0]:null,[r.input?r.input.val():"",r]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).each(function(){t(this).val(n)}))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(i,s,n){if(null==i||null==s)throw"Invalid arguments";if(s="object"==typeof s?""+s:s+"",""===s)return null;var o,a,r,h,l=0,c=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof c?c:(new Date).getFullYear()%100+parseInt(c,10),d=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,p=(n?n.dayNames:null)||this._defaults.dayNames,f=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,g=(n?n.monthNames:null)||this._defaults.monthNames,m=-1,v=-1,_=-1,b=-1,y=!1,w=function(t){var e=i.length>o+1&&i.charAt(o+1)===t;return e&&o++,e},k=function(t){var e=w(t),i="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n=RegExp("^\\d{1,"+i+"}"),o=s.substring(l).match(n);if(!o)throw"Missing number at position "+l;return l+=o[0].length,parseInt(o[0],10)},x=function(i,n,o){var a=-1,r=t.map(w(i)?o:n,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(r,function(t,i){var n=i[1];return s.substr(l,n.length).toLowerCase()===n.toLowerCase()?(a=i[0],l+=n.length,!1):e}),-1!==a)return a+1;throw"Unknown name at position "+l},D=function(){if(s.charAt(l)!==i.charAt(o))throw"Unexpected literal at position "+l;l++};for(o=0;i.length>o;o++)if(y)"'"!==i.charAt(o)||w("'")?D():y=!1;else switch(i.charAt(o)){case"d":_=k("d");break;case"D":x("D",d,p);break;case"o":b=k("o");break;case"m":v=k("m");break;case"M":v=x("M",f,g);break;case"y":m=k("y");break;case"@":h=new Date(k("@")),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"!":h=new Date((k("!")-this._ticksTo1970)/1e4),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"'":w("'")?D():y=!0;break;default:D()}if(s.length>l&&(r=s.substr(l),!/^\s+/.test(r)))throw"Extra/unparsed characters found in date: "+r;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),b>-1)for(v=1,_=b;;){if(a=this._getDaysInMonth(m,v-1),a>=_)break;v++,_-=a}if(h=this._daylightSavingAdjust(new Date(m,v-1,_)),h.getFullYear()!==m||h.getMonth()+1!==v||h.getDate()!==_)throw"Invalid date";return h},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getYear()%100?"0":"")+e.getYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,i){return t.settings[i]!==e?t.settings[i]:this._defaults[i]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){window["DP_jQuery_"+r].datepicker._adjustDate(s,-i,"M")},next:function(){window["DP_jQuery_"+r].datepicker._adjustDate(s,+i,"M")},hide:function(){window["DP_jQuery_"+r].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+r].datepicker._gotoToday(s)},selectDay:function(){return window["DP_jQuery_"+r].datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+r].datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+r].datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,v,_,b,y,w,k,x,D,C,I,P,T,M,S,z,A,H,N,E,W,O,F,R,j=new Date,L=this._daylightSavingAdjust(new Date(j.getFullYear(),j.getMonth(),j.getDate())),Y=this._get(t,"isRTL"),B=this._get(t,"showButtonPanel"),V=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),q=this._get(t,"showCurrentAtPos"),Q=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],$=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),G=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-q,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=G&&G>e?G:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-Q,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":V?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+Q,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":V?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?$:L,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+a+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),v=this._get(t,"showOtherMonths"),_=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,D=0;U[1]>D;D++){if(C=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",P="",X){if(P+="<div class='ui-datepicker-group",U[1]>1)switch(D){case 0:P+=" ui-datepicker-group-first",I=" ui-corner-"+(Y?"right":"left");break;case U[1]-1:P+=" ui-datepicker-group-last",I=" ui-corner-"+(Y?"left":"right");break;default:P+=" ui-datepicker-group-middle",I=""}P+="'>"}for(P+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+I+"'>"+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,G,J,k>0||D>0,f,g)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",T=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",w=0;7>w;w++)M=(w+c)%7,T+="<th"+((w+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[M]+"'>"+p[M]+"</span></th>";for(P+=T+"</tr></thead><tbody>",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),z=(this._getFirstDayOfMonth(te,Z)-c+7)%7,A=Math.ceil((z+S)/7),H=X?this.maxRows>A?this.maxRows:A:A,this.maxRows=H,N=this._daylightSavingAdjust(new Date(te,Z,1-z)),E=0;H>E;E++){for(P+="<tr>",W=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(N)+"</td>":"",w=0;7>w;w++)O=m?m.apply(t.input?t.input[0]:null,[N]):[!0,""],F=N.getMonth()!==Z,R=F&&!_||!O[0]||G&&G>N||J&&N>J,W+="<td class='"+((w+c+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(N.getTime()===C.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===N.getTime()&&b.getTime()===C.getTime()?" "+this._dayOverClass:"")+(R?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!v?"":" "+O[1]+(N.getTime()===$.getTime()?" "+this._currentClass:"")+(N.getTime()===L.getTime()?" ui-datepicker-today":""))+"'"+(F&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"'")+"'")+(R?"":" data-handler='selectDay' data-event='click' data-month='"+N.getMonth()+"' data-year='"+N.getFullYear()+"'")+">"+(F&&!v?" ":R?"<span class='ui-state-default'>"+N.getDate()+"</span>":"<a class='ui-state-default"+(N.getTime()===L.getTime()?" ui-state-highlight":"")+(N.getTime()===$.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+"' href='#'>"+N.getDate()+"</a>")+"</td>",N.setDate(N.getDate()+1),N=this._daylightSavingAdjust(N);P+=W+"</tr>"}Z++,Z>11&&(Z=0,te++),P+="</tbody></table>"+(X?"</div>"+(U[0]>0&&D===U[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),x+=P}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),v=this._get(t,"changeYear"),_=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(o||!m)y+="<span class='ui-datepicker-month'>"+a[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+r[c]+"</option>");y+="</select>"}if(_||(b+=y+(!o&&m&&v?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";g>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),_&&(b+=(!o&&m&&v?"":" ")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.drawYear+("Y"===i?e:0),n=t.drawMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).mousedown(t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new i,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.10.2",window["DP_jQuery_"+r]=t}(jQuery),function(t){var e={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};t.widget("ui.dialog",{version:"1.10.2",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._destroyOverlay(),this.opener.filter(":focusable").focus().length||t(this.document[0].activeElement).blur(),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,e){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!e&&this._trigger("focus",t),i},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=t(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var t=this.element.find("[autofocus]");t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).focus()},_keepFocus:function(e){function i(){var e=this.document[0].activeElement,i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),undefined;if(e.keyCode===t.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(n.focus(1),e.preventDefault()):(s.focus(1),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=t("<button></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(e),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title||t.html(" "),t.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(e.element[0],arguments)},o={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,t("<button></button>",s).button(o).appendTo(e.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){t(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){s.position=[o.position.left-i.document.scrollLeft(),o.position.top-i.document.scrollTop()],t(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o)) +}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){t(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){s.height=t(this).height(),s.width=t(this).width(),t(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(s){var n=this,o=!1,a={};t.each(s,function(t,s){n._setOption(t,s),t in e&&(o=!0),t in i&&(a[t]=s)}),o&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",a)},_setOption:function(t,e){var i,s,n=this.uiDialog;"dialogClass"===t&&n.removeClass(this.options.dialogClass).addClass(e),"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:""+e}),"draggable"===t&&(i=n.is(":data(ui-draggable)"),i&&!e&&n.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&(s=n.is(":data(ui-resizable)"),s&&!e&&n.resizable("destroy"),s&&"string"==typeof e&&n.resizable("option","handles",e),s||e===!1||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=this,i=this.widgetFullName;t.ui.dialog.overlayInstances||this._delay(function(){t.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(s){e._allowInteraction(s)||(s.preventDefault(),t(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=t("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),t.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(t.ui.dialog.overlayInstances--,t.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),t.ui.dialog.overlayInstances=0,t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{_position:function(){var e,i=this.options.position,s=[],n=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(s=i.split?i.split(" "):[i[0],i[1]],1===s.length&&(s[1]=s[0]),t.each(["left","top"],function(t,e){+s[t]===s[t]&&(n[t]=s[t],s[t]=e)}),i={my:s[0]+(0>n[0]?n[0]:"+"+n[0])+" "+s[1]+(0>n[1]?n[1]:"+"+n[1]),at:s.join(" ")}),i=t.extend({},t.ui.dialog.prototype.options.position,i)):i=t.ui.dialog.prototype.options.position,e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.position(i),e||this.uiDialog.hide()}})}(jQuery),function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var o,a,r,h=t(this),l=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(h,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",g=i.test(u),m={},v="show"===c;h.parent().is(".ui-effects-wrapper")?t.effects.save(h.parent(),l):t.effects.save(h,l),h.show(),o=t.effects.createWrapper(h).css({overflow:"hidden"}),a=o[p](),r=parseFloat(o.css(f))||0,m[p]=v?a:0,g||(h.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),m[f]=v?r:a+r),v&&(o.css(p,0),g||o.css(f,r+a)),o.animate(m,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&h.hide(),t.effects.restore(h,l),t.effects.removeWrapper(h),n()}})}}(jQuery),function(t){t.effects.effect.bounce=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"effect"),l="hide"===h,c="show"===h,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||l?1:0),g=e.duration/f,m=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=a.queue(),y=b.length;for((c||l)&&r.push("opacity"),t.effects.save(a,r),a.show(),t.effects.createWrapper(a),d||(d=a["top"===v?"outerHeight":"outerWidth"]()/3),c&&(o={opacity:1},o[v]=0,a.css("opacity",0).css(v,_?2*-d:2*d).animate(o,g,m)),l&&(d/=Math.pow(2,p-1)),o={},o[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m).animate(o,g,m),d=l?2*d:d/2;l&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m)),a.queue(function(){l&&a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),a.dequeue()}}(jQuery),function(t){t.effects.effect.clip=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"hide"),l="show"===h,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(a,r),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n="IMG"===a[0].tagName?s:a,o=n[d](),l&&(n.css(d,0),n.css(p,o/2)),f[d]=l?o:0,f[p]=l?0:o/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){l||a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","opacity","height","width"],a=t.effects.setMode(n,e.mode||"hide"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,o),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===c?-s:s),u[l]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),g||p.hide(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),g="show"===f,m=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*_,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*v,l=a-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-a*v,top:-o*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(g?l*v:0),top:h+(g?c*_:0),opacity:g?0:1}).animate({left:r+(g?0:l*v),top:h+(g?0:c*_),opacity:g?1:0},e.duration||500,e.easing,s)}}(jQuery),function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}}(jQuery),function(t){t.effects.effect.fold=function(e,i){var s,n,o=t(this),a=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(o,e.mode||"hide"),h="show"===r,l="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=h!==d,f=p?["width","height"]:["height","width"],g=e.duration/2,m={},v={};t.effects.save(o,a),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[l?0:1]),h&&s.css(d?{height:0,width:c}:{height:c,width:0}),m[f[0]]=h?n[0]:c,v[f[1]]=h?n[1]:0,s.animate(m,g,e.easing).animate(v,g,e.easing,function(){l&&o.hide(),t.effects.restore(o,a),t.effects.removeWrapper(o),i()})}}(jQuery),function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],o=t.effects.setMode(s,e.mode||"show"),a={backgroundColor:s.css("backgroundColor")};"hide"===o&&(a.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(a,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&s.hide(),t.effects.restore(s,n),i()}})}}(jQuery),function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),o=t.effects.setMode(n,e.mode||"show"),a="show"===o,r="hide"===o,h=a||"hide"===o,l=2*(e.times||5)+(h?1:0),c=e.duration/l,u=0,d=n.queue(),p=d.length;for((a||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;l>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,l+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),o="hide"===n,a=parseInt(e.percent,10)||150,r=a/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:o?a:100,from:o?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),o=t.effects.setMode(s,e.mode||"effect"),a=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===o?0:100),r=e.direction||"both",h=e.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?a/100:1,x:"vertical"!==r?a/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==o&&(n.origin=h||["middle","center"],n.restore=!0),n.from=e.from||("show"===o?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*c.y,width:l.width*c.x,outerHeight:l.outerHeight*c.y,outerWidth:l.outerWidth*c.x},n.fade&&("show"===o&&(n.from.opacity=0,n.to.opacity=1),"hide"===o&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(a,e.mode||"effect"),f=e.restore||"effect"!==p,g=e.scale||"both",m=e.origin||["middle","center"],v=a.css("position"),_=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&a.show(),s={height:a.height(),width:a.width(),outerHeight:a.outerHeight(),outerWidth:a.outerWidth()},"toggle"===e.mode&&"show"===p?(a.from=e.to||b,a.to=e.from||s):(a.from=e.from||("show"===p?b:s),a.to=e.to||("hide"===p?b:s)),o={from:{y:a.from.height/s.height,x:a.from.width/s.width},to:{y:a.to.height/s.height,x:a.to.width/s.width}},("box"===g||"both"===g)&&(o.from.y!==o.to.y&&(_=_.concat(u),a.from=t.effects.setTransition(a,u,o.from.y,a.from),a.to=t.effects.setTransition(a,u,o.to.y,a.to)),o.from.x!==o.to.x&&(_=_.concat(d),a.from=t.effects.setTransition(a,d,o.from.x,a.from),a.to=t.effects.setTransition(a,d,o.to.x,a.to))),("content"===g||"both"===g)&&o.from.y!==o.to.y&&(_=_.concat(c).concat(l),a.from=t.effects.setTransition(a,c,o.from.y,a.from),a.to=t.effects.setTransition(a,c,o.to.y,a.to)),t.effects.save(a,_),a.show(),t.effects.createWrapper(a),a.css("overflow","hidden").css(a.from),m&&(n=t.effects.getBaseline(m,s),a.from.top=(s.outerHeight-a.outerHeight())*n.y,a.from.left=(s.outerWidth-a.outerWidth())*n.x,a.to.top=(s.outerHeight-a.to.outerHeight)*n.y,a.to.left=(s.outerWidth-a.to.outerWidth)*n.x),a.css(a.from),("content"===g||"both"===g)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),l=r.concat(u).concat(d),a.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,l),i.from={height:s.height*o.from.y,width:s.width*o.from.x,outerHeight:s.outerHeight*o.from.y,outerWidth:s.outerWidth*o.from.x},i.to={height:s.height*o.to.y,width:s.width*o.to.x,outerHeight:s.height*o.to.y,outerWidth:s.width*o.to.x},o.from.y!==o.to.y&&(i.from=t.effects.setTransition(i,u,o.from.y,i.from),i.to=t.effects.setTransition(i,u,o.to.y,i.to)),o.from.x!==o.to.x&&(i.from=t.effects.setTransition(i,d,o.from.x,i.from),i.to=t.effects.setTransition(i,d,o.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,l)})})),a.animate(a.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===a.to.opacity&&a.css("opacity",a.from.opacity),"hide"===p&&a.hide(),t.effects.restore(a,_),f||("static"===v?a.css({position:"relative",top:a.to.top,left:a.to.left}):t.each(["top","left"],function(t,e){a.css(e,function(e,i){var s=parseInt(i,10),n=t?a.to.left:a.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","height","width"],a=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",h=e.distance||20,l=e.times||3,c=2*l+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},g={},m={},v=n.queue(),_=v.length;for(t.effects.save(n,o),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+h,g[d]=(p?"+=":"-=")+2*h,m[d]=(p?"-=":"+=")+2*h,n.animate(f,u,e.easing),s=1;l>s;s++)n.animate(g,u,e.easing).animate(m,u,e.easing);n.animate(g,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","width","height"],a=t.effects.setMode(n,e.mode||"show"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u={};t.effects.save(n,o),n.show(),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,c?isNaN(s)?"-"+s:-s:s),u[l]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}}(jQuery),function(t){t.widget("ui.menu",{version:"1.10.2",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.mouseHandled=!0,this.select(e),i.has(".ui-menu").length?this.expand(e):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,o,a,r,h=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:h=!1,n=this.previousFilter||"",o=String.fromCharCode(e.keyCode),a=!1,clearTimeout(this.filterTimer),o===n?a=!0:o=n+o,r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=a&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(o=String.fromCharCode(e.keyCode),r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=o,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}h&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("<span>").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)}})}(jQuery),function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var o,a=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(o!==e)return o;var i,s,n=t("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),a=n.children()[0];return t("body").append(n),i=a.offsetWidth,n.css("overflow","scroll"),s=a.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),o=i-s},getScrollInfo:function(e){var i=e.isWindow?"":e.element.css("overflow-x"),s=e.isWindow?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,o="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:o?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]);return{element:i,isWindow:s,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s?i.width():i.outerWidth(),height:s?i.height():i.outerHeight()}}},t.fn.position=function(e){if(!e||!e.of)return f.apply(this,arguments);e=t.extend({},e);var o,p,g,m,v,_,b=t(e.of),y=t.position.getWithinInfo(e.within),w=t.position.getScrollInfo(y),k=(e.collision||"flip").split(" "),x={};return _=n(b),b[0].preventDefault&&(e.at="left top"),p=_.width,g=_.height,m=_.offset,v=t.extend({},m),t.each(["my","at"],function(){var t,i,s=(e[this]||"").split(" ");1===s.length&&(s=l.test(s[0])?s.concat(["center"]):c.test(s[0])?["center"].concat(s):["center","center"]),s[0]=l.test(s[0])?s[0]:"center",s[1]=c.test(s[1])?s[1]:"center",t=u.exec(s[0]),i=u.exec(s[1]),x[this]=[t?t[0]:0,i?i[0]:0],e[this]=[d.exec(s[0])[0],d.exec(s[1])[0]]}),1===k.length&&(k[1]=k[0]),"right"===e.at[0]?v.left+=p:"center"===e.at[0]&&(v.left+=p/2),"bottom"===e.at[1]?v.top+=g:"center"===e.at[1]&&(v.top+=g/2),o=i(x.at,p,g),v.left+=o[0],v.top+=o[1],this.each(function(){var n,l,c=t(this),u=c.outerWidth(),d=c.outerHeight(),f=s(this,"marginLeft"),_=s(this,"marginTop"),D=u+f+s(this,"marginRight")+w.width,C=d+_+s(this,"marginBottom")+w.height,I=t.extend({},v),P=i(x.my,c.outerWidth(),c.outerHeight());"right"===e.my[0]?I.left-=u:"center"===e.my[0]&&(I.left-=u/2),"bottom"===e.my[1]?I.top-=d:"center"===e.my[1]&&(I.top-=d/2),I.left+=P[0],I.top+=P[1],t.support.offsetFractions||(I.left=h(I.left),I.top=h(I.top)),n={marginLeft:f,marginTop:_},t.each(["left","top"],function(i,s){t.ui.position[k[i]]&&t.ui.position[k[i]][s](I,{targetWidth:p,targetHeight:g,elemWidth:u,elemHeight:d,collisionPosition:n,collisionWidth:D,collisionHeight:C,offset:[o[0]+P[0],o[1]+P[1]],my:e.my,at:e.at,within:y,elem:c})}),e.using&&(l=function(t){var i=m.left-I.left,s=i+p-u,n=m.top-I.top,o=n+g-d,h={target:{element:b,left:m.left,top:m.top,width:p,height:g},element:{element:c,left:I.left,top:I.top,width:u,height:d},horizontal:0>s?"left":i>0?"right":"center",vertical:0>o?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>g&&g>r(n+o)&&(h.vertical="middle"),h.important=a(r(i),r(s))>a(r(n),r(o))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(I,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,o=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-o-n;e.collisionWidth>o?h>0&&0>=l?(i=t.left+h+e.collisionWidth-o-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+o-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=a(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,o=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-o-n;e.collisionHeight>o?h>0&&0>=l?(i=t.top+h+e.collisionHeight-o-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+o-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=a(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,a=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-a-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-a-o,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,a=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-a-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-a-o,t.top+p+f+g>c&&(0>s||r(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,t.top+p+f+g>u&&(i>0||u>r(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,o,a=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(a?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},a&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)e.style[o]=s[o];e.appendChild(r),i=a||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()}(jQuery),function(t,e){t.widget("ui.progressbar",{version:"1.10.2",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=t("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue() +},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})}(jQuery),function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",a=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)a.push(o);this.handles=n.add(t(a.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):this.range=t([])},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,o,a,r,h,l,c=this,u=this.options;return u.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-c.values(e));(n>i||n===i&&(e===c._lastChangedValue||c.values(e)===u.min))&&(n=i,o=t(this),a=e)}),r=this._start(e,a),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=a,o.addClass("ui-state-active").focus(),h=o.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-o.width()/2,top:e.pageY-h.top-o.height()/2-(parseInt(o.css("borderTopWidth"),10)||0)-(parseInt(o.css("borderBottomWidth"),10)||0)+(parseInt(o.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,a,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,o;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),o=this._valueMin()+s*n,this._trimAlignValue(o)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,o;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,o=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),o!==!1&&this.values(e,i,!0))):i!==this.value()&&(o=this._trigger("slide",t,{handle:this.handles[e],value:i}),o!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,o;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],o=0;s.length>o;o+=1)s[o]=this._trimAlignValue(n[o]),this._change(null,o);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,o,a=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,c={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),c["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](c,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),o=this._valueMax(),i=o!==n?100*((s-n)/(o-n)):0,c["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](c,r.animate),"min"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===a&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===a&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,o,a,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(a=this.options.step,n=o=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:o=this._valueMin();break;case t.ui.keyCode.END:o=this._valueMax();break;case t.ui.keyCode.PAGE_UP:o=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:o=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;o=this._trimAlignValue(n+a);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;o=this._trimAlignValue(n-a)}this._slide(i,r,o)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})}(jQuery),function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.2",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>▲</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>▼</span>"+"</a>"},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})}(jQuery),function(t,e){function i(){return++n}function s(t){return t.hash.length>1&&decodeURIComponent(t.href.replace(o,""))===decodeURIComponent(location.href.replace(o,""))}var n=0,o=/#.*$/;t.widget("ui.tabs",{version:"1.10.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,o){return t(o).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),o=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:o=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,o),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var o,a,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),c=l.attr("aria-controls");s(n)?(o=n.hash,a=e.element.find(e._sanitizeSelector(o))):(r=e._tabId(l),o="#"+r,a=e.element.find(o),a.length||(a=e._createPanel(r),a.insertAfter(e.panels[i-1]||e.tablist)),a.attr("aria-live","polite")),a.length&&(e.panels=e.panels.add(a)),c&&l.data("ui-tabs-aria-controls",c),l.attr({"aria-controls":o.substring(1),"aria-labelledby":h}),a.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,o=this.tabs.eq(e),a=o.find(".ui-tabs-anchor"),r=this._getPanelForTab(o),h={tab:o,panel:r};s(a[0])||(this.xhr=t.ajax(this._ajaxSettings(a,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(o.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),o.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})}(jQuery),function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.2",options:{content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=o),this._open(e,t,i) +})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function o(t){l.of=t,a.is(":hidden")||a.position(l)}var a,r,h,l=t.extend({},this.options.position);if(n){if(a=this._find(s),a.length)return a.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),a=this._tooltip(s),e(s,a.attr("id")),a.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:o}),o(i)):a.position(t.extend({of:s},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){a.is(":visible")&&(o(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:a}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(a)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),o.stop(!0),this._hide(o,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:o}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("<div>").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("<div>").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})}(jQuery);
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/.gitignore b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/.gitignore new file mode 100644 index 0000000..3d88074 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/.gitignore @@ -0,0 +1,3 @@ +#common-functions.tld is generated via mvn generate-sources +#Its content is copied from org.eclipse.winery.topologymodeler +common-functions.tld diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/appengine-web.xml b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 0000000..c9883a3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> + <application>opentosca-valesca</application> + <version>1</version> + <!-- we lie at this point, but we don't want to delay execution --> + <threadsafe>true</threadsafe> +</appengine-web-app> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/functions.tld b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/functions.tld new file mode 100644 index 0000000..09921b2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/functions.tld @@ -0,0 +1,153 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<taglib + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" + version="2.1"> + + <tlib-version>1.0</tlib-version> + <short-name>Winery_Repository_Functions</short-name> + <uri>http://www.eclipse.org/winery/repository/functions</uri> + + <function> + <name>URLencode</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String URLencode(java.lang.String)</function-signature> + </function> + <function> + <name>DoubleURLencode</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String DoubleURLencode(javax.xml.namespace.QName)</function-signature> + </function> + <function> + <name>absoluteURL</name> + <function-class> org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String getAbsoluteURL(org.eclipse.winery.common.ids.GenericId)</function-signature> + </function> + <function> + <name>allNamespaces</name> + <function-class>org.eclipse.winery.repository.resources.admin.NamespacesResource</function-class> + <function-signature>java.util.Collection getNamespaces()</function-signature> + </function> + <function> + <name>allNodeTypeResources</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.util.Collection getAllNodeTypeResources()</function-signature> + </function> + <function> + <name>allRelationshipTypeResources</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.util.Collection getAllRelationshipTypeResources()</function-signature> + </function> + <function> + <name>determineIdUsingHashCode</name> + <function-class>org.eclipse.winery.repository.resources._support.collections.withoutid.IdDeterminationWithHashCode</function-class> + <function-signature>java.lang.String getIdStatically(java.lang.Object)</function-signature> + </function> + <function> + <name>isContainerLocallyAvailable</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.Boolean isContainerLocallyAvailable()</function-signature> + </function> + <function> + <name>isRestDocDocumentationAvailable</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.Boolean isRestDocDocumentationAvailable()</function-signature> + </function> + <function> + <name>namespace</name> + <function-class>org.eclipse.winery.common.ids.IdUtil</function-class> + <function-signature>org.eclipse.winery.common.ids.Namespace getNamespace(org.eclipse.winery.common.ids.GenericId)</function-signature> + </function> + <function> + <name>namespaceToJavaPackage</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String namespaceToJavaPackage(java.lang.String)</function-signature> + </function> + <function> + <name>artifactTypeQName2href</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String artifactTypeQName2href(javax.xml.namespace.QName)</function-signature> + </function> + <function> + <name>nodeTypeQName2href</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String nodeTypeQName2href(javax.xml.namespace.QName)</function-signature> + </function> + <function> + <name>policyTypeQName2href</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String policyTypeQName2href(javax.xml.namespace.QName)</function-signature> + </function> + <function> + <name>relationshipTypeQName2href</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String relationshipTypeQName2href(javax.xml.namespace.QName)</function-signature> + </function> + <function> + <name>getPrefix</name> + <function-class>org.eclipse.winery.repository.resources.admin.NamespacesResource</function-class> + <function-signature>java.lang.String getPrefix(java.lang.String)</function-signature> + </function> + <function> + <name>typeForTemplate</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>org.eclipse.winery.model.tosca.TEntityType getTypeForTemplate(org.eclipse.winery.model.tosca.TEntityTemplate)</function-signature> + </function> + + <function> + <name>renderMaxInstances</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String renderMaxInstances(java.lang.String)</function-signature> + </function> + <function> + <name>renderMinInstances</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String renderMinInstances(java.lang.Integer)</function-signature> + </function> + <function> + <name>topologyModelerURI</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String getWineryTopologyModelerPath()</function-signature> + </function> + <function> + <name>allXSDElementDefinitionsForTypeAheadSelection</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String getAllXSDElementDefinitionsForTypeAheadSelection()</function-signature> + </function> + <function> + <name>allXSDTypeDefinitionsForTypeAheadSelection</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String getAllXSDTypeDefinitionsForTypeAheadSelection()</function-signature> + </function> + + <function> + <name>doubleEscapeHTMLAndThenConvertNL2BR</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String doubleEscapeHTMLAndThenConvertNL2BR(java.lang.String)</function-signature> + </function> + <function> + <name>XML</name> + <function-class>org.eclipse.winery.repository.Utils</function-class> + <function-signature>java.lang.String getXMLAsString(java.lang.Object)</function-signature> + </function> + + <function> + <name>randomUUID</name> + <function-class>java.util.UUID</function-class> + <function-signature>java.util.UUID randomUUID()</function-signature> + </function> +</taglib> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/jetty-web.xml b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/jetty-web.xml new file mode 100644 index 0000000..a6d2944 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/jetty-web.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<Configure class="org.eclipse.jetty.webapp.WebAppContext"> + <!-- max(int) (=2 GB) is the upload size --> + <Set name="maxFormContentSize">2147483640</Set> +</Configure>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/about.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/about.tag new file mode 100644 index 0000000..351bd0f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/about.tag @@ -0,0 +1,65 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@tag description="About for the repository" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags"%> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<div class="modal fade" id="about"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Winery ${project.version}</h4> + </div> + <div class="modal-body"> + <p> Supporting <a href="docs.oasis-open.org/tosca/TOSCA/v1.0/os/TOSCA-v1.0-os.html">TOSCA-v1.0 – + Topology and Orchestration Specification for Cloud Applications Version 1.0. 25 November 2013. OASIS Standard.</a><br/> + <br/> + Part of the <a href="http://www.cloudcycle.org">CloudCycle</a> ecosystem.<br/> + <br/> + Code contributions by Oliver Kopp, Tobias Binz, Uwe Breitenbücher, Kálmán Képes, Rene Trefft, Yves Schubert, Timur Sungur, Jerome Tagliaferri, and Tobias Unger. + </p> + <h3>License</h3> + <p>The Eclipse Foundation makes available all content of this software (“Content”). + Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 (“EPL”) and the and the Apache License 2.0. + A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + A copy of the ASL is available at <a href="http://www.apache.org/licenses/LICENSE-2.0.html">http://www.apache.org/licenses/LICENSE-2.0.html</a>. + For purposes of the EPL, “Program” will mean the Content.</p> + <p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (“Redistributor”) and different terms and conditions may apply to your use of any object code in the Content. + Check the Redistributor's license that was provided with the Content. + If no such license exists, contact the Redistributor. + Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> + </div> + <div class="modal-footer"> + <c:if test="${w:isRestDocDocumentationAvailable()}"> + <a class="btn btn-primary" target="_blank" href="/restdoc.html">Show documentation of REST API</a> + </c:if> + <button type="button" class="btn btn-primary" data-dismiss="modal" id="aboutDiagOKButton">Ok</button> + </div> + </div> + </div> +</div> + +<script> +$("#about").on("shown.bs.modal", function() { + $("#aboutDiagOKButton").focus(); +}); + +function showAbout() { + $("#about").modal("show"); +} +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/addComponentInstance.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/addComponentInstance.tag new file mode 100644 index 0000000..a82901a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/addComponentInstance.tag @@ -0,0 +1,147 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="used by genericcomponentpage.jsp and by implementations.jsp to create a component instance" pageEncoding="UTF-8"%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> +<%-- +function createResource(nameOfResource, fields, url, onSuccess) cannot be used as this method is more diverse +--%> + +<%@attribute name="label" required="true" description="The lable to display"%> + +<%@attribute name="URL" description=""%> +<%@attribute name="onSuccess" description=""%> +<%@attribute name="type" description="added to dataToSend when doing a POST"%> +<%@attribute name="typeSelectorData" type="java.util.Collection" description="All available types when creating a template. We do not support types with names (additional to the id) as the current TOSCA specification does not foresee the usage of both name and id at types"%> +<%@attribute name="openinnewwindow" description="if true, the editor for the created component instance is openend in a new window"%> + +<div class="modal fade" id="addComponentInstanceDiag"> +<div class="modal-dialog"> +<div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add ${label}</h4> + </div> + <div class="modal-body" style="overflow-y: inherit;"> + <form id="addComponentInstanceForm" enctype="multipart/form-data"> + <%-- we send namespace + name to server. There, the ID is generated out of the name --%> + <fieldset> + <div class="form-group"> + <label for="nameOfNewCI" class="control-label">Name</label> + <input class="form-control" name="name" id="nameOfNewCI" type="text" required="required" /> + </div> + + <t:namespaceChooser idOfInput="namespace" allNamespaces="${w:allNamespaces()}"></t:namespaceChooser> + + <%-- (optional) the type, for instance at an artifact template or node type implementation --%> + <c:choose> + <%-- Either directly given ... --%> + <c:when test="${not empty type}"> + <%-- then, we just submit it together with the other data --%> + <input id="ciType" type="hidden" class="form-control" name="type" value="${type}"/> + </c:when> + <%-- ... or a list is given given. --%> + <%-- This is somewhat ugly as the UI displays no type dialog if no types are existing, but a template is to be created. + We consider that as special case and do not add code to work around that issue. + A good solution is to present an error dialog to the user if he hits that case: + A hint should be presented to state that the user has to add a type first. --%> + <c:when test="${empty type and not empty typeSelectorData}"> + <div class="form-group"> + <label for="ciType" class="control-label">Type</label> + <%-- similar code to artifacts.jsp.openLink${name}ArtifactDiag().ajax.success --%> + <select id="ciType" name="type" class="form-control"> + <c:forEach var="typeId" items="${typeSelectorData}"> + <option value="${typeId.QName}">${typeId.xmlId.decoded}</option> + </c:forEach> + </select> + </div> + </c:when> + </c:choose> + + </fieldset> + + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" onclick="addComponentInstance();">Add</button> + </div> +</div> +</div> +</div> + +<script> +<c:if test="${empty type and not empty typeSelectorData}"> +$("#ciType").select2(); +</c:if> + +$("#addComponentInstanceDiag").on("shown.bs.modal", function() { + $("#nameOfNewCI").focus(); +}); + +function addComponentInstance() { + if (highlightRequiredFields()) { + vShowError("Please fill in all required fields"); + return; + } + + var namespace = $("#namespace").val(); + require(["URIjs/URI"], function(URI) { + if (!URI(namespace).is("absolute")) { + vShowError("Please enter a valid namespace"); + return; + } + + var dataToSend = $('#addComponentInstanceForm').serialize(); + $.ajax({ + type: "POST", + async: false, + "data": dataToSend, + <c:if test="${not empty URL}">"url": "${URL}",</c:if> + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add ${label}", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + <c:if test="${not empty onSuccess}"> + ${onSuccess} + </c:if> + + //if we want to add the new entry directly in the list, we have to start with following: + //var name = $('#nameOfNewCI').val(); + //var namespace = $('#namespaceOfNewCI').val(); + + //otherwise: directly open edito + $('#addComponentInstanceDiag').modal('hide'); + // open editor for newly created component (assumption: window.location ends with "/") + var loc = jqXHR.getResponseHeader('Location'); + <c:choose> + <c:when test="${openinnewwindow}"> + window.open(loc, "_blank"); + </c:when> + <c:otherwise> + window.location = loc; + </c:otherwise> + </c:choose> + } + }); + }); +} + +function openNewCIdiag() { + $('#addComponentInstanceDiag').modal('show'); +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/colorwheel.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/colorwheel.tag new file mode 100644 index 0000000..1b7fede --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/colorwheel.tag @@ -0,0 +1,36 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="displays a color wheel" pageEncoding="UTF-8"%> + +<%@attribute name="id" required="true" description="id of the div to initialize"%> +<%@attribute name="url" required="true" description="URL to put to"%> +<%@attribute name="color" required="true" description="the initial color"%> +<%@attribute name="label" required="true" description="the label"%> + +<div id="${id}" class="form-group" style="height:175px;"> + <label for="${id}Div">${label}</label> + <div id="${id}Div" style="width:100%"> + <div class="colorwheel" style="float:left; margin-right:20px; width:300px; text-align:left;"></div> + <div style="float:left; width:50%"> + <input id="${id}Input" name="input_example" value="${color}" size="7" style="background-color: ${color}"> + <p class="text-info">Enter the hex value above</p> + <button type="button" class="btn btn-default btn-primary btn-sm" onclick="putColor('${url}', $('#${id}Input').val());">Save</button> + </div> + </div> +</div> + +<script> + var cw = Raphael.colorwheel($("#${id} div.colorwheel")[0],150); + cw.input($("#${id} input")[0]); +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstance.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstance.tag new file mode 100644 index 0000000..c5c2b4f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstance.tag @@ -0,0 +1,163 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013, 2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Wrapper for resources, which are backed by definitions and thus offer an XML div" pageEncoding="UTF-8"%> + +<%-- + quick hack to avoid specifying windowtitle at elements having it.name, too. + TODO: check why in this class a check on it.name is done, although there is componentinstancewithname.tag +--%> +<%@attribute name="windowtitle" description="If it.name is not available, this parameter should be given"%> + +<%@attribute name="selected" required="true"%> + +<%@attribute name="cssClass" required="true"%> + +<%@attribute name="image" required="false"%> + +<%@attribute name="libs" fragment="true" %> + +<%@attribute name="subMenus" required="false" type="java.util.List" description="list of SubMenuData objects stating the content of the submenus. The first submenu is used as default page. Subpage #xml must not be included, it is added automatically."%> + +<%@attribute name="implementationFor" description="In case the component instance is an implementation for another type, the link (a href) to the type is put here"%> + +<%@attribute name="type" description="In case the component instance is a template, the link (a href) to the type is put here"%> + +<%@attribute name="twolines" required="false" description="if set, two lines are required for the tabs"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<c:if test="${empty windowtitle}"> + <c:set var="windowtitle" value="${it.name}" /> +</c:if> + +<t:genericpage windowtitle="${windowtitle}" selected="${selected}" cssClass="mainContentContainer ${cssClass}" libs="${libs}"> + + <div class="top<c:if test="${not empty twolines}"> twolines</c:if>"> + <c:if test="${not empty image}"> + <img src='visualappearance/50x50' style='position: absolute; margin-top: 32px; margin-left: 27px; height: 40px; width: 40px;' /> + </c:if> + + <%-- Quick hack to enable usage of this tag at adminresource --%> + <c:catch var="exception"><c:if test="${empty it.name}"></c:if></c:catch> + <c:if test="${empty exception}"> + <%@ include file="/jsp/componentnaming.jspf" %> + <div style="float:right; margin-right:29px; margin-top: -20px; position:relative;"> + <div style="float:right;"> + <button type="button" class="btn btn-danger" onclick="deleteResource('${it.name}', '.', openOverviewPage)">Delete</button> + <a href="?definitions" class="btn btn-info">XML</a> + <a href="?csar" class="btn btn-info">CSAR</a> + <c:if test="${w:isContainerLocallyAvailable()}"> + <button id="deployBtn" type="button" onclick="deployOnOpenTOSCAContainer()" class="btn btn-info" data-loading-text="Deploying...">Deploy</button> + </c:if> + </div> + <c:if test="${not empty implementationFor}"> + <div style="clear:both; float:right;"> + Implementation for ${implementationFor} + </div> + </c:if> + <c:if test="${not empty type}"> + <div style="clear:both; float:right;"> + Type ${type} + </div> + </c:if> + </div> + </c:if> + <div class="subMenu"> + <c:if test="${not empty subMenus}"> + <c:forEach items="${subMenus}" var="subMenu" varStatus="status"> + <t:submenu selected="${status.first}" subMenuData="${subMenu}"> + </t:submenu> + </c:forEach> + </c:if> + + <%-- Quick hack to enable usage of this tag at adminresource --%> + <c:if test="${empty exception}"> + <t:submenu subMenuData="<%=org.eclipse.winery.repository.resources.SubMenuData.SUBMENU_DOCUMENTATION%>" selected="${empty subMenus}"> + </t:submenu> + <t:submenu subMenuData="<%=org.eclipse.winery.repository.resources.SubMenuData.SUBMENU_XML%>" selected="${empty subMenus}"> + </t:submenu> + </c:if> + </div> + </div> + + <div class="middle" id="ccontainer"> + </div> + + <c:if test="${empty subMenus}"> + <jsp:include page="/jsp/hashloading.jsp"> + <jsp:param name="validpages" value="['#documentation', '#xml']" /> + <jsp:param name="defaultpage" value="#documentation" /> + </jsp:include> + </c:if> + <c:if test="${not empty subMenus}"> + <c:forEach items="${subMenus}" var="subMenu" varStatus="status"> + <c:if test="${status.first}"> + <c:set var="defaultpage" value="${subMenu.href}"></c:set> + <c:set var="additionalHashes" value="'${subMenu.href}'"></c:set> + </c:if> + <c:if test="${not status.first}"> + <c:set var="additionalHashes" value="${additionalHashes}, '${subMenu.href}'"></c:set> + </c:if> + </c:forEach> + + <jsp:include page="/jsp/hashloading.jsp"> + <jsp:param name="validpages" value="[${additionalHashes}, '#documentation', '#xml']" /> + <jsp:param name="defaultpage" value="${defaultpage}" /> + </jsp:include> + </c:if> + + <div class="bottom"> + </div> + +<script> +function openOverviewPage() { + window.location="../../"; +} + +function deployOnOpenTOSCAContainer() { + $("#deployBtn").button('loading'); + + urlToUpload = window.location.href; + var hash = window.location.hash; + if (hash != "") { + urlToUpload = urlToUpload.substr(0, urlToUpload.length - hash.length) + } + var search = window.location.search; + if (search != "") { + urlToUpload = urlToUpload.substr(0, urlToUpload.length - search.length) + } + + urlToUpload = urlToUpload + "?csar"; + + var data = { + urlToUpload: urlToUpload + } + + // we assume the container runs at the same host and port + $.ajax({ + url: "/admin/uploadCSARFromURL.action", + data: data + }).always(function () { + $("#deployBtn").button('reset'); + }).fail(function (jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not trigger CSAR deployment at OpenTOSCA container", jqXHR, errorThrown); + }).done(function (result) { + vShowSuccess("Successfully triggered CSAR deployment at OpenTOSCA container"); + }); +} +</script> + +</t:genericpage> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstancewithName.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstancewithName.tag new file mode 100644 index 0000000..f970b99 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstancewithName.tag @@ -0,0 +1,33 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag import="org.eclipse.winery.repository.resources.SubMenuData"%> +<%@tag description="Wrapper for component instances with a name. Name is also used for window title." pageEncoding="UTF-8"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@tag import="java.util.ArrayList"%> + +<!-- for the header --> +<%@attribute name="selected" required="true"%> +<%@attribute name="cssClass" required="true"%> +<%@attribute name="image" required="false"%> +<%@attribute name="libs" fragment="true" %> +<%@attribute name="implementationFor" %> +<%@attribute name="twolines" required="false" description="if set, two lines are required for the tabs"%> +<%@attribute name="type" description="In case the component instance is a template, the link (a href) to the type is put here"%> + +<%@attribute name="subMenus" required="false" type="java.util.List" %> + +<t:componentinstance cssClass="${cssClass}" selected="${selected}" subMenus="<%=subMenus%>" image="${image}" libs="${libs}" implementationFor="${implementationFor}" twolines="${twolines}" type="${type}"> +</t:componentinstance> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstancewithNameDerivedFromAbstractFinal.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstancewithNameDerivedFromAbstractFinal.tag new file mode 100644 index 0000000..a8ea212 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/componentinstancewithNameDerivedFromAbstractFinal.tag @@ -0,0 +1,45 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag import="org.eclipse.winery.repository.resources.SubMenuData"%> +<%@tag description="Wrapper for component instances with name, derived from, abstract, final (equivalent to AbstractComponentInstanceWithName..." pageEncoding="UTF-8"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@tag import="java.util.ArrayList"%> + +<!-- for the header --> +<%@attribute name="selected" required="true"%> +<%@attribute name="cssClass" required="true"%> +<%@attribute name="image" required="false"%> +<%@attribute name="libs" fragment="true" %> +<%@attribute name="implementationFor" %> +<%@attribute name="twolines" required="false" description="if set, two lines are required for the tabs"%> + +<%@attribute name="subMenus" required="false" type="java.util.List" description="list of SubMenuData objects stating the content of the submenus. The first submenu is used as default page. Subpage #xml must not be included, it is added automatically."%> + +<!-- add submenus after the submenus defined for the type --> +<% + +if (subMenus == null) { + subMenus = new ArrayList(1); +} + +SubMenuData data; + +data = new SubMenuData("#inheritance", "Inheritance"); +subMenus.add(data); +%> + +<t:componentinstancewithName cssClass="${cssClass}" selected="${selected}" subMenus="<%=subMenus%>" image="${image}" libs="${libs}" implementationFor="${implementationFor}" twolines="${twolines}"> +</t:componentinstancewithName> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/constraints/constraint.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/constraints/constraint.tag new file mode 100644 index 0000000..30607b6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/constraints/constraint.tag @@ -0,0 +1,83 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Models editing a single constraint" pageEncoding="UTF-8"%> + +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags"%> + + +<div class="modal fade" id="constraint-dialog"> + <div class="modal-dialog"> + <div class="modal-content" style="width:660px;"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Edit Constraint</h4> + </div> + <div class="modal-body"> + + <form> + <fieldset> + <t:typeswithshortnameasselect label="Type" type="constrainttype" selectname="typenameinput" typesWithShortNames="<%=org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager.INSTANCE.getTypes()%>"> + </t:typeswithshortnameasselect> + + <o:orioneditorarea areaid="constrainttextarea" /> + </fieldset> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <%-- click functionality is set by editConstraint() --%> + <button type="button" class="btn btn-primary" id="createConstraintBtn">Create</button> + <button type="button" class="btn btn-primary" id="updateConstraintBtn">Update</button> + </div> + </div> + </div> +</div> + +<%-- +Quick hack to get the representation of an empty constraint +TODO: A resource should provide the empty representation (?!) + +The alternative is not to use the complete XML as the specification only allows the content of the XML wrapper to be modified. +If we use that method, this textarea is not required, but the sending of an existing constraint has to be modified to send only lines 2 to n-1, i.e., send without the wrapping lines. +This is not possible if the stored constraint is empty, then there are 2 lines only. +--%> +<textarea class="hidden" id="emptyconstraint"> +<%=org.eclipse.winery.repository.Utils.getXMLAsString(new org.eclipse.winery.model.tosca.TConstraint())%> +</textarea> + +<script> +/** + * Shows an error if XML is invalid, calls onSuccess otherwise + * + * @param onSuccess Function called with XML String containging the constraint + */ +function getXMLOfConstraint(onSuccess) { + // we have to weave in the type into the XML + // The editor presents the complete XML as this is easier to implement + // in comparison to select lines 3 to n-1 of the XML and then create a TConstraints element + + require(["winery-support-common"], function(wsc) { + var txt = window.winery.orionareas["constrainttextarea"].editor.getText(); + var xmlDoc = wsc.checkXMLValidityAndShowErrorIfInvalid(txt); + + var type = document.createAttribute('constraintType'); + type.nodeValue = $("#typenameinput").val(); + xmlDoc.documentElement.attributes.setNamedItem(type); + xmlString = (new XMLSerializer()).serializeToString(xmlDoc); + + onSuccess(xmlString); + }); +} +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytemplate.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytemplate.tag new file mode 100644 index 0000000..781e2d8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytemplate.tag @@ -0,0 +1,43 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Wrapper for instances of entity types" pageEncoding="UTF-8"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@tag import="java.util.ArrayList"%> +<%@tag import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<!-- for the header --> +<%@attribute name="selected" required="true"%> +<%@attribute name="cssClass" required="true"%> +<%@attribute name="image" required="false"%> +<%@attribute name="libs" fragment="true" %> + +<%@attribute name="subMenus" required="false" type="java.util.List" description="list of SubMenuData objects stating the content of the submenus. The first submenu is used as default page. Subpage #xml must not be included, it is added automatically."%> + +<!-- add submenus after the submenus defined for the type--> +<% + +if (subMenus == null) { + subMenus = new ArrayList<SubMenuData>(2); +} + +SubMenuData data; + +data = new SubMenuData("#properties", "Properties"); +subMenus.add(data); +%> + +<t:componentinstancewithName cssClass="${cssClass}" selected="${selected}" subMenus="<%=subMenus%>" image="${image}" libs="${libs}"> +</t:componentinstancewithName> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytype.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytype.tag new file mode 100644 index 0000000..6bd1d3d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytype.tag @@ -0,0 +1,49 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Wrapper for instances of entity types" pageEncoding="UTF-8"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@tag import="java.util.ArrayList"%> +<%@tag import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<!-- for the header --> +<%@attribute name="selected" required="true"%> +<%@attribute name="cssClass" required="true"%> +<%@attribute name="image" required="false"%> +<%@attribute name="twolines" required="false" description="if set, two lines are required for the tabs"%> +<%@attribute name="libs" fragment="true" %> + +<%@attribute name="subMenus" required="false" type="java.util.List" description="list of SubMenuData objects stating the content of the submenus. The first submenu is used as default page. Subpage #xml must not be included, it is added automatically."%> + +<!-- add submenus after the submenus defined for the type--> +<% + +if (subMenus == null) { + subMenus = new ArrayList<SubMenuData>(2); +} + +SubMenuData data; + +data = new SubMenuData("#propertiesdefinition", "Properties Definition"); +subMenus.add(data); + +// Tags are currently not implemented -> Don't confuse users by showing the tab +// has to be enabled again, when tags are implemented +//data = new SubMenuData("#tags", "Tags"); +//subMenus.add(data); +%> + +<t:componentinstancewithNameDerivedFromAbstractFinal cssClass="${cssClass}" selected="${selected}" subMenus="<%=subMenus%>" image="${image}" libs="${libs}" twolines="${twolines}"> +</t:componentinstancewithNameDerivedFromAbstractFinal> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytypes/nodetypes/reqandcapdefs/reqandcapdefs.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytypes/nodetypes/reqandcapdefs/reqandcapdefs.tag new file mode 100644 index 0000000..3748bd6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/entitytypes/nodetypes/reqandcapdefs/reqandcapdefs.tag @@ -0,0 +1,334 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3, integration with spinnerwithinphty + *******************************************************************************/ +--%> +<%@tag description="Models Requirement and Capability Definitions" pageEncoding="UTF-8"%> + +<%@attribute name="labelForSingleItem" required="true" %> +<%@attribute name="url" required="true"%> +<%@attribute name="allSubResources" required="true" type="java.util.List" description="All available req-/cap-defs" %> +<%@attribute name="allTypes" required="true" type="java.util.Collection" description="All available types of req-/cap-def" %> +<%@attribute name="typeClass" required="true" type="java.lang.Class" description="The class of the type" %> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> +<%@taglib prefix="con" tagdir="/WEB-INF/tags/constraints" %> +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> + +<button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOnServerAndInTable(reqCapTableInfo, '${labelForSingleItem}', '${url}');">Remove</button> +<button class="rightbutton btn btn-primary btn-xs" type="button" onclick="$('#addReqOrCapDefDiag').modal('show');">Add</button> + +<div class="modal fade" id="addReqOrCapDefDiag"> +<div class="modal-dialog"> +<div class="modal-content" style="width:660px;"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add ${labelForSingleItem}</h4> + </div> + <div class="modal-body"> + <form id="addReqOrCapDefForm" enctype="multipart/form-data"><fieldset> + <div class="form-group"> + <label for="reqorcapname">Name</label> + <input class="form-control" name="name" id="reqorcapname" type="text" required="required" /> + </div> + <ct:QNameChooser allQNames="${allTypes}" idOfSelectField="type" labelOfSelectField="Type" /> + <ct:spinnerwithinphty label="Lower Bound" id="lowerbound" min="0" value="1" /> + <ct:spinnerwithinphty label="Upper Bound" id="upperbound" min="1" value="1" withinphty="true" /> + </fieldset></form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" onclick="createReqOrCapDef();">Add</button> + </div> +</div> +</div> +</div> + +<table id="reqorcapdefs"> + +<thead> + <tr> + <th>name</th> + <th>type</th> + <th>lower bound</th> + <th>upper bound</th> + <th>constraints</th> + </tr> +</thead> + +<tbody> + +<c:forEach var="r" items="${allSubResources}"> + <tr> + <td>${r.def.name}</td> + <td>${wc:qname2href(pageContext.request.contextPath, typeClass, r.type)}</td> + <td>${w:renderMinInstances(r.def.lowerBound)}</td> + <td>${w:renderMaxInstances(r.def.upperBound)}</td> + <td><button class="btn btn-xs" onclick="editConstraints('${r.def.name}');">Constraints...</button></td> + </tr> +</c:forEach> + +</tbody> + +</table> + +<%-- Editing a set of constraints --%> + +<div class="modal fade" id="constraints-dialog"> +<div class="modal-dialog"> +<div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Constraints</h4> + </div> + <div class="modal-body"> + <div id="noconstraintsexisting" style="display:none;">No constraints defined</div> + <ol id="constraintlist" style="display:none;"> + </ol> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" onclick="editConstraint();">Add new</button> + </div> +</div> +</div> +</div> + +<script> +function deleteConstraint(id) { + $.ajax({ + url: "${url}" + currentReqCapName + "/constraints/" + id, + method: "DELETE", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not delete constraint", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + $("#"+id).remove(); + + // quick hack + var constraintListIsEmpty = $("#constraintlist").children().length == 0; + if (constraintListIsEmpty) { + // last item was removed -> show empty message + $("#noconstraintsexisting").show(); + $("#constraintlist").hide(); + } + } + }); +} + +function getLiForConstraint(id) { + return '<li id="' + id + '"><span onclick="editConstraint(\'' + id + '\');">constraint</span> <button class="btn btn-danger btn-xs" style="margin-left:10px;" onclick="deleteConstraint(\'' + id + '\')">Delete</button></li>'; +} +/** + * @param id the id of the constraint + */ +function addConstraintToList(id) { + var constraintList = $("#constraintlist"); + + var li = getLiForConstraint(id); + constraintList.append(li); + + // ensure that "no constraints existing" is hidden and the list is shown + $("#noconstraintsexisting").hide(); + constraintList.show(); +} + +var currentReqCapName; + +function editConstraints(reqCapName) { + currentReqCapName = reqCapName; + $.ajax({ + url: "${url}" + currentReqCapName + "/constraints/", + dataType: "json", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch constraints data", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + if (data.length == 0) { + $("#noconstraintsexisting").show(); + $("#constraintlist").hide(); + } else { + $("#noconstraintsexisting").hide(); + var constraintList = $("#constraintlist"); + constraintList.empty(); + $(data).each(function(i,id) { + addConstraintToList(id); + }); + $("#constraintlist").show(); + }; + $("#constraints-dialog").modal("show"); + } + }); +} +</script> + + +<%-- Editing a single constraint --%> + +<con:constraint /> + +<script> +var currentConstraintId; + +/** + * @param constraintId (optional) If not given, enable editing of a newly created constraint + */ +function editConstraint(constraintId) { + currentConstraintId = constraintId; + + // Adjust Create/Update button + if (currentConstraintId === undefined) { + $("#createConstraintBtn").show(); + $("#updateConstraintBtn").hide(); + + $("#createConstraintBtn").off("click"); + $("#createConstraintBtn").on("click", function() { + getXMLOfConstraint(function(xmlString) { + $.ajax({ + type: "POST", + url: "${url}" + currentReqCapName + "/constraints/", + contentType: "text/xml", + async: true, + data: xmlString, + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add constraint", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + addConstraintToList(resData); + $("#constraint-dialog").modal("hide"); + } + }); + }); + }); + } else { + // updating an existing constraint + $("#createConstraintBtn").hide(); + $("#updateConstraintBtn").show(); + + $("#updateConstraintBtn").off("click"); + $("#updateConstraintBtn").on("click", function() { + getXMLOfConstraint(function(xmlString) { + $.ajax({ + type: "PUT", + url: "${url}" + currentReqCapName + "/constraints/" + currentConstraintId + "/", + contentType: "text/xml", + async: true, + data: xmlString, + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not update constraint", jqXHR, errorThrown); + }, + success: function(newId, textStatus, jqXHR) { + $("#constraint-dialog").modal("hide"); + var newLi = getLiForConstraint(newId); + var oldLi = $("#" + currentConstraintId); + oldLi.before(newLi); + oldLi.remove(); + } + }); + }); + }); + }; + + // fill textarea + if (currentConstraintId === undefined) { + $("#constraint-dialog").modal("show"); + // setting content only works if dialog is fully shown + window.setTimeout(function() { + window.winery.orionareas["constrainttextarea"].editor.setText($("#emptyconstraint").val()); + }, window.winery.BOOTSTRAP_ANIMATION_DURATION); + } else { + $.ajax({ + type: "GET", + url: "${url}" + currentReqCapName + "/constraints/" + currentConstraintId + "/", + dataType: "xml", + async: true, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could get constraint information", jqXHR, errorThrown); + }, + success: function(xmlData, textStatus, jqXHR) { + // xmlDoc contains an XML document and not just a string + // We let jQuery parse the XML as we need to parse the type attribute + + // *move* type information to input field + var type = xmlData.documentElement.getAttribute("constraintType"); + $("#typenameinput").val(type); + xmlData.documentElement.removeAttribute("constraintType"); + + $("#constraint-dialog").modal("show"); + + // the XML document cannot be put directly as content. It has to be converted to a String + // TODO: add nice formatting + var xmlString = (new XMLSerializer()).serializeToString(xmlData); + window.setTimeout(function() { + window.winery.orionareas["constrainttextarea"].editor.setText(xmlString); + }, window.winery.BOOTSTRAP_ANIMATION_DURATION); + } + }); + } +} +</script> + + +<script> +// TODO: this variable is available after switching tabs. +// One could cache this information without requiring reloading all the content +var reqCapTableInfo = { + id : '#reqorcapdefs' +}; + +require(["winery-support"], function(ws) { + ws.initTable(reqCapTableInfo); +}); + +function createReqOrCapDef() { + if (highlightRequiredFields()) { + vShowError("Please fill out all required fields."); + return; + } + + var data = $('#addReqOrCapDefForm').serialize(); + + // replace &inphty; by TOSCA's "unbounded" + data = data.replace("∞", "unbounded"); + // %E2%88%9E is the HTML encoding of &inphty; + data = data.replace("%E2%88%9E", "unbounded"); + + $.ajax({ + url: "${url}", + type: "POST", + async: false, + data: data, + error: function(jqXHR, textStatus, errorThrown) { + vShowError("Could not add ${labelForSingleItem}: " + errorThrown + "<br/>" + jqXHR.responseText); + }, + success: function(data, textStatus, jqXHR) { + // Data has been validated at the server + // We can just add the local data + var name = $('#reqorcapname').val(); + var type = $('#type').select2("data").text; // TODO: make href to be consistent with other lines + var lbound = $('#lowerbound').val(); + var ubound = $('#upperbound').val(); + var constraints = "<button class=\"btn btn-xs\" onclick=\"editConstraints('" + name + "');\">Constraints...</button>"; + var dataToAdd = [name, type, lbound, ubound, constraints]; + reqCapTableInfo.table.fnAddData(dataToAdd); + $('#addReqOrCapDefDiag').modal('hide'); + } + }); +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/genericpage.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/genericpage.tag new file mode 100644 index 0000000..7063697 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/genericpage.tag @@ -0,0 +1,349 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@tag description="Global Wrapper" pageEncoding="UTF-8"%><!DOCTYPE html> + +<%@attribute name="windowtitle" required="true" description="String to be used as window title"%> +<%@attribute name="selected" required="true"%> +<%@attribute name="cssClass" required="true"%> + +<%@attribute name="libs" fragment="true" %> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags"%> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<%@tag import="org.eclipse.winery.repository.Prefs" %> + +<!-- This is Winery ${project.version} --> + +<html> +<head> + <title>${windowtitle}</title> + <meta name="application-name" content="Winery" /> + <meta charset="UTF-8"> + <link rel="icon" href="${w:topologyModelerURI()}/favicon.png" type="image/png"> + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/bootstrap/dist/css/bootstrap.css" /> + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/bootstrap/dist/css/bootstrap-theme.css" /> + + <%-- CSS to style the file input field as button and adjust the Bootstrap progress bars --%> + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/blueimp-file-upload/css/jquery.fileupload.css" /> + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/blueimp-file-upload/css/jquery.fileupload-ui.css" /> + <link type="text/css" href="${pageContext.request.contextPath}/components/datatables/media/css/jquery.dataTables.css" rel="stylesheet" /> + <link type="text/css" href="${pageContext.request.contextPath}/css/winery-repository.css" rel="Stylesheet" /> + <link type="text/css" href="${pageContext.request.contextPath}/components/pnotify/jquery.pnotify.default.css" media="all" rel="stylesheet" /> + <link type="text/css" href="${pageContext.request.contextPath}/components/pnotify/jquery.pnotify.default.icons.css" media="all" rel="stylesheet" /> + <link type="text/css" href="${pageContext.request.contextPath}/components/select2/select2.css" media="all" rel="stylesheet" /> + <link type="text/css" href="${pageContext.request.contextPath}/components/select2/select2-bootstrap.css" media="all" rel="stylesheet" /> + + <link type="text/css" href="${pageContext.request.contextPath}/components/bootstrap3-wysihtml5-bower/dist/bootstrap3-wysihtml5.css" media="all" rel="stylesheet" /> + <link type="text/css" href="${pageContext.request.contextPath}/components/x-editable/dist/bootstrap3-editable/css/bootstrap-editable.css" media="all" rel="stylesheet" /> + + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/bootstrap-spinedit/css/bootstrap-spinedit.css" /> + + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/xmltree/xmltree.css" /> + + <link rel="stylesheet" type="text/css" href="http://eclipse.org/orion/editor/releases/6.0/built-editor.css"/> + + <link type="text/css" href="${w:topologyModelerURI()}/css/winery-common.css" rel="stylesheet" /> + + <script type='text/javascript' src='${pageContext.request.contextPath}/components/requirejs/require.js'></script> + <script> + require.config({ + baseUrl: "${pageContext.request.contextPath}/js", + paths: { + "artifacttemplateselection": "${w:topologyModelerURI()}/js/artifacttemplateselection", + "winery-sugiyamaLayouter": "${w:topologyModelerURI()}/js/winery-sugiyamaLayouter", + + "datatables": "../components/datatables/media/js/jquery.dataTables", + "jquery": "../components/jquery/jquery", + + "jquery.fileupload": "../components/blueimp-file-upload/js/jquery.fileupload", + "jquery.fileupload-ui": "../components/blueimp-file-upload/js/jquery.fileupload-ui", + "jquery.fileupload-process": "../components/blueimp-file-upload/js/jquery.fileupload-process", + "jquery.ui.widget": "../components/blueimp-file-upload/js/vendor/jquery.ui.widget", + + // required for jsplumb + "jquery.ui": "../3rdparty/jquery-ui/js/jquery-ui", + + "jsplumb": "../components/jsPlumb/dist/js/jquery.jsPlumb-1.5.4", + + "keyboardjs": "../components/KeyboardJS/keyboard", + + "orioneditor": "http://eclipse.org/orion/editor/releases/6.0/built-editor-amd", + + "pnotify": "../components/pnotify/jquery.pnotify", + + "select2": "../components/select2/select2", + + "tmpl": "../components/blueimp-tmpl/js/tmpl", + + "URIjs": '../components/uri.js/src', + + "xmltree": "../components/xmltree/xmltree", + + "XMLWriter": "../components/XMLWriter/XMLWriter" + } + }); + </script> + + <script type='text/javascript' src='${pageContext.request.contextPath}/components/jquery/jquery.js'></script> + <script type='text/javascript' src='${pageContext.request.contextPath}/components/bootstrap/dist/js/bootstrap.js'></script> + + <script type="text/javascript" src="${pageContext.request.contextPath}/components/jquery-typing/plugin/jquery.typing-0.3.2.js"></script> + <script type="text/javascript" src="${pageContext.request.contextPath}/components/select2/select2.js"></script> + + <script type="text/javascript" src="${pageContext.request.contextPath}/components/wysihtml5/dist/wysihtml5-0.3.0.js"></script> + <script type="text/javascript" src="${pageContext.request.contextPath}/components/handlebars/handlebars.min.js"></script> + <script type="text/javascript" src="${pageContext.request.contextPath}/components/bootstrap3-wysihtml5-bower/dist/bootstrap3-wysihtml5.min.js"></script> + <script type="text/javascript" src="${pageContext.request.contextPath}/components/x-editable/dist/bootstrap3-editable/js/bootstrap-editable.js"></script> + <script type="text/javascript" src="${pageContext.request.contextPath}/components/x-editable/dist/inputs-ext/wysihtml5/wysihtml5.js"></script> + + <script type='text/javascript' src='${pageContext.request.contextPath}/components/bootstrap-spinedit/js/bootstrap-spinedit.js'></script> + <script type="text/javascript" src="${pageContext.request.contextPath}/js/winery-support-non-AMD.js"></script> + <script type="text/javascript" src="${w:topologyModelerURI()}/js/winery-common.js"></script> + + <script> + // all x-editable popups should be placed in a way to fit "perfectly" on the screen + $.fn.editable.defaults.placement = "auto"; + + //configuration for pnotify + require(["jquery", "pnotify"], function() { + $.pnotify.defaults.styling = "bootstrap3"; + }); + </script> +</head> + +<body> + +<jsp:include page="/jsp/shared/dialogs.jsp" /> + +<script> +//enable caching. This disables appending of "?_=xy" at requests +jQuery.ajaxSetup({cache:true}); + +// prevent form submission on pressing "enter" +// In the topology modeler, this phenomen does not occurr. +// The reason why all forms are submitted on enter pressing is unknown. +$(document).on("keypress", "input", function(e) { + var key = (e.keyCode || e.which); + if (key == 13) { + // enter pressed + // press tab instead + // The following does not work + // TODO: include jQuery.tabbable plugin (http://stackoverflow.com/a/18740738/873282 / https://github.com/marklagendijk/jQuery.tabbable) + $(e.currentTarget).trigger({ + type: 'keydown', + which: 9 + }); + return false; + } +}); + +$(function() { + var scrolling = $(document).height() > $(window).height(); + if (scrolling) { + // add CSS fix to prevent flickering + $("#mainContainer").addClass("overflown"); + } else { + $("#mainContainer").addClass("notoverflown"); + } +}); +</script> + +<t:about /> + +<div id="mainContainer"> + <div id="header"> + <div id="showabout"> + <button type="button" class="btn btn-default btn-xs" onClick="showAbout();">about</button> + </div> + <c:set var="warning" value="<%=Prefs.INSTANCE.getProperties().get(\"warning\")%>" /> + <c:if test="${not empty warning}"> + <div id="warning"> + ${warning} + </div> + </c:if> + + <div id="mainMenuContainer"> + + <%-- String values come from ComponentKind.toString() --%> + + <a class="styledTabMenuButton <c:if test="${selected eq 'ServiceTemplate'}">selected</c:if>" href="${pageContext.request.contextPath}/servicetemplates/"> + <div class="left"></div> + <div class="center">Service Templates</div> + <div class="right"></div> + </a> + + <%-- TopologyTemplates: top level topology templates only in "pro" mode <a href="${pageContext.request.contextPath}/topologytemplates/">Topology Templates</a> --%><%! %> + + <a class="styledTabMenuButton <c:if test="${selected eq 'NodeType'}">selected</c:if>" href="${pageContext.request.contextPath}/nodetypes/"> + <div class="left"></div> + <div class="center">Node Types</div> + <div class="right"></div> + </a> + + <a class="styledTabMenuButton <c:if test="${selected eq 'RelationshipType'}">selected</c:if>" href="${pageContext.request.contextPath}/relationshiptypes/"> + <div class="left"></div> + <div class="center">Relationship Types</div> + <div class="right"></div> + </a> + + + <%-- include all other TOSCA Elements into admin --%> + <%-- We need to call it "Elements" instead of "components" as PRD01 on line 334 calls these "elements" --%> + + <c:choose> + + <c:when test="${selected eq 'ArtifactTemplate'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Artifact Templates" /> + </c:when> + + <c:when test="${selected eq 'ArtifactType'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Artifact Types" /> + </c:when> + + <c:when test="${selected eq 'CapabilityType'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Capability Types" /> + </c:when> + + <c:when test="${selected eq 'NodeTypeImplementation'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Node Type Implementations" /> + </c:when> + + <c:when test="${selected eq 'PolicyTemplate'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Policy Templates" /> + </c:when> + + <c:when test="${selected eq 'PolicyType'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Policy Types" /> + </c:when> + + <c:when test="${selected eq 'RelationshipTypeImplementation'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Relationship Type Implementations" /> + </c:when> + + <c:when test="${selected eq 'RequirementType'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Requirement Types" /> + </c:when> + + <c:when test="${selected eq 'XSDImport'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements: Imports: XSD" /> + </c:when> + + + <c:when test="${selected eq 'OtherElements'}"> + <c:set var="otherSelected" value="selected" /> + <c:set var="otherLabel" value="Other Elements" /> + </c:when> + + + <c:otherwise> + <c:set var="otherSelected" value="" /> + <c:set var="otherLabel" value="Other Elements" /> + </c:otherwise> + + </c:choose> + + <a class="styledTabMenuButton ${otherSelected}" href="${pageContext.request.contextPath}/other/"> + <div class="left"></div> + <div class="center">${otherLabel}</div> + <div class="right"></div> + </a> + + <a class="styledTabMenuButton <c:if test="${selected eq 'admin'}">selected</c:if>" href="${pageContext.request.contextPath}/admin/"> + <div class="left"></div> + <div class="center">Administration</div> + <div class="right"></div> + </a> + + </div> + </div> + +<script id="template-createresource" type="text/x-tmpl"> +<div class="modal fade" id="createResource"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">{%=o.nameOfResource%}</h4> + </div> + <div class="modal-body"> + <form id="createResourceForm" enctype="multipart/form-data"> + <fieldset> + {% for (var i=0, field; field=o.fields[i]; i++) { %} + {% + if (field.type === undefined) { + field.type = "text"; + } + if (field.type == 'checkbox' || field.type == 'radio') { + %} + <div class="form-group"> + <label> + <input + style="margin: 0 5px;" + name="{%=field.name%}" + type="{%=field.type%}" + required="required" + {% if (field.checked) { %}checked="checked"{% } %} + autocomplete="off"> + {%=field.label%} + </label> + {% } else { %} + <div class="form-group"> + <label for="addedtypeinput">{%=field.label%}</label> + <input id="addedtypeinput" class="form-control" name="{%=field.name%}" type="{%=field.type%}" required="required" autocomplete="off" /> + {% } %} + {% if (field.hint) { %} + <span class="help-block">{%=field.hint%}</span> + {% } %} + </div> + {% } %} + </fieldset> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" data-dismiss="modal" onclick="addResourceInstance();">Add</button> + </div> + </div> + </div> +</div> +</script> + +<div id="mainContent"> + + +<jsp:invoke fragment="libs"></jsp:invoke> + +<div class="${cssClass}"> +<jsp:doBody/> +</div> + +</div> +</div> + +</body> +</html> + diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/imageUpload.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/imageUpload.tag new file mode 100644 index 0000000..6ef5d18 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/imageUpload.tag @@ -0,0 +1,42 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="form div to upload an icon" pageEncoding="UTF-8"%> + +<%@attribute name="label" required="true" description="LAbel to be used. Also used as title of the dialog"%> +<%@attribute name="URL" required="true" description="URL to post to"%> +<%@attribute name="id" required="true" description="id to form basis for ...Diag: id of diag; ...Form: id of input field used for file upload; ...Img: Image to refresh"%> +<%@attribute name="accept" description="if not null/'': list of accepted MIME file types"%> +<%@attribute name="width" required="true" description="Width of the image to display"%> +<%@attribute name="resize" description="if not null/'': enables image resizing. Currently not supported"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<t:simpleSingleFileUpload + title="Upload ${label}" + text="File" + additionalDropZone="#${id}FormGroup" + URL="${URL}" + type="PUT" + id="${id}" + accept="${accept}"/> + +<div id="${id}FormGroup" class="form-group"> + <label for="${id}DisplayDiv">${label}</label> + <div id="${id}DisplayDiv" style="width:100%"> + <div class="col-md-2"> + <a href="${URL}" target="_blank"><img id="${id}Img" style="width:${width};" src="${URL}" alt="n/a" /></a> + </div> + <button class="btn btn-default btn-xs" type="button" onClick="$('#${id}Diag').modal('show');">Upload...</button> or drop the image in this area. + </div> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/namespaceChooser.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/namespaceChooser.tag new file mode 100644 index 0000000..56b0712 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/namespaceChooser.tag @@ -0,0 +1,52 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="places a bootstrap form control to chooose a namespace. A new namespace can be created" pageEncoding="UTF-8"%> + +<!-- + This tag is shared at repository and topologytemplate. + Both versions differ from each other. + In the repository, ns.decoded is used. + In the topology modeler only "ns" is used: + In other words: The topology modeler passes a Collection<String>, whereas repository passes Collection<Namespace> + --> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%@attribute name="allNamespaces" required="true" type="java.util.Collection" description="All known namespaces"%> +<%@attribute name="idOfInput" required="true" description="The id if the input field storing the namespace. Also used as name"%> +<%@attribute name="nameOfInput" required="false" description="The name if the input field storing the namespace. If not provided, ifOfInput is used"%> +<%@attribute name="selected" description="The currently selected namespace (optional)"%> + +<c:if test="${empty nameOfInput}"><c:set var="nameOfInput" value="${idOfInput}"></c:set></c:if> + +<!-- createArtifactTemplate class is required for artifactcreationdialog --> +<div class="form-group createArtifactTemplate"> + <label for="${idOfInput}" class="control-label">Namespace</label> + <input type="hidden" class="form-control" name="${nameOfInput}" id="${idOfInput}"></input> +</div> + +<script> +// we have to use data as select2 does not allow "createSearchChoice" when using <select> as underlying html element +$("#${idOfInput}").select2({ + createSearchChoice: function(term) { + // enables creation of new namespaces + return {id:term, text:term}; + }, + data:[ + <c:forEach var="ns" items="${allNamespaces}" varStatus="loop"> + {id:"${ns.decoded}",text:"${ns.decoded}"}<c:if test="${!loop.last}">,</c:if> + </c:forEach> + ] +}).select2("val", "${selected}"); +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersHTML.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersHTML.tag new file mode 100644 index 0000000..7474851 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersHTML.tag @@ -0,0 +1,38 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Input or Output parameters" pageEncoding="UTF-8"%> + +<%@attribute name="label" required="true" %> +<%@attribute name="inOrOut" required="true" %> +<%@attribute name="tableId" required="true" %> +<%@attribute name="baseURL" required="true" description="JavaScript expression for determining the baseURL"%> + +<div class="row"> + <div class="row listheading"> + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="delete${inOrOut}putParameter(${baseURL});" id="remove${inOrOut}ParBtn">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="create${inOrOut}putParameter(${baseURL});" id="add${inOrOut}ParBtn">Add</button> + <label>${label}</label> + </div> + <table class="row" id="${tableId}"> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th>Required</th> + </tr> + </thead> + <tbody> + </tbody> + </table> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersInput.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersInput.tag new file mode 100644 index 0000000..73b8c1b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersInput.tag @@ -0,0 +1,20 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag pageEncoding="UTF-8"%> + +<%@attribute name="baseURL" required="true" description="JavaScript expression for determining the baseURL"%> + +<%@ taglib prefix="p" tagdir="/WEB-INF/tags/parameters" %> + +<p:parametersHTML label="Input Parameters" tableId="inputparameterstab" baseURL="${baseURL}" inOrOut="In"></p:parametersHTML> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersJS.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersJS.tag new file mode 100644 index 0000000..021c8c0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersJS.tag @@ -0,0 +1,177 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Input and Output parameters handling. Used at interface/operation and plan" pageEncoding="UTF-8"%> + +<%@attribute name="afterLoad" description="JavaScript code to be executed after successfully loading/initialization"%> + +<script> +var inputParametersTableInfo = { + id: '#inputparameterstab' +}; + +var outputParametersTableInfo = { + id: '#outputparameterstab' +}; + +$(function() { + // for options see http://datatables.net/usage/options#sDom + var opts = { + "sDom": '<"H"r>t<"F"ip>', + "iDisplayLength" : 3 + }; + + require(["winery-support"], function(ws) { + ws.initTable(inputParametersTableInfo, opts); + $(inputParametersTableInfo.id).click(function(event) { + if (inputParametersTableInfo.selectedRow) { + // something has been selected + $("#removeInParBtn").removeAttr("disabled"); + } else { + // row has been deselected + $("#removeInParBtn").attr("disabled", "disabled"); + } + }); + + ws.initTable(outputParametersTableInfo, opts, function() { + ${afterLoad} + }); + $(outputParametersTableInfo.id).click(function(event) { + if (outputParametersTableInfo.selectedRow) { + // something has been selected + $("#removeOutParBtn").removeAttr("disabled"); + } else { + // row has been deselected + $("#removeOutParBtn").attr("disabled", "disabled"); + } + }); + }); + +}); + +function afterInputParameterCreation(serializedArray, resData, textStatus, jqXHR) { + var required; + if (serializedArray.length == 2) { + required = "no"; + } else { + required = serializedArray[2].value; + } + addRowToParameterstable(inputParametersTableInfo, serializedArray[0].value, serializedArray[1].value, required); +} + +function afterOutputParameterCreation(serializedArray, resData, textStatus, jqXHR) { + var required; + if (serializedArray.length == 2) { + required = "no"; + } else { + required = serializedArray[2].value; + } + addRowToParameterstable(outputParametersTableInfo, serializedArray[0].value, serializedArray[1].value, required); +} + +function createInputParameter(baseURL) { + var url = baseURL + "inputparameters/"; + createResource('Input Parameter', [ + {'label': 'Name', 'name':'name'}, + { + label: 'Type', + name: 'type', + hint:'TOSCA v1.0 does not specify any type system here. The content of this field is a string. The concrete semantics is left open. The convension is to use the xsd prefix for XML Schema basic types.' + }, + {'label':'Required', 'name':'required', 'type': 'checkbox'} + ], + url, + afterInputParameterCreation); +} + +function createOutputParameter(baseURL) { + var url = baseURL + "outputparameters/"; + createResource('Output Parameter', [ + {'label': 'Name', 'name':'name'}, + { + label: 'Type', + name: 'type', + hint:'TOSCA v1.0 does not specify any type system here. The content of this field is a string. The concrete semantics is left open. The convension is to use the xsd prefix for XML Schema basic types.' + }, + {'label':'Required', 'name':'required', 'type': 'checkbox'} + ], + url, + afterOutputParameterCreation); +} + +function addRowToParameterstable(tableInfo, name, type, required) { + var checked; + required = required.toLowerCase(); + if ((required == "yes") || (required == "on")) { + checked = ' checked="checked"'; + } else { + checked = ""; + } + var checkbox = '<input type="checkbox"' + checked + ' disabled="disabled"></input>'; + var addData = [name, type, checkbox]; + tableInfo.table.fnAddData(addData); +} + +function deleteInputParameter() { + deleteOnServerAndInTable(inputParametersTableInfo, "Input Parameter", getOperationURL() + "inputparameters/"); +} + +function deleteOutputParameter() { + deleteOnServerAndInTable(outputParametersTableInfo, "Output Parameter", getOperationURL() + "outputparameters/"); +} + +/** + * only called if operation is selected + * + * @param url: the URL to query the parameters data + * @param inOrOut: "In"|"Out" + */ +function updateParameters(url, tableInfo, inOrOut) { + $.ajax({ + "url": url, + dataType: "json", + success: function(data) { + tableInfo.table.fnClearTable(); + $.each(data, function(number, item) { + var paramURL = url + item + "/"; + $.ajax({ + async: false, + dataType: "json", + url: paramURL, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch operation information", jqXHR, errorThrown); + }, + success: function(data) { + addRowToParameterstable(tableInfo, data.name, data.type, data.required); + } + }); + }); + $("#add" + inOrOut + "ParBtn").removeAttr("disabled"); + + // remove button should always be disalbed as it gets enabled only after clicking a row in the table + $("#remove" + inOrOut + "ParBtn").attr("disabled", "disabled"); + }, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch interface", jqXHR, errorThrown); + } + }); +} + +function updateInputAndOutputParameters(baseURL) { + var url = baseURL + "inputparameters/"; + updateParameters(url, inputParametersTableInfo, "In"); + url = baseURL + "outputparameters/"; + updateParameters(url, outputParametersTableInfo, "Out"); +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersOutput.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersOutput.tag new file mode 100644 index 0000000..32a5565 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/parameters/parametersOutput.tag @@ -0,0 +1,20 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag pageEncoding="UTF-8"%> + +<%@attribute name="baseURL" required="true" description="JavaScript expression for determining the baseURL"%> + +<%@ taglib prefix="p" tagdir="/WEB-INF/tags/parameters" %> + +<p:parametersHTML label="Output Parameters" tableId="outputparameterstab" baseURL="${baseURL}" inOrOut="Out"></p:parametersHTML> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/relationshiptype/validnodetypeendingsselect.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/relationshiptype/validnodetypeendingsselect.tag new file mode 100644 index 0000000..1e0702d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/relationshiptype/validnodetypeendingsselect.tag @@ -0,0 +1,43 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Offers choice for valid endings" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + +<%@attribute name="shortName" required="true" description="source|target"%> +<%@attribute name="currentSelection" required="false"%> +<%@attribute name="possibleValidEndings" type="java.util.Collection" %> + + +<select name="valid${shortName}" onchange="updateValue('valid${shortName}', this.options[this.selectedIndex].value);"> + <c:choose> + <c:when test="${empty currentSelection}"> + <option value="" selected="selected">(all)</option> + </c:when> + <c:otherwise> + <option value="">(all)</option> + </c:otherwise> + </c:choose> + <c:forEach var="typeId" items="${possibleValidEndings}"> + <c:choose> + <c:when test="${currentSelection eq typeId.QName}"> + <c:set var="selected" value=" selected=\"selected\"" /> + </c:when> + <c:otherwise> + <c:set var="selected" value="" /> + </c:otherwise> + </c:choose> + <option value="${typeId.QName}"${selected}>${typeId.xmlId.decoded} (${typeId.namespace.decoded})</option> + </c:forEach> +</select> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForReqOrCap.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForReqOrCap.tag new file mode 100644 index 0000000..5195f9b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForReqOrCap.tag @@ -0,0 +1,161 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@tag pageEncoding="UTF-8"%> + +<%@attribute name="label" description="Requirement|Capability" required="true" %> +<%@attribute name="requirementsOrCapabilities" description="requirements|capabilities" required="true" %> +<%@attribute name="reqOrCap" description="requirement|capability" required="true" %> + +<%@taglib prefix="b" tagdir="/WEB-INF/tags/servicetemplates/boundarydefinitions"%> + +<b:browseForX XShort="${reqOrCap}" XLong="${label}" /> + +<div class="modal fade" id="${reqOrCap}Diag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title"><span id="addOrUpdate${reqOrCap}Span"></span> ${label}</h4> + </div> + <div class="modal-body"> + <form> + <fieldset> + <div class="form-group"> + <label for="${reqOrCap}Name">Name</label> + <div> + <input name="${reqOrCap}Name" id="${reqOrCap}Name" class="form-control" type="text"> + </div> + </div> + <div class="form-group"> + <label for="${reqOrCap}RefDiv">${label}</label> + <div id="${reqOrCap}RefDiv" class="row"> + <div class="col-xs-10"> + <input id="X${reqOrCap}Ref" class="form-control" type="text"> <%-- The input id is prefixed with "X" as "requirementRef" alone does not work --%> + </div> + <div class="col-xs-2"> + <button type="button" class="btn btn-default btn-sm" onclick="browseFor${reqOrCap}($('#XReqRef'));">Browse</button> + </div> + </div> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button id="add${reqOrCap}" type="button" class="btn btn-primary" onclick="addorUpdate${reqOrCap}(false);">Add</button> + <button id="delete${reqOrCap}" type="button" class="btn btn-danger" onclick="delete${reqOrCap}t();">Delete</button> + <button id="update${reqOrCap}" type="button" class="btn btn-primary" onclick="addorUpdate${reqOrCap}(true);">Update</button> + </div> + </div> + </div> +</div> + + +<script> +/** + * Triggered by the browse button at requirements. In the dialog Add/Change Requirement + */ +function browseFor${reqOrCap}(field) { + $("#${reqOrCap}ReferenceField").val($("#X${reqOrCap}Ref").val()); + $("#browseFor${reqOrCap}Diag").modal("show"); +} + +/** + * Called by click on "Set" button at the browseForReqDiag + */ +function set${reqOrCap}Ref() { + $("#X${reqOrCap}Ref").val($("#${reqOrCap}ReferenceField").val()); + $("#browseFor${reqOrCap}Diag").modal("hide"); +} + +/** + * Called from the modal after the user clicks "Add" or "Delete" + */ +function addorUpdate${reqOrCap}(update) { + var data = { + name: $("#${reqOrCap}Name").val(), + ref: $("#X${reqOrCap}Ref").val() + } + + $.ajax({ + url: "boundarydefinitions/${requirementsOrCapabilities}/", + data: data, + type: "POST" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add ${label}", jqXHR, errorThrown); + }).done(function(id) { + // data is the new id + var tableRow = [id, data.name, data.ref]; + ${requirementsOrCapabilities}TableInfo.table.fnAddData(tableRow); + + if (update) { + // update is implemented as delete + recreate + // after successfull creation, we can delete + deleteOnServerAndInTable(${requirementsOrCapabilities}TableInfo, '${label}', 'boundarydefinitions/${requirementsOrCapabilities}/', undefined, undefined, undefined, true); + // TODO: we should hook into onSuccess/onError, but currently these are not exposed from deleteResource to deleteOnServerAndInTable + vShowSuccess("Successfully updated ${label}."); + } else { + vShowSuccess("Successfully added ${label}."); + } + + + $('#${reqOrCap}Diag').modal('hide'); + }); +}; + +function deleteRequirement() { + $('#${reqOrCap}Diag').modal('hide'); + $("#delete${reqOrCap}").click(); +} + +/** + * Called from the buttons in the table if the user clicks "Add" or "Edit" + */ +function open${reqOrCap}Editor(update) { + if (update) { + if (${requirementsOrCapabilities}TableInfo.selectedRow) { + require(["winery-support"], function(ws) { + if (ws.isEmptyTable(${requirementsOrCapabilities}TableInfo)) { + vShowError("No ${requirementsOrCapabilities} available"); + return; + } + + var data = ${requirementsOrCapabilities}TableInfo.table.fnGetData(${requirementsOrCapabilities}TableInfo.table.selectedRow); + // we don't require the id as deleteOnServerAndInTable automatically deletes the selectedRow + $("#${reqOrCap}Name").val(data[0][1]); + $("#X${reqOrCap}Ref").val(data[0][2]); + + $("#add${reqOrCap}").hide(); + $("#update${reqOrCap}").show(); + $("#delete${reqOrCap}").show(); + + $("#addOrUpdate${reqOrCap}Span").text("Change"); + $('#${reqOrCap}Diag').modal('show'); + }); + } else { + vShowError("No ${label} selected"); + } + } else { + // create a new req/cap + $("#add${reqOrCap}").show(); + $("#update${reqOrCap}").hide(); + $("#delete${reqOrCap}").hide(); + $("#addOrUpdate${reqOrCap}Span").text("Add"); + $('#${reqOrCap}Diag').modal('show'); + } +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForServiceTemplatePropertyReqOrCap.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForServiceTemplatePropertyReqOrCap.tag new file mode 100644 index 0000000..430d4db --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForServiceTemplatePropertyReqOrCap.tag @@ -0,0 +1,166 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@tag pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="bd" tagdir="/WEB-INF/tags/servicetemplates/boundarydefinitions" %> + +<%@attribute name="definedPropertiesAsJSONString" required="true" %> + +<div class="modal fade z1051" id="browseForServiceTemplatePropertyDiag" > + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Choose Property of Service Template</h4> + </div> + + <div class="modal-body"> + <p class="text-info">Please click on a node to select the element</p> + <div id='propertymappingstree'></div> + <form> + <fieldset> + <div class="form-group"> + <label for="newServiceTemplatePropertyRef">Reference to the property of the Service Template</label> + <input type="text" id="newServiceTemplatePropertyRef" class="form-control" /> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" onclick="setServiceTemplatePropertyRef();">Set</button> + </div> + </div> + </div> +</div> + +<%-- Browse for property --%> +<%-- +The following cannot be used as we return TWO things: the template and the property +<bd:browseForX XShort="Property" XLong="Node Template, Relationship Template, or directly a property" /> +--%> +<div class="modal fade z1051" id="browseForTemplateProperty"> + <div class="modal-dialog" style="width:1000px;"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Choose Node Template, Relationship Template, or directly a property</h4> + </div> + + <div class="modal-body"> + <p class="text-info">Please click on the desired element</p> + <iframe id="topologyTemplatePreview" class="topologyTemplatePreviewSizing" src="topologytemplate/?view=propertySelection&script=${pageContext.request.contextPath}/js/boundaryDefinitionsXSelection.js"></iframe> + <form> + <fieldset> + <div class="form-group"> + <label for="newObjectRef">Reference to the object in the topology template</label> + <input type="text" id="newObjectRef" class="form-control newObjectRef" /> <%-- newObjectRef required as --%> + </div> + <div class="form-group"> + <label for="newObjectPropertyRef">Reference to the object's property</label> + <input type="text" id="newObjectPropertyRef" class="form-control" /> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" onclick="setTemplateAndTemplatePropertyRef();">Set</button> + </div> + </div> + </div> +</div> + +<bd:browseForReqOrCap label="Requirement" reqOrCap="Req" requirementsOrCapabilities="requirements"/> +<bd:browseForReqOrCap label="Capability" reqOrCap="Cap" requirementsOrCapabilities="capabilities"/> + +<script> +//global variable to hold the reference to the input field where the selection of the service template property should be written into +//Requried as both a property mapping and a property constraint refer to a property of the service template. +var fieldToWriteSelectedServiceTemplateProperty; + +function setServiceTemplatePropertyRef() { + fieldToWriteSelectedServiceTemplateProperty.val($("#newServiceTemplatePropertyRef").val()); + $("#browseForServiceTemplatePropertyDiag").modal("hide"); +} + +function browseForServiceTemplateProperty(field) { + fieldToWriteSelectedServiceTemplateProperty = field; + $("#newServiceTemplatePropertyRef").val(field.val()); + $("#browseForServiceTemplatePropertyDiag").modal("show"); +} + + +/** + * Opens topology and lets user select a node template, relationship template, + */ +function browseForTemplateAndProperty() { + $("#newObjectRef").val($("#targetObjectRef").val()); + $("#newObjectPropertyRef").val($("#targetPropertyRef").val()); + $("#browseForTemplateProperty").modal("show"); +} + +function setTemplateAndTemplatePropertyRef() { + $("#targetObjectRef").val($("#newObjectRef").val()); + // always copy over targetPropertyRef, even if it's empty + $("#targetPropertyRef").val($("#newObjectPropertyRef").val()); + + $("#browseForTemplateProperty").modal("hide"); +} + +<c:if test="${not empty definedPropertiesAsJSONString}"> +// initialize the xmltree of the service template properties +// xmltree has to be inialized once and not more than once +// Therefore, we put it here and not in some shown events +require(["xmltree"], function(xmltree) { + new xmltree({ + xml: '${definedPropertiesAsJSONString}', + container: '#propertymappingstree', + startCollapsed: false, + clickCallback: serviceTemplatePropertyClicked + }); +}); +</c:if> + +function serviceTemplatePropertyClicked(li, xpath, event) { + require(["winery-support"], function(ws) { + var pathFragmentRegExp = ws.QName_RegExp + "(.*)"; + var pathFragmentPattern = new RegExp(pathFragmentRegExp); + + // Transform the XPath to an XPath being namespace unaware + // This is required as the OpenTOSCA container does not implement XPath processing in a namespace-aware manner + var fragments = xpath.split("/"); + var path = []; + $(fragments).each(function(i,e) { + var res = pathFragmentPattern.exec(e); + if (res != null) { + if (typeof res[1] !== undefined) { + e = "*[local-name()='" + res[3] + "']" + res[5]; + } + } + path.push(e); + }); + xpath = path.join("/"); + + $("#newServiceTemplatePropertyRef").val(xpath); + }); +} + +/* communication with the iframe is at boundarydefinitions.jsp as we also need it for "Interfaces" */ + +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForX.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForX.tag new file mode 100644 index 0000000..4b38b62 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/servicetemplates/boundarydefinitions/browseForX.tag @@ -0,0 +1,49 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@tag pageEncoding="UTF-8"%> + +<%@attribute name="XShort" description="The X to browse for. Short form. E.g., Req, Cap, ..." required="true" %> +<%@attribute name="XLong" description="The X to browse for. Long form. E.g., Requirement, Capability, ..." required="true" %> + + +<%-- Browse for property --%> +<div class="modal fade z1051" id="browseFor${XShort}Diag"> + <div class="modal-dialog" style="width:1000px;"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Choose a ${XLong}</h4> + </div> + + <div class="modal-body"> + <p class="text-info">Please click on the desired ${XLong}</p> + <iframe id="topologyTemplatePreview" class="topologyTemplatePreviewSizing" src="topologytemplate/?view=${XShort}Selection&script=${pageContext.request.contextPath}/js/boundaryDefinitionsXSelection.js"></iframe> + <form> + <fieldset> + <div class="form-group"> + <label for="${XShort}RefeferenceField">Reference to the ${XLong} in the topology template</label> + <input type="text" id="${XShort}ReferenceField" class="form-control newObjectRef" /> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" onclick="set${XShort}Ref();">Set</button> + </div> + </div> + </div> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/simpleSingleFileUpload.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/simpleSingleFileUpload.tag new file mode 100644 index 0000000..9774ba3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/simpleSingleFileUpload.tag @@ -0,0 +1,114 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@tag description="Global Wrapper" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + +<%@attribute name="title" required="true" description="title of the dialog"%> +<%@attribute name="text" required="true" description="text to show before upload box"%> +<%@attribute name="URL" required="true" description="URL to post to"%> +<%@attribute name="type" required="true" description="PUT|POST"%> +<%@attribute name="additionalDropZone" required="false" description="jQuery selector for an additional dropzone"%> +<%@attribute name="id" required="true" description="id to form basis for ...Diag: id of diag; ...Form: id of input field used for file upload; ...Img: Image to refresh"%> +<%@attribute name="accept" description="if not null/'': list of accepted MIME file types"%> +<%@attribute name="resize" description="if not null/'': enables image resizing. Currently not supported"%> + +<div class="modal fade" id="${id}Diag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">${title}</h4> + </div> + <div class="modal-body"> + <form> + <fieldset> + <div class="form-group"> + <label for="${id}Form">${text}:</label> + <input id="${id}Form" class="form-control" type="file" name="${id}Form" <c:if test="${!empty accept}">accept="${accept}"</c:if> /> + </div> + </fieldset> + <p>You may also <strong>drop the file</strong> here.</p> + <p>The file is <strong>immediately</strong> uploaded without any confirmation.</p> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal" data-loading-text="Uploading..." id="cancelfileuploadbtn">Cancel</button> + </div> + </div> + </div> +</div> + +<script> +/** + * We cannot use jQuery's ",", because this leads to multiple uploads at a single drop. + * Therefore, we introduced that function + */ +function bindFileUploadForSingleFileUpload(selector) { + requirejs(["jquery.fileupload"], function(){ + $(selector).fileupload({ + dataType: 'json', + url: '${URL}', + type: '${type}', + dropZone: $(selector), + paramName: 'file', + autoUpload: true + }).bind("fileuploadstart", function(e) { + $("#cancelfileuploadbtn").button("loading"); + }).bind('fileuploadfail', function(e, data) { + vShowAJAXError("File upload failed", data.jqXHR, data.errorThrown); + $("#cancelfileuploadbtn").button("reset"); + }).bind('fileuploaddone', function(e, data) { + var text = "File uploaded successfully."; + var responseText = data.jqXHR.responseText; + if (responseText != "") { + // we expect a JSON array + var response = $.parseJSON(responseText); + if (response.length == 0) { + // some JSON parsing error, just display the text itself + text = text + "<br /><br />With following issues, possibly wrong<br />" + responseText; + } else if (response.length == 1) { + text = text + "<br /><br />With following issue<br />" + response[0]; + } else { + text = text + "<br /><br />With following issues, possibly wrong<br /><ul>"; + $(response).each(function(i,e) { + text = text + "<li>" + e + "</li>"; + }); + text = text + "</ul>"; + } + } + vShowSuccess(text); + $("#cancelfileuploadbtn").button("reset"); + $('#${id}Diag').modal('hide'); + + // refresh the image + img = $('#${id}Img'); + if (img.length === 1) { + src = img.attr('src'); + queryPos = src.indexOf('?'); + if(queryPos != -1) { + src = src.substring(0, queryPos); + } + img.attr('src', src + '?' + Math.random()); + } + }); + }); +} + +$(function() { + bindFileUploadForSingleFileUpload("#${id}Diag"); + <c:if test="${not empty additionalDropZone}">bindFileUploadForSingleFileUpload("${additionalDropZone}");</c:if> +}); +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/submenu.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/submenu.tag new file mode 100644 index 0000000..0e6a320 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/submenu.tag @@ -0,0 +1,26 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<!-- basic idea by http://stackoverflow.com/a/3257426/873282 --> +<%@tag description="submenu" pageEncoding="UTF-8"%> + +<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + +<%@attribute name="subMenuData" required="true" type="org.eclipse.winery.repository.resources.SubMenuData"%> +<%@attribute name="selected" required="true"%> + +<a href="${subMenuData.href}" class="styledTabMenuButton styledTabMenuButton2ndlevel<c:if test="${selected}"> selected</c:if>"> + <div class="left"></div> + <div class="center">${subMenuData.text}</div> + <div class="right"></div> +</a> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/topologyTemplateRenderer.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/topologyTemplateRenderer.tag new file mode 100644 index 0000000..5f0aaa4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/topologyTemplateRenderer.tag @@ -0,0 +1,208 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - skeletton for topology rendering + * Oliver Kopp - converted to .tag and integrated in the repository + *******************************************************************************/ +--%> +<%@tag description="Renders a toplogytemplate. This tag is used to render a topology template readonly. The topoology modeler does the rendering on itself." pageEncoding="UTF-8" %> + +<%@tag import="java.lang.Math"%> +<%@tag import="java.util.ArrayList"%> +<%@tag import="java.util.Collection"%> +<%@tag import="java.util.Map"%> +<%@tag import="java.util.HashMap"%> +<%@tag import="java.util.UUID"%> +<%@tag import="javax.xml.namespace.QName"%> +<%@tag import="org.eclipse.winery.common.ModelUtilities"%> +<%@tag import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeType"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate.TargetElement"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.model.tosca.TTopologyTemplate"%> +<%@tag import="org.eclipse.winery.repository.Utils"%> + +<%@attribute name="topology" required="true" description="the topology template to be rendered" type="org.eclipse.winery.model.tosca.TTopologyTemplate" %> +<%@attribute name="repositoryURL" required="true" %> +<%@attribute name="client" required="true" type="org.eclipse.winery.common.interfaces.IWineryRepository" %> +<%@attribute name="fullscreen" required="false" type="java.lang.Boolean" %> +<%@attribute name="additonalCSS" required="false"%> +<%@attribute name="autoLayoutOnLoad" required="false" type="java.lang.Boolean" %> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="tmpl" tagdir="/WEB-INF/tags/common/templates" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<%-- required for vShowError --%> +<script type="text/javascript" src="${w:topologyModelerURI()}/components/pnotify/jquery.pnotify.js"></script> +<script type="text/javascript" src="${w:topologyModelerURI()}/js/winery-common.js"></script> + +<%-- required for vShowError --%> +<link type="text/css" href="${w:topologyModelerURI()}/components/pnotify/jquery.pnotify.default.css" media="all" rel="stylesheet" /> +<link type="text/css" href="${w:topologyModelerURI()}/components/pnotify/jquery.pnotify.default.icons.css" media="all" rel="stylesheet" /> + +<%-- winery-common.css also contains definitions for properties --%> +<link type="text/css" href="${w:topologyModelerURI()}/css/winery-common.css" rel="stylesheet" /> +<link type="text/css" href="${w:topologyModelerURI()}/css/topologytemplatecontent.css" rel="stylesheet" /> +<link rel="stylesheet" href="${pageContext.request.contextPath}/css/topologyTemplateRenderer.css" /> +<c:if test="${not empty fullscreen}"><link rel="stylesheet" href="${pageContext.request.contextPath}/css/topologyTemplateRendererFullscreen.css" /></c:if> +<c:if test="${not empty additonalCSS}"><link rel="stylesheet" href="${additonalCSS}" /></c:if> + +<% + Collection<TRelationshipType> relationshipTypes = client.getAllTypes(TRelationshipType.class); + + // quick hack + // better would be to collect all types used in the curren topoloy template + Collection<TNodeType> nodeTypes = client.getAllTypes(TNodeType.class); +%> + +<tmpl:CSSForTypes nodeTypes="<%=nodeTypes%>" relationshipTypes="<%=relationshipTypes%>"/> + +<script> +// required by winery-common-topologyrendering +if (typeof winery === "undefined") winery = {} +if (typeof winery.connections === "undefined") winery.connections = {} + +//enable caching. This disables appending of "?_=xy" at requests +jQuery.ajaxSetup({cache:true}); + +//configuration for pnotify +require(["jquery", "pnotify"], function() { + $.pnotify.defaults.styling = "bootstrap3"; +}); +</script> + +<% + // used for the position of the NodeTemplates + int topCounter = 0; +%> +<script> +function doLayout() { + var editor = $("#editorArea"); + var nodeTemplates = editor.find(".NodeTemplateShape"); + require(["winery-sugiyamaLayouter"], function(layouter) { + layouter.layout(nodeTemplates); + }); +} +</script> +<div class="topbar"> + <div class="topbarbuttons"> + <button class="btn btn-default" onclick="doLayout();">Layout</button> + <tmpl:toggleButtons /> + </div> +</div> +<%-- div #editorArea required for layouter --%> +<div id="editorArea"> +<div id="templateDrawingArea"> + +<tmpl:defineCreateConnectorEndpointsFunction relationshipTypes="<%=relationshipTypes%>"/> + +<% + // can be used later to call a doLayout() + boolean somethingWithoutPosition = false; + + Collection<TRelationshipTemplate> relationshipTemplates = new ArrayList<TRelationshipTemplate>(); + Collection<TNodeTemplate> nodeTemplates = new ArrayList<TNodeTemplate>(); + + // the minimum x/y coordinates. + // used to move the content to the top left corner + int minTop = Integer.MAX_VALUE; + int minLeft = Integer.MAX_VALUE; + + for (TEntityTemplate entity: topology.getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) entity; + nodeTemplates.add(nodeTemplate); + + // determine minTop and minLeft + String top = ModelUtilities.getTop(nodeTemplate); + if (top != null) { + int intTop = Utils.convertStringToInt(top); + if (intTop != 0) { + minTop = Math.min(minTop, intTop); + } + } + + String left = ModelUtilities.getLeft(nodeTemplate); + if (left != null) { + int intLeft = Utils.convertStringToInt(left); + if (intLeft != 0) { + minLeft = Math.min(minLeft, intLeft); + } + } + + } else { + assert(entity instanceof TRelationshipTemplate); + relationshipTemplates.add((TRelationshipTemplate) entity); + } + } + + for (TNodeTemplate nodeTemplate: nodeTemplates) { + // assuming the topology can be displayed as a stack, else call doLayout() afterwards + topCounter = topCounter + 150; + + String left = ModelUtilities.getLeft(nodeTemplate); + if (left == null) { + left = "0"; + somethingWithoutPosition = true; + } else { + // calulate offset + // we could hash the coordinate in the loop before + // but that would obfuscate the code and currently, we don't have speed issues here + left = Integer.toString(Utils.convertStringToInt(left) - minLeft); + } + String top = ModelUtilities.getTop(nodeTemplate); + if (top == null) { + top = Integer.toString(topCounter); + somethingWithoutPosition = true; + } else { + // calulate offset + top = Integer.toString(Utils.convertStringToInt(top) - minTop); + } +%> + <nt:nodeTemplateRenderer top="<%=top%>" left="<%=left%>" nodeTemplate="<%=nodeTemplate%>" repositoryURL="${repositoryURL}" client="<%=client%>" relationshipTypes="<%=relationshipTypes%>" topologyModelerURI="${w:topologyModelerURI()}/" /> +<% + } + if (somethingWithoutPosition) { + autoLayoutOnLoad = true; + } +%> + +<script> +function onDoneRendering() { + <c:if test="${autoLayoutOnLoad}"> + doLayout(); + </c:if> + + // copied from index.jsp -> togglePrintView + + // move labels 10 px up + // we have to do it here as jsPlumb currently paints the label on the line instead of above of it + // See https://groups.google.com/d/msg/jsplumb/zdyAdWcRta0/K6F2MrHBH1AJ + $(".relationshipTypeLabel").each(function(i, e) { + var pos = $(e).offset(); + pos.top = pos.top - 10; + $(e).offset(pos); + }); + + // The user can pass an additional script to the topologyTemplateResource via the script query parameter + // In that script, he can define the function wineryViewExternalScriptOnLoad which is called here + if (typeof wineryViewExternalScriptOnLoad === "function") { + wineryViewExternalScriptOnLoad(); + } +} +</script> +<tmpl:registerConnectionTypesAndConnectNodeTemplates repositoryURL="${repositoryURL}" relationshipTypes="<%=relationshipTypes%>" relationshipTemplates="<%=relationshipTemplates%>" ondone="onDoneRendering();" readOnly="true"/> +</div> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/typeswithshortnameasselect.tag b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/typeswithshortnameasselect.tag new file mode 100644 index 0000000..f658b2b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/tags/typeswithshortnameasselect.tag @@ -0,0 +1,46 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Renders pairs of types with shortname as select element" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%@attribute name="label" required="true"%> +<%@attribute name="selectname" required="true" description="Used as Name and as Id"%> +<%@attribute name="typesWithShortNames" required="true" type="java.util.Collection"%> +<%@attribute name="type" required="true" description="The type of all types. E.g., planlanguage"%> + +<div class="form-group"> +<label for="${selectname}">${label}</label> + +<div style="display: block; width: 100%"> + <select name="${selectname}" id="${selectname}" style="width:300px;"> + <c:forEach var="t" items="${typesWithShortNames}"> + <option value="${t.type}">${t.shortName}</option> + </c:forEach> + </select> + <button type="button" class="btn btn-info btn-xs" onclick="updateTypesWithShortNames();">Refresh</button> + <a href="${pageContext.request.contextPath}/admin/#${type}s" class="btn btn-info btn-xs" target="_blank">Manage</a> +</div> +</div> + +<script> +function updateTypesWithShortNames() { + vShowNotification('not yet implemented') + /* Implementation idea: + * get on ...${type}s resource with app/json and ?select2 - this is the direct select2 data + * replace select element with input: select2 cannot update an input element + */ +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/web.xml b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..b5eb167 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="winery" version="3.0"> + <display-name>Winery Repository</display-name> + <filter> + <filter-name>WineryResources</filter-name> + <filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class> + <init-param> + <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name> + <!-- RestDocFilter is required for RESTDoc. CORSFilter is required for the BPMN4TOSCA Plan Modeler --> + <param-value>org.eclipse.winery.repository.RestDocFilter;org.eclipse.winery.repository.CORSFilter</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.property.packages</param-name> + <param-value>org.eclipse.winery.repository.resources</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.feature.CanonicalizeURIPath</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.feature.NormalizeURI</param-name> + <param-value>true</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.feature.Redirect</param-name> + <param-value>true</param-value> + </init-param> + + <!-- enables @Consumes(MediaType.APPLICATION_JSON) and @Produces(MediaType.APPLICATION_JSON), see https://jersey.java.net/nonav/documentation/1.7/json.html --> + <init-param> + <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> + <param-value>true</param-value> + </init-param> + + </filter> + <filter-mapping> + <filter-name>WineryResources</filter-name> + + <!-- + Each resource handled by JAX-RS has to be written separately. + Reason: + * /components, /css, /images, /js are not provided by JAX-RS + * FilterForwardOn404 is a Jersey feature, not standardized + * It also forwards if a resource itself returns 404 (without an entity) + * The JAX-RS code should not be cluttered with Jersey specifics + --> + + <!-- ordering as in TOSCA-v1.0.xsd of TOSCA CSD08 --> + + <url-pattern>/imports/*</url-pattern> + <url-pattern>/servicetemplates/*</url-pattern> + <url-pattern>/nodetypes/*</url-pattern> + <url-pattern>/nodetypeimplementations/*</url-pattern> + <url-pattern>/relationshiptypes/*</url-pattern> + <url-pattern>/relationshiptypeimplementations/*</url-pattern> + <url-pattern>/requirementtypes/*</url-pattern> + <url-pattern>/capabilitytypes/*</url-pattern> + <url-pattern>/artifacttypes/*</url-pattern> + <url-pattern>/artifacttemplates/*</url-pattern> + <url-pattern>/policytypes/*</url-pattern> + <url-pattern>/policytemplates/*</url-pattern> + + <!-- additional resources --> + <url-pattern>/</url-pattern> + <url-pattern>/admin/*</url-pattern> + <url-pattern>/API/*</url-pattern> + <url-pattern>/other/*</url-pattern> + <url-pattern>/test/*</url-pattern> + + </filter-mapping> + <listener> + <listener-class>org.eclipse.winery.repository.Prefs</listener-class> + </listener> + + <session-config> + <tracking-mode>COOKIE</tracking-mode> + </session-config> +</web-app> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologyTemplateRenderer.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologyTemplateRenderer.css new file mode 100644 index 0000000..f24db2c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologyTemplateRenderer.css @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial implementation + * Pascal Hirmer - improvements + * Oliver Kopp - improvements + *******************************************************************************/ + +#templateDrawingArea { + height: 500px; + position: relative; + overflow-y: scroll; +} + +#templateEditorArea { + width: 100%; + height: 100%; + margin-top: 45px; +} + +div.NodeTemplateShape { + cursor: default; +} + +div.topbar { + position: absolute; + height: 30px; + width: 100%; + z-index: 1000; +} + +div.topbarbuttons { + display: none; +} + +div.topbar:hover > div.topbarbuttons { + display: inherit; +} + +/* hide the area to add a deployment artifact */ +div.addDA { + display: none; +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologyTemplateRendererFullscreen.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologyTemplateRendererFullscreen.css new file mode 100644 index 0000000..b5535ba --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologyTemplateRendererFullscreen.css @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial implementation + *******************************************************************************/ + +#templateDrawingArea { + height: 100%; + background: white; +} + +#templateEditorArea { + margin-top: 0px; +} + +/* + * used if elements should be hidden forever. Cannot be undone with $(...).show() + * + * not globally defined + */ +.hidden { + display: none; +} + diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/CapSelection.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/CapSelection.css new file mode 100644 index 0000000..1032dd2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/CapSelection.css @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial implementation + *******************************************************************************/ + +div.NodeTemplateShape > div.capabilitiesContainer { + display: inherit; +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/NodeTemplateSelection.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/NodeTemplateSelection.css new file mode 100644 index 0000000..53b69ef --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/NodeTemplateSelection.css @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial implementation + *******************************************************************************/ + +/* nothing special needed */
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/RelationshipTemplateSelection.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/RelationshipTemplateSelection.css new file mode 100644 index 0000000..53b69ef --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/RelationshipTemplateSelection.css @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial implementation + *******************************************************************************/ + +/* nothing special needed */
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/ReqSelection.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/ReqSelection.css new file mode 100644 index 0000000..f4bcfae --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/ReqSelection.css @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial implementation + *******************************************************************************/ + +div.NodeTemplateShape > div.requirementsContainer { + display: inherit; +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/propertySelection.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/propertySelection.css new file mode 100644 index 0000000..f3673eb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/propertySelection.css @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial implementation + *******************************************************************************/ + +div.NodeTemplateShape > div.propertiesContainer { + display: inherit; +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/small.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/small.css new file mode 100644 index 0000000..d7f298c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/topologytemplaterendering/small.css @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial implementation + *******************************************************************************/ +div.relationshipTypeLabel { + display:none; +} + +div.nodetemplate.name { + display: none; +} +div.NodeTemplateShape > .headerContainer > div.type { + top: 15px; + left: 34px; + width: 111px; + text-align: center; + font-size: 11px; +} + +div.NodeTemplateShape > .headerContainer > img.icon { + height: 35px; + margin: 4px 4px; +} + +div.NodeTemplateShape { + border-width: 1px; + height: 45px; + width: 150px; + border-radius: 8px; +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/css/winery-repository.css b/winery/org.eclipse.winery.repository/src/main/webapp/css/winery-repository.css new file mode 100644 index 0000000..11441b4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/css/winery-repository.css @@ -0,0 +1,868 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial implementation + * Oliver Kopp - improvements + *******************************************************************************/ + +/* override jquery redmond theme */ + +.hidden { + display: none; +} + +.ui-widget { + font-size: 11px; +} + +body { + width: 1000px; + background: #eaeaea; +} + +#header { + width: 100%; + height: 87px; + background: url('../images/header_background.png'); + background-repeat: no-repeat; +} + +#showabout { + float: right +} + +#header > div#buttonContainer { + + height: 30px; + top: 40px; + position: relative; +} + +#header > div#buttonContainer > a { + height: 30px; + float: left; + display: block; + margin-left: 30px; + padding-left: 10px; + padding-right: 10px; + border-radius: 10px 10px 0px 0px; + line-height: 27px; + text-decoration: none; + font-family: arial; + color: #787878; + font-size: 14px; + text-shadow: 1px 1px 0px white; +} + +#header > span { + position: relative; + top: 42px; + left: 10px; +} + +#headerelements { + position: relative; + bottom: 0px; +} + +#tabs { + box-shadow: 3px 3px 9px #888888; + min-height: 350px; +} + +#mainContainer { + border-left: 1px solid #AEAEAE; + position: absolute; + left: 50%; + margin: 10px 0 0 -500px; + padding-bottom: 15px; + border-radius: 0px 0px 18px 18px; + border-bottom: 1px solid #AEAEAE; + border-right: 1px solid #AEAEAE; + box-shadow: 3px 3px 9px #888888; + background: white; + width: 1000px; +} + +/* bootstrap removes scrollbar making the content moving. Undo that effect: + 15 / 2 = 7.5. We choose 8. 500+8=508 */ +body.modal-open > #mainContainer.overflown { + margin: 10px 0 0 -508px; +} + +/* resulting in the same alignment if a scrollbar is shown or not (two browser tabs with different tabs) */ +#mainContainer.notoverflown { + margin: 10px 0 0 -508px; +} + + +#mainContent { + padding-left: 5px; + min-height: 350px; +} + +#naming { + margin-bottom: 15px; +} + +#namespacesListContainer { + width: 300px; + float: left; +} + +.listheading { + margin: 0px 0px 15px 0px; +} + +.listcontent { + width: 100%; +} + +#buttonList { + width: 140px; +} + +#buttonList > a { + width: 85px; + float: left; + margin-top: 10px; +} + +.rightbutton { + float: right; + margin: 0 0 2px 2px; +} + +.label { + font-family: sans-serif; +} + +a.squareButton { + border: 1px solid #aeaeae; + background: #eaeaea; + height: 20px; + width: 20px; + text-align: center; + text-decoration: none; + line-height: 20px; + margin-left: 4px; + float: left; +} + +a.button { + border: 1px solid #aeaeae; + background: #eaeaea; + height: 20px; + padding-left: 4px; + padding-right: 4px; + text-align: center; + text-decoration: none; + line-height: 20px; + margin-left: 4px; + float: left; +} + +table tr.even.row_selected td { + background-color: #B0BED9; +} + +table tr.odd.row_selected td { + background-color: #9FAFD1; +} + +table tr.even.row_selected td.sorting_1 { + background-color: #B0BED9; +} + +table tr.odd.row_selected td.sorting_1 { + background-color: #9FAFD1; +} + + +div#mainMenuContainer { + height: 28px; + position: relative; + top: 38px; +} + +/* jquery file upload styling */ +.fileupload-buttonbar .ui-progressbar-value { + background: url(../images/jquery-fileupload/progressbar.gif); +} +.fileupload-loading { + background: url(../images/jquery-fileupload/loading.gif) center no-repeat; +} + + +/* tabs */ + +a.styledTabMenuButton { + margin-bottom: 3px; + float: left; +} + +a.styledTabMenuButton > div { + height: 28px; + float: left; +} + +a.styledTabMenuButton > div.left { + width: 19px; +} + +a.styledTabMenuButton > div.center { + line-height: 29px; + text-decoration: none; + font-family: arial; + color: #787878; + font-size: 14px; + text-shadow: 1px 1px 0px white; + padding-left: 5px; +} + +a.styledTabMenuButton > div.right { + width: 29px; +} + +a.styledTabMenuButton.selected > div.left, a.styledTabMenuButton:hover > div.left { + background: url('../images/styledTabMenuButtonLeft.jpg'); + width: 19px; +} + +a.styledTabMenuButton.selected > div.center, a.styledTabMenuButton:hover > div.center { + background: url('../images/styledTabMenuButtonCenter.jpg'); +} + +a.styledTabMenuButton.selected > div.right, a.styledTabMenuButton:hover > div.right { + background: url('../images/styledTabMenuButtonRight.jpg'); + width: 29px; +} + +/* main containers */ + +div.mainContentContainer, div.mainContentContainer > div { + float: left; + width: 989px; +} +div.mainContentContainer > div.top { + height: 150px; +} + +div.mainContentContainer > div.top.twolines { + height: 179px; +} + +div.mainContentContainer > div.middle { + width: 987px; + min-height: 350px; + padding: 0px 35px 0px 35px; + font-family: arial, verdana; + font-size: 12px; + line-height: 19px; + color: #494949; +} +div.mainContentContainer > div.bottom { + height: 40px; +} + +div.mainContentContainer.serviceTemplate > div.top { + background: url('../images/containers/st/FrameTop.jpg'); +} +div.mainContentContainer.serviceTemplate > div.middle { + background: url('../images/containers/st/FrameMiddle.jpg'); +} +div.mainContentContainer.serviceTemplate > div.bottom { + background: url('../images/containers/st/FrameBottom.jpg'); +} + +div.mainContentContainer.relationshipType > div.top { + background: url('../images/containers/rt/FrameTopLarge.jpg'); +} +div.mainContentContainer.relationshipType > div.middle { + background: url('../images/containers/rt/FrameMiddle.jpg'); +} +div.mainContentContainer.relationshipType > div.bottom { + background: url('../images/containers/rt/FrameBottom.jpg'); +} + +div.mainContentContainer.nodeType > div.top { + background: url('../images/containers/nt/FrameTopLarge.jpg'); +} +div.mainContentContainer.nodeType > div.middle { + background: url('../images/containers/nt/FrameMiddle.jpg'); +} +div.mainContentContainer.nodeType > div.bottom { + background: url('../images/containers/nt/FrameBottom.jpg'); +} + +div.mainContentContainer.admin > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.admin > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.admin > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + + +/* quick hack for new types: just use the administration */ + +div.mainContentContainer.artifactTemplate > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.artifactTemplate > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.artifactTemplate > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.artifactType > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.artifactType > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.artifactType > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.nodeTypeImplementation > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.nodeTypeImplementation > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.nodeTypeImplementation > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.relationshipTypeImplementation > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.relationshipTypeImplementation > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.relationshipTypeImplementation > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.requirementType > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.requirementType > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.requirementType > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.capabilityType > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.capabilityType > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.capabilityType > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.policyTemplate > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.policyTemplate > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.policyTemplate > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.policyType > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.policyType > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.policyType > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + +div.mainContentContainer.xsdimport > div.top { + background: url('../images/containers/admin/FrameTop.jpg'); +} +div.mainContentContainer.xsdimport > div.middle { + background: url('../images/containers/admin/FrameMiddle.jpg'); +} +div.mainContentContainer.xsdimport > div.bottom { + background: url('../images/containers/admin/FrameBottom.jpg'); +} + + + + +div.mainContentContainer > div.top > div.informationContainer { + position: relative; + top: 30px; + left: 120px; + height: 45px; + width: 100%; + + color: #787878; + font-family: arial; + font-size: 14px; + padding-left: 5px; + text-decoration: none; + text-shadow: 1px 1px 0 white; +} + + +div.mainContentContainer > div.top > div.informationContainer > div.name { + font-size: 17px; + font-weight: bold; + height: 22px; +} + +div.mainContentContainer > div.top > div.informationContainer > div.namespace { +} + + +div.mainContentContainer > div.top { + position: relative; +} + +div.mainContentContainer > div.top > div.subMenu { + position: absolute; + top: 97px; + left: 20px; +} + +/** lists of components (service templates, node types, relationship types) **/ + +div.entityContainer { + float: left; + margin-bottom: 10px; + cursor: pointer; +} + +div.entityContainer > div { + float: left; + height: 86px; +} + +div.entityContainer > div.left { + width: 117px; +} + +div.entityContainer > div.center { + width: 500px; +} + +div.entityContainer > div.right { + width: 33px; +} + +div.entityContainer > div.center > div.informationContainer { + margin-top: 25px; + height: 45px; + color: #787878; + font-family: arial; + font-size: 12px; + padding-left: 5px; + text-decoration: none; + text-shadow: 1px 1px 0 white; + float: left; + max-width: 313px; +} + + +div.entityContainer > div.center > div.informationContainer > div.name { + font-size: 14px; + font-weight: bold; + height: 18px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +div.entityContainer > div.center > div.informationContainer > div.namespace { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +div.entityContainer.serviceTemplate > div.left { + background: url('../images/entityBox/serviceTemplate/left.jpg'); +} + +div.entityContainer.serviceTemplate > div.center { + background: url('../images/entityBox/serviceTemplate/center.jpg'); +} + +div.entityContainer.serviceTemplate > div.right { + background: url('../images/entityBox/serviceTemplate/right.jpg'); +} + +div.entityContainer.nodeType > div.left { + background: url('../images/entityBox/nodeType/left.jpg'); +} + +div.entityContainer.nodeType > div.center { + background: url('../images/entityBox/nodeType/center.jpg'); +} + +div.entityContainer.nodeType > div.right { + background: url('../images/entityBox/nodeType/right.jpg'); +} + +div.entityContainer.relationshipType > div.left { + background: url('../images/entityBox/relationshipType/left.jpg'); +} + +div.entityContainer.relationshipType > div.center { + background: url('../images/entityBox/relationshipType/center.jpg'); +} + +div.entityContainer.relationshipType > div.right { + background: url('../images/entityBox/relationshipType/right.jpg'); +} + +div.entityContainer.admin > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.admin > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.admin > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + + +div.entityContainer.artifactTemplate > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.artifactTemplate > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.artifactTemplate > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + + +div.entityContainer.artifactType > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.artifactType > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.artifactType > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + + +div.entityContainer.nodeTypeImplementation > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.nodeTypeImplementation > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.nodeTypeImplementation > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + + +div.entityContainer.relationshipTypeImplementation > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.relationshipTypeImplementation > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.relationshipTypeImplementation > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + +div.entityContainer.requirementType > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.requirementType > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.requirementType > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + +div.entityContainer.capabilityType > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.capabilityType > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.capabilityType > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + +div.entityContainer.policyTemplate > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.policyTemplate > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.policyTemplate > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + +div.entityContainer.policyType > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.policyType > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.policyType > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + +div.entityContainer.xSDImport > div.left { + background: url('../images/entityBox/admin/left.jpg'); +} + +div.entityContainer.xSDImport > div.center { + background: url('../images/entityBox/admin/center.jpg'); +} + +div.entityContainer.xSDImport > div.right { + background: url('../images/entityBox/admin/right.jpg'); +} + + +/* buttons */ +div.entityContainer > div.center > div.buttonContainer { + float: right; + height: 42px; + + margin-top: 23px; + margin-left: 40px; +} + +div.entityContainer > div.center > div.buttonContainer > a { + float: left; + height: 42px; + margin-right: 5px; +} + +div.entityContainer > div.center > div.buttonContainer > a.editButton { + background: url('../images/entityBox/editButton.jpg'); + width: 41px; +} +div.entityContainer > div.center > div.buttonContainer > a.editButton:hover { + background: url('../images/entityBox/editButtonHover.jpg'); +} + +div.entityContainer > div.center > div.buttonContainer > a.exportButton { + background: url('../images/entityBox/exportButton.jpg'); + width: 53px; +} +div.entityContainer > div.center > div.buttonContainer > a.exportButton:hover { + background: url('../images/entityBox/exportButtonHover.jpg'); +} + +div.entityContainer > div.center > div.buttonContainer > a.deleteButton { + background: url('../images/entityBox/deleteButton.jpg'); + width: 33px; +} +div.entityContainer > div.center > div.buttonContainer > a.deleteButton:hover { + background: url('../images/entityBox/deleteButtonHover.jpg'); +} + +input.highlight { + background-color: lightskyblue; +} + +input.qnameinput { + width: 600px; +} + +/* fixes wrong z-index of autocompleter in jQuery UI 1.10.3 */ +.ui-autocomplete { + z-index: 1000; +} + +#warning { + color: blue; + font-weight: bold; + cursor: default; + float: right; + margin-right: 10px; + /* 0px is required to have the tabs below not being pushed down */ + height: 0px; +} + +#constraintlist { + cursor: pointer; +} + +#searchBox { + background: url("../images/searchBoxBackground.jpg") no-repeat scroll 2px -4px transparent; + border: 2px solid #BEBEBE; + border-radius: 15px 15px 15px 15px; + box-shadow: 5px 5px 5px #EAEAEA; + color: #676767; + font-size: 15px; + height: 35px; + margin-bottom: 30px; + padding: 5px 5px 5px 70px; + width: 660px; +} + +#gcprightcolumn { + background: url('../images/overviewShadowMiddle.jpg'); + width: 35px; + position: relative; + padding:0px; +} + +#overviewtopshadow { + top: 0px; + background-image: url("../images/overviewShadowTop.jpg"); + height: 269px; +} + +#overviewbottomshadow { + bottom: 0px; + background-image: url("../images/overviewShadowBottom.jpg"); + height: 269px; + position: absolute; + width: 35px; +} + +span.cursorpointer { + cursor: pointer; +} + +div.otherelements > a.btn { + width: 250px; +} + +#bigIconDiv { + height: 50px; +} + +div.colorpickerdiv { + height: 35px; + width: 35px; + background: url("../components/colorPicker/images/select.png") +} + +#applicationDescriptionDiv { + overflow-x: hidden; + overflow-y: scroll; + height: 200px; +} + +.XMLtextarea { + height: 300px; +} + +div.col-xs-4.bordered { + width: 32%; + border: 1px solid #DADADA; + padding: 0px; + +} + +div.col-xs-4.bordered div.listheading { + height: 36px; + padding-right: 3px; +} + +div.col-xs-4.middlebox { + margin-left: 18px; + margin-right: 18px; +} + +div.col-xs-4.bordered div.listheading > button { + margin-top: 3px; +} + +table.dataTable { + font-size: 12px; +} + +table.dataTable thead th { + font-size: 11px; + color: #3F3F3F; +} + +div.titledTableBox { + box-shadow: 2px 2px 5px #AEAEAE; + margin-bottom: 5px; + margin-right: 10px; + border: 1px solid #aeaeae; + padding: 0px; + margin-left: 0px; + padding-left: 0px !important; +} +.listheading { + background: url("../images/header_background.png") repeat scroll 0 -39px transparent; + height: 30px; + margin: 0px; + padding-left: 7px; + line-height: 30px; + font-size: 12px; + color: #606060; + text-shadow: 1px 1px 0 white; +} + +#names { + width: 200px; + overflow: hidden; + padding-left: 10px; + float: left; +} + +.listcontent { + border: 0px; + width: 100%; + margin: 0px; + border-top: 0px; +} + +.topologyTemplatePreviewSizing { + height:400px; + width:921px; +} + +#topologyTemplatePreview { + border: 0; +} + +div.policiesContainer > div.header { + display: none; +} + +div.policiesContainer > div.content > div.policy > textarea.policy_xml { + display: none; +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/back_disabled.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/back_disabled.png Binary files differnew file mode 100644 index 0000000..881de79 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/back_disabled.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/back_enabled.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/back_enabled.png Binary files differnew file mode 100644 index 0000000..c608682 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/back_enabled.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/back_enabled_hover.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/back_enabled_hover.png Binary files differnew file mode 100644 index 0000000..d300f10 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/back_enabled_hover.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameBottom.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameBottom.jpg Binary files differnew file mode 100644 index 0000000..b4a6162 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameBottom.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameMiddle.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameMiddle.jpg Binary files differnew file mode 100644 index 0000000..7aa2d8f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameMiddle.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameTop.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameTop.jpg Binary files differnew file mode 100644 index 0000000..3abcd7d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/FrameTop.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonCenter.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonCenter.jpg Binary files differnew file mode 100644 index 0000000..06867f4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonCenter.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonLeft.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonLeft.jpg Binary files differnew file mode 100644 index 0000000..507e738 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonLeft.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonRight.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonRight.jpg Binary files differnew file mode 100644 index 0000000..0727686 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/admin/styledTabMenuButtonRight.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameBottom.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameBottom.jpg Binary files differnew file mode 100644 index 0000000..6adfebc --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameBottom.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameMiddle.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameMiddle.jpg Binary files differnew file mode 100644 index 0000000..ef3ea5b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameMiddle.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameTop.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameTop.jpg Binary files differnew file mode 100644 index 0000000..59041c8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameTop.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameTopLarge.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameTopLarge.jpg Binary files differnew file mode 100644 index 0000000..0cf4f27 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/nt/FrameTopLarge.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameBottom.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameBottom.jpg Binary files differnew file mode 100644 index 0000000..adf92ce --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameBottom.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameMiddle.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameMiddle.jpg Binary files differnew file mode 100644 index 0000000..8ca58dd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameMiddle.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameTop.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameTop.jpg Binary files differnew file mode 100644 index 0000000..0bb76f1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameTop.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameTopLarge.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameTopLarge.jpg Binary files differnew file mode 100644 index 0000000..c0875c9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/rt/FrameTopLarge.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameBottom.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameBottom.jpg Binary files differnew file mode 100644 index 0000000..eb5bac3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameBottom.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameMiddle.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameMiddle.jpg Binary files differnew file mode 100644 index 0000000..009c9da --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameMiddle.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameTop.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameTop.jpg Binary files differnew file mode 100644 index 0000000..4c37ebf --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/containers/st/FrameTop.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/center.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/center.jpg Binary files differnew file mode 100644 index 0000000..b22c1ff --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/center.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/left.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/left.jpg Binary files differnew file mode 100644 index 0000000..e9e6559 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/left.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/right.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/right.jpg Binary files differnew file mode 100644 index 0000000..a1d34b4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/admin/right.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/deleteButton.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/deleteButton.jpg Binary files differnew file mode 100644 index 0000000..042ea00 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/deleteButton.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/deleteButtonHover.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/deleteButtonHover.jpg Binary files differnew file mode 100644 index 0000000..ba275b3 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/deleteButtonHover.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/editButton.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/editButton.jpg Binary files differnew file mode 100644 index 0000000..0a58fa4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/editButton.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/editButtonHover.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/editButtonHover.jpg Binary files differnew file mode 100644 index 0000000..2fdfc34 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/editButtonHover.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/exportButton.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/exportButton.jpg Binary files differnew file mode 100644 index 0000000..b1ddd75 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/exportButton.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/exportButtonHover.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/exportButtonHover.jpg Binary files differnew file mode 100644 index 0000000..f58de95 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/exportButtonHover.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/center.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/center.jpg Binary files differnew file mode 100644 index 0000000..3951c2b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/center.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/left.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/left.jpg Binary files differnew file mode 100644 index 0000000..dda69ce --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/left.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/right.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/right.jpg Binary files differnew file mode 100644 index 0000000..9d796c9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/nodeType/right.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/center.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/center.jpg Binary files differnew file mode 100644 index 0000000..c66dbf0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/center.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/left.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/left.jpg Binary files differnew file mode 100644 index 0000000..5945f80 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/left.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/right.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/right.jpg Binary files differnew file mode 100644 index 0000000..f49ddff --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/relationshipType/right.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/center.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/center.jpg Binary files differnew file mode 100644 index 0000000..385327a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/center.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/left.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/left.jpg Binary files differnew file mode 100644 index 0000000..eda0c8b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/left.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/right.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/right.jpg Binary files differnew file mode 100644 index 0000000..8d4cd7e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/entityBox/serviceTemplate/right.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/favicon.ico b/winery/org.eclipse.winery.repository/src/main/webapp/images/favicon.ico Binary files differnew file mode 100644 index 0000000..823222e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/favicon.ico diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_disabled.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_disabled.png Binary files differnew file mode 100644 index 0000000..6a6ded7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_disabled.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_enabled.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_enabled.png Binary files differnew file mode 100644 index 0000000..a4e6b53 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_enabled.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_enabled_hover.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_enabled_hover.png Binary files differnew file mode 100644 index 0000000..fc46c5e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/forward_enabled_hover.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/header_background.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/header_background.png Binary files differnew file mode 100644 index 0000000..0a797ac --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/header_background.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/jquery-fileupload/loading.gif b/winery/org.eclipse.winery.repository/src/main/webapp/images/jquery-fileupload/loading.gif Binary files differnew file mode 100644 index 0000000..90f28cb --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/jquery-fileupload/loading.gif diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/jquery-fileupload/progressbar.gif b/winery/org.eclipse.winery.repository/src/main/webapp/images/jquery-fileupload/progressbar.gif Binary files differnew file mode 100644 index 0000000..fbcce6b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/jquery-fileupload/progressbar.gif diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowBottom.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowBottom.jpg Binary files differnew file mode 100644 index 0000000..28ae493 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowBottom.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowMiddle.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowMiddle.jpg Binary files differnew file mode 100644 index 0000000..ab770b2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowMiddle.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowTop.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowTop.jpg Binary files differnew file mode 100644 index 0000000..9b6afec --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/overviewShadowTop.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/DiamondSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/DiamondSource.png Binary files differnew file mode 100644 index 0000000..4e43840 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/DiamondSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/DiamondTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/DiamondTarget.png Binary files differnew file mode 100644 index 0000000..18b50ba --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/DiamondTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/PlainArrowSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/PlainArrowSource.png Binary files differnew file mode 100644 index 0000000..8fd1883 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/PlainArrowSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/PlainArrowTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/PlainArrowTarget.png Binary files differnew file mode 100644 index 0000000..cb66797 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/PlainArrowTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/circleSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/circleSource.png Binary files differnew file mode 100644 index 0000000..c897794 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/circleSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/circleTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/circleTarget.png Binary files differnew file mode 100644 index 0000000..aec0926 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/circleTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/dotted2Line.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/dotted2Line.png Binary files differnew file mode 100644 index 0000000..a5d774d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/dotted2Line.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/dottedLine.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/dottedLine.png Binary files differnew file mode 100644 index 0000000..aaa49a7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/dottedLine.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/doubleArrowSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/doubleArrowSource.png Binary files differnew file mode 100644 index 0000000..62d40b8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/doubleArrowSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/doubleArrowTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/doubleArrowTarget.png Binary files differnew file mode 100644 index 0000000..d9b6bd6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/doubleArrowTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/noneSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/noneSource.png Binary files differnew file mode 100644 index 0000000..2ef91c2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/noneSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/noneTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/noneTarget.png Binary files differnew file mode 100644 index 0000000..0505eb1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/noneTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/plainLine.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/plainLine.png Binary files differnew file mode 100644 index 0000000..b4c4c6b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/plainLine.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/simpleArrowSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/simpleArrowSource.png Binary files differnew file mode 100644 index 0000000..c8a0323 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/simpleArrowSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/simpleArrowTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/simpleArrowTarget.png Binary files differnew file mode 100644 index 0000000..ccddf69 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/simpleArrowTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/squareSource.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/squareSource.png Binary files differnew file mode 100644 index 0000000..74d045b --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/squareSource.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/squareTarget.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/squareTarget.png Binary files differnew file mode 100644 index 0000000..95b4add --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/relationshiptype/squareTarget.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/searchBoxBackground.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/searchBoxBackground.jpg Binary files differnew file mode 100644 index 0000000..9d76525 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/searchBoxBackground.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_asc.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_asc.png Binary files differnew file mode 100644 index 0000000..a88d797 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_asc.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_asc_disabled.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_asc_disabled.png Binary files differnew file mode 100644 index 0000000..4e144cf --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_asc_disabled.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_both.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_both.png Binary files differnew file mode 100644 index 0000000..1867040 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_both.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_desc.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_desc.png Binary files differnew file mode 100644 index 0000000..def071e --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_desc.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_desc_disabled.png b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_desc_disabled.png Binary files differnew file mode 100644 index 0000000..7824973 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/sort_desc_disabled.png diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonCenter.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonCenter.jpg Binary files differnew file mode 100644 index 0000000..e5b87d9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonCenter.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonLeft.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonLeft.jpg Binary files differnew file mode 100644 index 0000000..fa0c989 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonLeft.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonRight.jpg b/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonRight.jpg Binary files differnew file mode 100644 index 0000000..3329d70 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/images/styledTabMenuButtonRight.jpg diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/.gitignore b/winery/org.eclipse.winery.repository/src/main/webapp/js/.gitignore new file mode 100644 index 0000000..23c1477 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/.gitignore @@ -0,0 +1,3 @@ +# copied from topology modeler at mvn generate-sources +winery-common-topologyrendering.js +winery-support-common.js
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/boundaryDefinitionsXSelection.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/boundaryDefinitionsXSelection.js new file mode 100644 index 0000000..afefc8c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/boundaryDefinitionsXSelection.js @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + * Tobias Binz - communication with the parent window + *******************************************************************************/ + + /** + * Called from the renderer as soon as the whole topology is loaded + */ + function wineryViewExternalScriptOnLoad() { + + function getIdOfNodeTemplateShape(element) { + var nodeTemplate = element.closest("div.NodeTemplateShape"); + var id = nodeTemplate.children("div.headerContainer").children("div.id").text(); + return id; + } + + jsPlumb.bind("ready", function() { + jsPlumb.bind("click", function(conn, originalEvent) { + var id = winery.connections[conn.id].id; + var message = { + targetRelationshipTemplateRef: id + } + sendMessage(message); + }); + }); + + + $("div.NodeTemplateShape").on("click", function(e) { + var id = getIdOfNodeTemplateShape($(e.target)); + // send id and empty property as no property has been clicked + var message = { + targetObjectRef: id, + targetPropertyRef: "" + }; + sendMessage(message); + + return false; + }); + + $("tr.KVProperty").on("click", function(e) { + var trKVProperty = $(e.target).closest("tr.KVProperty"); + var key = trKVProperty.children("td").children("span.KVPropertyKey").text(); + + var content = trKVProperty.closest("div.content"); + var elementName = content.children("span.elementName").text(); + + // form namespace-unaware XPath + var xpath = "/*[local-name()='" + elementName + "']/*[local-name()='" + key + "']"; + + var message = { + targetPropertyRef: xpath, + targetObjectRef: getIdOfNodeTemplateShape(trKVProperty) + }; + sendMessage(message); + + // do not trigger click on NodeTemplateShape -> we included both values in the message + return false; + }); + + $("div.requirements").on("click", function(e) { + var reqorcap = $(e.target).closest("div.requirements"); + var id = reqorcap.children("div.id").text(); + + var message = { + reqRef: id + }; + sendMessage(message); + + return false; + }); + + $("div.capabilities").on("click", function(e) { + var reqorcap = $(e.target).closest("div.capabilities"); + var id = reqorcap.children("div.id").text(); + + var message = { + capRef: id + }; + sendMessage(message); + + return false; + }); + + } + +function sendMessage(message) { + window.parent.postMessage(message, "*"); +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-audio.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-audio.js new file mode 100644 index 0000000..9b68349 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-audio.js @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-image.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-image.js new file mode 100644 index 0000000..9b68349 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-image.js @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-validate.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-validate.js new file mode 100644 index 0000000..9b68349 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-validate.js @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-video.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-video.js new file mode 100644 index 0000000..9b68349 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/jquery.fileupload-video.js @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/nextselect.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/nextselect.js new file mode 100644 index 0000000..050fcb1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/nextselect.js @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +/* + +Script for dependent selection boxes. + +One object for stating a map from value to content. The value is globally unique. + +Verbose example: +<script> + +var WSDLoperationsData = { + "ns1" : { + "options" : ["ns1:pt11", "ns1:pt12"], + }, + + "ns2" : { + "options" : ["ns2:pt21"], + }, + + "ns3" : { + "options" : ["ns3:pt31"], + }, + + "ns1:pt11" : { + "label" : "PortType 1.1", + "options" : ["ns1:pt11:op111", "ns1:pt11:op112"] + }, + + "ns1:pt12" : { + "label" : "PortType 1.2", + "options" : ["ns1:pt12:op113", "ns1:pt11:op114"] + }, + + + "ns2:pt21" : { + "label" : "PortType 2.1", + "options" : ["ns2:pt21:op211", "ns2:pt21:op212"] + }, + + + "ns3:pt31" : { + "label" : "PortType 3.1", + "options" : ["ns3:pt31:op311", "ns3:pt31:op312"] + }, + + + "ns1:pt11:op111" : { + "label" : "operation 1.1.1", + }, + + "ns1:pt11:op112" : { + "label" : "operation 1.1.2", + }, + + "ns1:pt12:op113" : { + "label" : "operation 1.1.3", + }, + + "ns1:pt12:op114" : { + "label" : "operation 1.1.4", + }, + + "ns2:pt21:op211" : { + "label" : "operation 2.1.1", + }, + + "ns2:pt21:op212" : { + "label" : "operation 2.1.2", + }, + + "ns3:pt31:op311" : { + "label" : "operation 3.1.1", + }, + + "ns3:pt31:op312" : { + "label" : "operation 3.1.2", + } +} + +var WSDLdependendSelects = { + "#portTypes" : "#operations" +} +</script> + +<select size="15" onchange="updateListContent(this.value, '#portTypes', WSDLdependendSelects, WSDLoperationsData);" > + <option value="ns1" selected="true" >Namespace1</option> + <option value="ns2" >Namespace2</option> + <option value="ns3" >Namespace3</option> +</select> + +<select id="portTypes" size="15" onchange="updateListContent(this.value, '#operations', WSDLdependendSelects, WSDLoperationsData);"> + <option value="ns1:pt11" selected="true">PortType1.1</option> + <option value="ns1:pt11">PortType1.2</option> +</select> + +<select id="operations" size="15"> + <option value="ns1:pt11:op111" selected="true">op1.1.2</option> + <option value="ns1:pt12:op112">op1.1.2</option> + <option value="ns1:pt13:op113">op1.1.2</option> +</select> + + */ + +/** + * + * @param value the current selected value + * @param targetElement the select to update + * @param dependendSelects the data structure for subsequently dependent select elements + * @param completeData the data structure with the complete data + */ +function updateListContent(value, targetElement, dependendSelects, completeData) { + jQuery(targetElement).empty(); + var listData = completeData[value]; + if (listData !== undefined) { + for (var i=0; i < listData.options.length; i++) { + var optionName = listData.options[i]; + var label = completeData[optionName].label; + var selected; + if (i == 0) { + selected = ' selected="selected"'; + } else { + selected = ''; + } + var toAppend = '<option value="' + optionName + '"' + selected + '>' + label + '</option>'; + jQuery(targetElement).append(toAppend); + } + nextSelect = dependendSelects[targetElement]; + if (nextSelect !== undefined) { + // We assume listData is not empty + updateListContent(listData.options[0], nextSelect, dependendSelects, completeData); + } + } + jQuery(targetElement).trigger("change"); +} diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/winery-support-non-AMD.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/winery-support-non-AMD.js new file mode 100644 index 0000000..f1f1cfa --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/winery-support-non-AMD.js @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +function addResourceInstance() { + if (highlightRequiredFields()) { + vShowError("Please fill in all required fields"); + return; + } + + var dataToSend = $('#createResourceForm').serialize(); + var cr = $('#createResource'); + $.ajax({ + type: "POST", + async: false, + "data": dataToSend, + "url": cr.data("url"), + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create resource", jqXHR, errorThrown); + cr.modal("hide"); + }, + success: function(resData, textStatus, jqXHR) { + cr.data("onSuccess")($('#createResourceForm').serializeArray(), resData, textStatus, jqXHR); + cr.modal('hide'); + } + }); +} + +/** + * This function creates a dialog, where the user can add key/value pairs. + * These pairs are then sent to the given URL via POST. + * + * REQUIRES <script id="template-createresource" type="text/x-tmpl"> + * Currently placed in header.jsp + * + * @param nameOfResource the name of the resource to add + * @param fields array of label/name/type/hint/checked values to use for the field and to pass in the AJAX call. (optional) type is in "text"/"checkbox"/... -- the values allowed for "type" attributes of <input> fields. Currently, all fields are required. + * @param url the URL to use. The URL is uses as unique ID. If a dialog is requested to be open with a URL and the previous dialog had the same URL, the previous dialog is opened + * @param onSuccess: function(serializedArray, data, textStatus, jqXHR) to call if adding has been successful. "serializedArray" contains the value of $('#formid').serializeArray() + */ +function createResource(nameOfResource, fields, url, onSuccess) { + var cr = $('#createResource'); + if (cr.length == 1) { + if (cr.data("url") == url) { + // the same dialog has been created before. Reuse it + cr.modal("show"); + return; + } else { + // remove the dialog and thus enable the creation of a new one + cr.remove(); + } + } + + var data = { + nameOfResource: nameOfResource, + fields: fields + }; + require(["tmpl"], function(tmpl) { + var div = tmpl("template-createresource", data); + + $("body").append(div); + cr = $('#createResource'); + cr.on("shown.bs.modal", function() { + $("#createResourceForm > fieldset > div:first-child > input").focus(); + }); + + cr.modal('show'); + cr.data("url", url); + cr.data("onSuccess", onSuccess); + }); +} + +/** + * + * @param selection jQuery selection object (<selection>) + * @param value the value of the text to add + * @param text the text to add + */ +function addSortedSelectionItem(selection, value, text) { + var option = selection.children("option:first-child"); + while ((option.length == 1) && (option.text() < text)) { + option = option.next(); + } + var toAppend = '<option value="' + value + '" selected="selected">' + text + '</option>'; + if (option.length == 0) { + selection.append(toAppend); + } else { + option.before(toAppend); + } +} + +/**** begin: for datatable ****/ + +/** + * Uses selected row as information for deleting on server (and on success deleting in table) + * + * the id of the thing to delete is read from the first column of the table + * + * @param tableInfo: info object about table + * @param nameOfThingToDelete: used at messages + * @param baseURL: used to form URL by baseURL+<name of thing> + * @param idColumn: (optional) column to look for the id. If not provided, look in the first column + * @param nameColumn: (optional) column to look for a name. If not provided, the id is used + * @param namespaceColumn: (optional) column to look for a namespace. If not provided, do not use any nameespace information + * @param withoutConfirmation (optional) if given, the resource is deleted without any confirmation +*/ +function deleteOnServerAndInTable(tableInfo, nameOfThingToDelete, baseURL, idColumn, nameColumn, namespaceColumn, withoutConfirmation) { + if (tableInfo.selectedRow == null) { + vShowError("No row selected."); + } else { + idColumn = idColumn || 0; // default: first column indicates identifier + var id = tableInfo.table.fnGetData(tableInfo.selectedRow, idColumn); + var name; + if (typeof nameColumn === "undefined") { + name = id; + } else { + name = tableInfo.table.fnGetData(tableInfo.selectedRow, nameColumn); + } + + var url = baseURL; + if (typeof namespaceColumn !== "undefined") { + var namespace = tableInfo.table.fnGetData(tableInfo.selectedRow, namespaceColumn); + namespace = encodeID(namespace); + url = url + namespace + '/'; + } + // append the id + // we could add a "/" to be compatible with Jersey's URL rewriting + // However, that prevents deleting a thing being a leaf in the URL (e.g. a namespace) + url = url + encodeID(id); + + // defined in winery-common.js + deleteResource(nameOfThingToDelete + " " + name, url, + function(data, textSTatus, jqXHR) { + tableInfo.table.fnDeleteRow(tableInfo.selectedRow); + tableInfo.selectedRow = null; + tableInfo.selectedTr = null; + }, false, false, withoutConfirmation + ); + } +} + +/**** end: for datatable ****/ + +/** + * Uploads the content of given form to given url + * + * @param form specifies the form to read data from + * @param url specifies the URL to send the data to + * @param onSuccess: function(XMLHttpRequest) to handle result + */ +function uploadFile(form, url, onSuccess) { + var xhr = new XMLHttpRequest(); + var fd = new FormData(form); + xhr.onreadystatechange = function(e) { + if (this.readyState == 4) { + if ((xhr.status != 200) && (xhr.status != 201)) { + alert("Upload error occurred: " + xhr.status); + } else { + onSuccess(xhr); + } + } + }; + xhr.open('post', url, true); + xhr.send(fd); +} + +/** + * PUTs given value to the server in the BODY + * + * @param thing the thing to send. used as URL and in the error messages + */ +function updateValue(thing, value) { + $.ajax({ + type: "PUT", + async: false, + url: thing, + "data": value, + dataType: "text", + processData: false, // leads to a send in the body + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not set " + thing, jqXHR, errorThrown); + }, + success: function() { + vShowSuccess("Successfully updated " + thing); + } + }); +} + +/** + * Puts the color to visualappearance/{id} + * + * Required by visualappearance.jsp (node type and relation ship type) + * + * @param id + */ +function putColor(id, hex) { + var dataToSend = { + "color" : hex + }; + $.ajax({ + type : "PUT", + async : false, + url : "visualappearance/" + id, + "data" : dataToSend, + dataType : "text", + error : function(jqXHR, textStatus, errorThrown) { + vShowError("Could not set color " + errorThrown); + }, + success: function(data, textStatus, jqXHR) { + vShowSuccess("Successfully updated color"); + } + }); +} + diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/js/winery-support.js b/winery/org.eclipse.winery.repository/src/main/webapp/js/winery-support.js new file mode 100644 index 0000000..0459235 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/js/winery-support.js @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +/* no name given as RequireJS' documentatio says that makes modules less portable */ +define(["datatables"], function() { + /* + * Valid chars: See + * <ul> + * <li>http://www.w3.org/TR/REC-xml-names/#NT-NCName</li> + * <li>http://www.w3.org/TR/REC-xml/#NT-Name</li> + * </ul> + */ + // NameCharRange \u10000-\ueffff is not supported by Java + var NCNameStartChar_RegExp = "[A-Z_a-z\u00c0-\u00d6\u00d8\u00f6\u00f8\u02ff\u0370\u037d\u037f-\u1fff\u200c-\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]"; + var NCNameChar_RegExp = NCNameStartChar_RegExp + "|[-\\.0-9\u00B7\u0300-\u036F\u203F-\u2040]"; + var NCName_RegExp = NCNameStartChar_RegExp + "(" + NCNameChar_RegExp + ")*"; + var QName_RegExp = "(" + NCName_RegExp + ":)?(" + NCName_RegExp + ")"; + + var NCNameStartChar_Pattern = new RegExp(NCNameStartChar_RegExp); + var NCNameChar_Pattern = new RegExp(NCNameChar_RegExp); + + /** + * Initializes a table (and updates tableInfo) + * * adds selection capability + * + * @param info.id: id of the table (with #) + * @param paramsForDataTable: additional parameters for dataTable() + * @param afterInit function to be called after dataTables object initalization happened + * + * @returns initialized info object + * * info.table is updated with a pointer to the data table + * * info.selectedTr is set to null + */ + function initTable(info, paramsForDataTable, afterInit) { + paramsForDataTable = paramsForDataTable || {}; + + $(info.id).click(function(event) { + if (info.selectedTr != null) { + info.selectedTr.removeClass('row_selected'); + } + var row = $(event.target.parentNode); + if ((info.selectedTr != null) && (info.selectedTr[0] == row[0])) { + // row is deselected if selected again + info.selectedRow = null; + info.selectedTr = null; + } else { + info.selectedTr = row; + info.selectedTr.addClass('row_selected'); + info.selectedRow = event.target.parentNode; + } + }); + info.selectedTr = null; + info.table = $(info.id).dataTable(paramsForDataTable); + if (afterInit) afterInit(); + } + + /** + * Function to determine whether a data table described with the tableInfo object is empty + * + * @param tableInfo the table info object describing the table + * @returns true if the table is empty, false otherwise + */ + function isEmptyTable(tableInfo) { + return tableInfo.table.children("tbody").children("tr").first().children("td").hasClass("dataTables_empty"); + } + + /** + * JavaScript implementation of org.eclipse.winery.common.Util.makeNCName(String) + */ + function makeNCName(text) { + if (!text || text == "") { + return text; + } + + var res = ""; + + var start = text.substr(0, 1); + if (NCNameStartChar_Pattern.test(start)) { + res += start; + } else { + res += "_"; + } + + for (var i=1; i<text.length; i++) { + var c = (text.substr(i, 1)); + if (NCNameChar_Pattern.test(c)) { + res += c; + } else { + res += "_"; + } + } + return res; + } + + var module = { + initTable: initTable, + isEmptyTable: isEmptyTable, + makeNCName: makeNCName, + QName_RegExp: QName_RegExp + }; + return module; + } +); diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/adminindex.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/adminindex.jsp new file mode 100644 index 0000000..c7ee9f7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/adminindex.jsp @@ -0,0 +1,41 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#namespaces", "Namespaces"); +subMenus.add(data); + +data = new SubMenuData("#repository", "Repository"); +subMenus.add(data); + +data = new SubMenuData("#planlanguages", "Plan Languages"); +subMenus.add(data); + +data = new SubMenuData("#plantypes", "Plan Types"); +subMenus.add(data); + +data = new SubMenuData("#constrainttypes", "Constraint Types"); +subMenus.add(data); +%> + +<%-- TODO: do not use componentinstance, but introduce a layer inbetween componentinstance.tag and genericpage.tag --%> + +<t:componentinstance windowtitle="Admin" cssClass="mainContentContainer admin" selected="admin" subMenus="<%=subMenus%>"> +</t:componentinstance> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/namespaces.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/namespaces.jsp new file mode 100644 index 0000000..e80ad1d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/namespaces.jsp @@ -0,0 +1,108 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="http://www.eclipse.org/winery/repository/functions" prefix="w" %> +<script> +var namespacePrefixesTableInfo = { + id : '#namespacePrefixesTable' +}; + +$(function() { + require(["winery-support"], function(ws) { + ws.initTable(namespacePrefixesTableInfo); + }); +}); + +function addNSprefix() { + $.ajax({ + url: "${pageContext.request.contextPath}/admin/namespaces/", + type: "POST", + async: false, + data: $('#addNamespacePrefixForm').serialize(), + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add namespace prefix", jqXHR, errorThrown); + }, + success: function(data, textSTatus, jqXHR) { + namespacePrefixesTableInfo.table.fnAddData([$('#nsPrefixAdded').val(), $('#namespaceAdded').val()]); + $('#addNamespacePrefixDiag').modal('hide'); + vShowSuccess("Successfully added namespace prefix."); + } + }); +} + +</script> + +<div class="modal fade" id="addNamespacePrefixDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add namespace prefix</h4> + </div> + <div class="modal-body"> + <form id="addNamespacePrefixForm" enctype="multipart/form-data"> + <fieldset> + <div class="form-group"> + <label for="nsPrefixAdded">Prefix</label> + <input name="nsPrefix" id="nsPrefixAdded" class="form-control" type="text" /> + </div> + + <div class="form-group"> + <label for="namespaceAdded">Namespace</label> + <input name="namespace" id="namespaceAdded" class="form-control" type="text" /> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" onclick="addNSprefix()">Add</button> + </div> + </div> + </div> +</div> + +<div id="namespaces"> + <div class="listheading"> + <label>Defined Prefixes for Namespaces</label> + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOnServerAndInTable(namespacePrefixesTableInfo, 'namespace', 'namespaces/', 1);">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="$('#addNamespacePrefixDiag').modal('show')">Add</button> + </div> + <table cellpadding="0" cellspacing="0" border="0" class="display" id="namespacePrefixesTable"> + <thead> + <tr> + <th>Prefix</th> + <th>Namespace</th> + </tr> + </thead> + <tbody> + <c:forEach var="ns" items="${it.namespacesForJSP}"> + <tr> + <td class="prefix">${w:getPrefix(ns.decoded)}</td> + <td>${ns.decoded}</td> + </tr> + </c:forEach> + </tbody> + </table> +</div> + +<script> +$(document).on("click", "td.prefix", + vCreateTdClickFunction( + "${pageContext.request.contextPath}/admin/namespaces/", + "nsPrefix", + "namespace")); +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/repository.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/repository.jsp new file mode 100644 index 0000000..446bd46 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/repository.jsp @@ -0,0 +1,101 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<h4>General Repository Commands</h4> +<div> + <a href="repository/?dump" class="btn btn-primary">Dump Repository</a> + <button class="btn btn-danger" onclick="clearRepository();" id="btnclearrepository" data-loading-text="Deleting...">Clear Repository</button> + <button class="btn btn-default" onclick="$('#upRepoZipDiag').modal('show');">Import Repository</button> +</div> + +<% +org.eclipse.winery.repository.backend.IRepository rep; +rep = org.eclipse.winery.repository.Prefs.INSTANCE.getRepository(); +boolean isGitBasedRepo = (rep instanceof org.eclipse.winery.repository.backend.filebased.GitBasedRepository); + +org.eclipse.winery.repository.backend.filebased.GitBasedRepository repo = null; +if (isGitBasedRepo) { + repo = (org.eclipse.winery.repository.backend.filebased.GitBasedRepository) rep; +} + +// We only support the commit and reset buttons if we can authenticate at the repository +// This is a hack to offer different versions of winery at dev.winery.opentosca.org and winery.opentosca.org +isGitBasedRepo = isGitBasedRepo && (repo.authenticationInfoAvailable()); + +if (isGitBasedRepo) { +%> +<h4>Versioning</h4> +<div> +<button id="commitBtn" class="btn btn-default" onclick="doCommit();" data-loading-text="committing...">Commit</button> +<button id="resetBtn" class="btn btn-danger" onclick="doReset();" data-loading-text="resetting...">Reset</button> +</div> + +<script> +function doCommit() { + $("#commitBtn").button("loading"); + $.ajax({ + url: "repository/?commit", + async: false, + error: function(jqXHR, textStatus, errorThrown) { + $("#commitBtn").button("reset"); + vShowAJAXError("Could not commit", jqXHR, errorThrown); + }, + success: function(data, textSTatus, jqXHR) { + $("#commitBtn").button("reset"); + vShowSuccess("Successfully committed changes."); + } + }); +} + +function doReset() { + $("#resetBtn").button("loading"); + $.ajax({ + url: "repository/?reset", + async: false, + error: function(jqXHR, textStatus, errorThrown) { + $("#resetBtn").button("reset"); + vShowAJAXError("Could not reset", jqXHR, errorThrown); + }, + success: function(data, textSTatus, jqXHR) { + $("#resetBtn").button("reset"); + vShowSuccess("Successfully reset to last known state."); + } + }); +} +</script> +<% +} +%> + +<t:simpleSingleFileUpload + title="Upload Repository Content" + text="Repository dump file" + URL="repository/" + type="POST" + id="upRepoZip" + accept="application/zip" /> + +<script> +function clearRepository() { + deleteResource('the complete repository', 'repository/', + function() {$("#btnclearrepository").button("reset");}, + function() {$("#btnclearrepository").button("reset");}, + function() {$("#btnclearrepository").button("loading");} + ); +} +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/types/types.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/types/types.jsp new file mode 100644 index 0000000..25b2e0f --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/admin/types/types.jsp @@ -0,0 +1,105 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<div class="listheading"> + <button class="rightbutton btn btn-danger btn-sm" type="button" onclick="deleteOnServerAndInTable(typesTableInfo, 'Type', '${it.URL}', 1);">Remove</button> + <button class="rightbutton btn btn-primary btn-sm" type="button" onclick="$('#addTypeShortnameDiag').modal('show');">Add</button> +</div> + +<table id="typeswithshortnametable"> + +<thead> + <tr> + <th>Short name</th> + <th>Long Name</th> + </tr> +</thead> + +<tbody> + <c:forEach var="type" items="${it.types}"> + <tr> + <td class="shortname editable">${type.shortName}</td> + <td>${type.type}</td> + </tr> + </c:forEach> +</tbody> + +</table> + + +<div class="modal fade" id="addTypeShortnameDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add short name</h4> + </div> + <div class="modal-body"> + <form id="addTypeShortnameForm" enctype="multipart/form-data"> + <fieldset> + <div class="form-group"> + <label for="shortname">Short name</label> + <input name="shortname" id="shortname" class="form-control" type="text" /> + </div> + <div class="form-group"> + <label for="type">Type</label> + <input name="type" id="type" class="form-control" type="text" /> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" onclick="addShortNameAndType();">Add</button> + </div> + </div> + </div> +</div> + + +<script> +$(document).on("click", "td.shortname", + vCreateTdClickFunction( + "${it.URL}", + "shortname", + "type")); + +var typesTableInfo = { + id: '#typeswithshortnametable' +}; +require(["winery-support"], function(ws) { + ws.initTable(typesTableInfo); +}); + +function addShortNameAndType() { + $.ajax({ + url: "${it.URL}", + type: "POST", + async: false, + data: $('#addTypeShortnameForm').serialize(), + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add type information", jqXHR, errorThrown); + }, + success: function(data, textSTatus, jqXHR) { + typesTableInfo.table.fnAddData([$('#shortname').val(), $('#type').val()]); + $('#addTypeShortnameDiag').modal('hide'); + vShowSuccess("Successfully added type information."); + } + }); +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/artifacts/artifacts.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/artifacts/artifacts.jsp new file mode 100644 index 0000000..89b6fca --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/artifacts/artifacts.jsp @@ -0,0 +1,141 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@taglib prefix="v" uri="http://www.eclipse.org/winery/repository/functions"%> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> + +<%-- +Parameter +isDeploymentArtifact: true/false +--%> + +<script> +var artifactsTableInfo = { + id : '#artifactsTable' +}; + +<c:choose> + <c:when test="${it.isDeploymentArtifacts}"> + <c:set var="URL" value="deploymentartifacts/" /> + <c:set var="name" value="Deployment" /> + <c:set var="interfacesOfAssociatedType" value="<%=null%>" /> + </c:when> + <c:otherwise> + <c:set var="URL" value="implementationartifacts/" /> + <c:set var="name" value="Implementation" /> + <c:set var="interfacesOfAssociatedType" value="${it.interfacesOfAssociatedType}" /> + </c:otherwise> +</c:choose> + + +$(function() { + require(["winery-support"], function(ws) { + ws.initTable(artifactsTableInfo); + }); + <jsp:include page="/jsp/setupTriggerRemoveByDELKey.jsp" /> +}); + +/** + * This function directly accesses the fields of the dialog, because the return value of the server is XML and we do not want to parse XML + * + * @param artifactInfo = {name, interfaceName (may be undefined), operationName (may be undefined), artifactTemplate (QName, may be undefined), artifactTemplateName (may be undefined), artifactType} + */ +function artifactAddedSuccessfully(artifactInfo) { + require(["winery-support-common"], function(wsc) { + var data = [artifactInfo.name<c:if test="${not it.isDeploymentArtifacts}">, artifactInfo.interfaceName, artifactInfo.operationName</c:if>]; + + // artifactTemplate + var link = ""; + if (artifactInfo.artifactTemplate) { + var nsAndId = wsc.getNamespaceAndLocalNameFromQName(artifactInfo.artifactTemplate); + link = '<a href="'; + link = link + makeArtifactTemplateURL("${pageContext.request.contextPath}", nsAndId.namespace, nsAndId.localname); + link = link + '">'; + link = link + artifactInfo.name; + link = link + "</a>"; + } + // table field has to be filled even if no artifact template has been created + data.push(link); + + // artifactType + var href = wsc.makeArtifactTypeURLFromQName("${pageContext.request.contextPath}", artifactInfo.artifactType); + link = '<a href="'; + link = link + href; + link = link + '">'; + link = link + wsc.getNamespaceAndLocalNameFromQName(artifactInfo.artifactType).localname; + link = link + "</a>"; + data.push(link); + + // artifactSpecificContent is emtpy as we do not allow addition of it in the UI + data.push(""); + + artifactsTableInfo.table.fnAddData(data); + }); +} + +</script> + +<ct:artifactcreationdialog + onSuccessfulArtifactCreationFunction="artifactAddedSuccessfully" + isDeploymentArtifact="${it.isDeploymentArtifacts}" + interfacesOfAssociatedType="${interfacesOfAssociatedType}" + name="${name}" + allArtifactTypes="${it.allArtifactTypes}" + URL="'${URL}'" + repositoryURL="${pageContext.request.contextPath}" + allNamespaces="${v:allNamespaces()}" + defaultNSForArtifactTemplate="TODO" +/> + +<div id="artifacts"> + <div class="listheading"> + <label>Available ${name} Artifacts</label> + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOnServerAndInTable(artifactsTableInfo, '${name} Artifact', '${URL}');">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="openAdd${name}ArtifactDiag();">Add</button> + </div> + <table cellpadding="0" cellspacing="0" border="0" class="display" id="artifactsTable"> + <thead> + <tr> + <th>Name</th> + <c:if test="${not it.isDeploymentArtifacts}"> + <th>Interface Name</th> + <th>Operation Name</th> + </c:if> + <th>Artifact Template</th> + <th>Artifact Type</th> + <th>Specific Content</th> + </tr> + </thead> + <tbody> + <c:forEach var="a" items="${it.allArtifactResources}"> + <tr> + <td>${a.a.name}</td> + <c:if test="${not it.isDeploymentArtifacts}"> + <td>${a.a.interfaceName}</td> + <td>${a.a.operationName}</td> + </c:if> + <td><c:if test="${not empty a.a.artifactRef}"><a href="${pageContext.request.contextPath}/artifacttemplates/${v:DoubleURLencode(a.a.artifactRef)}/">${a.a.artifactRef.localPart}</a></c:if></td> + <td><a href="${pageContext.request.contextPath}/artifacttypes/${v:DoubleURLencode(a.a.artifactType)}">${a.a.artifactType.localPart}</a></td> + <td><c:if test="${not empty a.a.any}"> + <!-- TODO: convert to bootstrap <a href="javascript: $.msgBox({title: 'Artifact Specific Content', content: '${v:doubleEscapeHTMLAndThenConvertNL2BR(a.a.any)}', type: 'info'});">show</a> --> + (exists) + </c:if></td> + + </tr> + </c:forEach> + </tbody> + </table> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/componentnaming.jspf b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/componentnaming.jspf new file mode 100644 index 0000000..877e60c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/componentnaming.jspf @@ -0,0 +1,28 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%-- + +Heading for a selected component (service template, node type, relationship type) + +Displays name + namespace + +--%> +<div class="informationContainer"> + <div class="name"> + ${it.name} + </div> + <div class="namespace"> + ${it.namespace} + </div> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/documentation.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/documentation.jsp new file mode 100644 index 0000000..55946a1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/documentation.jsp @@ -0,0 +1,87 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions" %> + +<%-- TODO: source (external documentation) and lang attributes not yet supported --%> + +<c:if test="${empty it}"> + <div class="form-group"> + <div class="form-control" id="documentation"></div> + </div> + <script> + $("#documentation").editable({ + type: "wysihtml5", + send: "always", + success: function(response, newValue) { + $.ajax({ + type: "POST", + async: false, + "data": newValue, + "url": "documentation/", + dataType: "text", + contentType: "text/html", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create documentation", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + vShowSuccess("Successfully created the documentation"); + doTheTabSelection(); + } + }); + } + }); + </script> +</c:if> + + +<c:if test="${not empty it}"> + <script>var documentationURL = {};</script> + <c:forEach var="documentation" items="${it}" varStatus="status"> + <div class="form-group"> + <%-- we only print a heading if we have multiple documentations. Otherwise, the documentation itself should be displayed --%> + <c:if test="${fn:length(it) > 1}"><label class="label-form">Documentation ${status.index}</label></c:if> + <div class="form-control" id="documentation${status.index}"> + <c:forEach items="${documentation.content}" var="content">${content}</c:forEach> + </div> + </div> + <c:set var="text" value="${w:XML(documentation)}"></c:set><!-- required to calculate the hashCode --> + <c:set var="hash" value="<%=pageContext.getAttribute(\"text\").hashCode()%>"></c:set> + <script> + documentationURL[${status.index}] = "documentation/${hash}"; + $("#documentation${status.index}").editable({ + type: "wysihtml5", + send: "always", + success: function(response, newValue) { + $.ajax({ + type: "PUT", + async: false, + "data": newValue, + "url": documentationURL[${status.index}], + dataType: "text", + contentType: "text/html", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not update documentation", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + vShowSuccess("Successfully updated the documentation"); + documentationURL[${status.index}] = "documentation/" + resData; + } + }); + } + }); + </script> + </c:forEach> +</c:if> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/artifacttemplates/artifacttemplate.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/artifacttemplates/artifacttemplate.jsp new file mode 100644 index 0000000..60f95f2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/artifacttemplates/artifacttemplate.jsp @@ -0,0 +1,32 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#files", "Files"); +subMenus.add(data); + +data = new SubMenuData("#properties", "Properties"); +subMenus.add(data); +%> + +<t:componentinstancewithName cssClass="artifactTemplate" selected="ArtifactTemplate" subMenus="<%=subMenus%>" type="${w:artifactTypeQName2href(it.type)}"> +</t:componentinstancewithName> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/artifacttemplates/files.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/artifacttemplates/files.jsp new file mode 100644 index 0000000..1c06254 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/artifacttemplates/files.jsp @@ -0,0 +1,18 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> + +<%@taglib prefix="fup" tagdir="/WEB-INF/tags/common"%> + +<fup:jquery-file-upload-full loadexistingfiles="true"></fup:jquery-file-upload-full> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/policytemplates/policytemplate.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/policytemplates/policytemplate.jsp new file mode 100644 index 0000000..e0e340c --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/policytemplates/policytemplate.jsp @@ -0,0 +1,29 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#properties", "Properties"); +subMenus.add(data); +%> + +<t:componentinstancewithName cssClass="policyTemplate" selected="PolicyTemplate" subMenus="<%=subMenus%>" type="${w:policyTypeQName2href(it.type)}"> +</t:componentinstancewithName> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/properties.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/properties.jsp new file mode 100644 index 0000000..61134f2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytemplates/properties.jsp @@ -0,0 +1,92 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> + +<%@page import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TEntityType"%> +<%@page import="org.eclipse.winery.common.ModelUtilities"%> +<%@page import="org.eclipse.winery.repository.Utils"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="props" tagdir="/WEB-INF/tags/common/templates" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> + +<script type="text/javascript" src="${pageContext.request.contextPath}/components/XMLWriter/XMLWriter.js"></script> + +<style> + div.header { + display: none; + } + span.elementName { + display: none; + } + span.namespace { + display: none; + } +</style> + +<props:propertiesBasic></props:propertiesBasic> + +<c:set var="type" value="${w:typeForTemplate(it.template)}" /> + +<div id="containerForPropertiesContainer"> +<div> <%-- This div is required by props:properties to be consistent with a node template. This mirrors div class="content" --%> +<props:properties + propertiesDefinition="${type.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(type)}" + template="${it.template}" + pathToImages="${w:topologyModelerURI()}/images/"> +</props:properties> +</div> +</div> + +<c:choose> + <c:when test="${not empty type.propertiesDefinition or not empty wc:winerysPropertiesDefinition(type)}"> + <button id="propsSaveBtn" data-loading-text="Saving..." type="button" class="btn btn-primary btn-sm" onclick="saveProperties();">Save</button> + </c:when> + <c:otherwise> + The type does not have a “properties definition”. + </c:otherwise> +</c:choose> + +<script> +$(".KVPropertyValue").editable(); + +// similar to topology modeler's index.jsp save() function +function saveProperties() { + $("#propsSaveBtn").button('loading'); + var w = new XMLWriter("utf-8"); + w.writeStartDocument(); + var divContainer = $("#containerForPropertiesContainer"); + savePropertiesFromDivToXMLWriter(divContainer.children("div").children(".propertiesContainer"), w, true); + w.writeEndDocument(); + + $.ajax({ + url: "properties/", + type: "PUT", + contentType: 'text/xml', + data: w.flush(), + success: function(data, textStatus, jqXHR) { + $("#propsSaveBtn").button('reset'); + vShowSuccess("successfully saved."); + }, + error: function(jqXHR, textStatus, errorThrown) { + $("#propsSaveBtn").button('reset'); + vShowAJAXError("Could not save", errorThrown, jqXHR.responseText); + } + }); + +} +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypeimplementations/nodetypeimplementations/nodetypeimplementation.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypeimplementations/nodetypeimplementations/nodetypeimplementation.jsp new file mode 100644 index 0000000..eec30c2 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypeimplementations/nodetypeimplementations/nodetypeimplementation.jsp @@ -0,0 +1,33 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#implementationartifacts", "Implementation Artifacts"); +subMenus.add(data); + +data = new SubMenuData("#deploymentartifacts", "Deployment Artifacts"); +subMenus.add(data); + +%> + +<t:componentinstancewithNameDerivedFromAbstractFinal cssClass="nodeTypeImplementation" selected="NodeTypeImplementation" subMenus="<%=subMenus%>" implementationFor="${w:nodeTypeQName2href(it.type)}"> +</t:componentinstancewithNameDerivedFromAbstractFinal> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypeimplementations/relationshiptypeimplementations/relationshiptypeimplementation.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypeimplementations/relationshiptypeimplementations/relationshiptypeimplementation.jsp new file mode 100644 index 0000000..97a9ad5 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypeimplementations/relationshiptypeimplementations/relationshiptypeimplementation.jsp @@ -0,0 +1,29 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib uri="http://www.eclipse.org/winery/repository/functions" prefix="w" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#implementationartifacts", "Implementation Artifacts"); +subMenus.add(data); +%> + +<t:componentinstancewithNameDerivedFromAbstractFinal cssClass="relationshipTypeImplementation" selected="RelationshipTypeImplementation" subMenus="<%=subMenus%>" implementationFor="${w:nodeTypeQName2href(it.type)}"> +</t:componentinstancewithNameDerivedFromAbstractFinal> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/artifacttypes/artifacttype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/artifacttypes/artifacttype.jsp new file mode 100644 index 0000000..c51630a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/artifacttypes/artifacttype.jsp @@ -0,0 +1,26 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%-- +TODO: implement update / subresource "file extension" +<div class="center">Associated File Extension</div> + + <div class="middle" id="ccontainer"> + <input name="fileextension" type="text" onblur="updateValue('fileextension', this.value)" <c:if test="${not empty it.associatedFileExtension}"> value="${it.associatedFileExtension}" </c:if> /> + </div> +--%> + +<t:entitytype cssClass="artifactType" selected="ArtifactType"> +</t:entitytype> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/capabilitytypes/capabilitytype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/capabilitytypes/capabilitytype.jsp new file mode 100644 index 0000000..2e2b2f0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/capabilitytypes/capabilitytype.jsp @@ -0,0 +1,17 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<t:entitytype cssClass="capabilityType" selected="CapabilityType"> +</t:entitytype> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/implementations.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/implementations.jsp new file mode 100644 index 0000000..46ef5a8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/implementations.jsp @@ -0,0 +1,63 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<t:addComponentInstance + label="${it.typeStr} Implementation" + URL="${pageContext.request.contextPath}/${it.type}implementations/" + onSuccess="implementationsTableInfo.table.fnAddData([$(\"#addComponentInstanceForm :input[name='namespace']\").val(), $(\"#addComponentInstanceForm :input[name='name']\").val()]);" + type="${it.typeId.QName}" + openinnewwindow="false" + /> + +<script> +var implementationsTableInfo = { + id: '#implementationsTable' +}; + +require(["winery-support"], function(ws) { + ws.initTable(implementationsTableInfo, { + "aoColumns": [ + { "sTitle": "namespace" }, + { "sTitle": "name" } + ], + "aaData" : ${it.implementationsTableData} + }); +}); + + function openImplementationEditor() { + var namespace = implementationsTableInfo.table.fnGetData(implementationsTableInfo.selectedRow,0); + var id = implementationsTableInfo.table.fnGetData(implementationsTableInfo.selectedRow,1); + window.open("${pageContext.request.contextPath}/${it.type}implementations/" + encodeID(namespace) + "/" + encodeID(id), "_self"); + } + +</script> + +<p> +This page shows implementations available for this type. +Go to <a href="${pageContext.request.contextPath}/other/">Other Elements</a> to get an overview on all implementations stored in this repository. +</p> + + <div id="implementations"> + + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOnServerAndInTable(implementationsTableInfo, '${it.typeStr} Implementation', '${pageContext.request.contextPath}/${it.type}implementations/', 1, 1, 0);">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="openNewCIdiag();">Add</button> + <button class="rightbutton btn btn-default btn-xs" type="button" onclick="openImplementationEditor();">Edit</button> + + <table cellpadding="0" cellspacing="0" border="0" class="display" id="implementationsTable"></table> + </div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/instancestates.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/instancestates.jsp new file mode 100644 index 0000000..059ae55 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/instancestates.jsp @@ -0,0 +1,86 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + +<div class="modal fade" id="addStateDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add State</h4> + </div> + <div class="modal-body"> + <form id="addPropertyForm" enctype="multipart/form-data" method="post"> + <div class="row"> + <label> + State: <input name="state" id="state" type="text" /> + </label> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" data-dismiss="modal" onclick="createState();">Add</button> + </div> + </div> + </div> +</div> + +<div id="Properties"> + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOnServerAndInTable(propertiesTableInfo, 'InstanceState', 'instancestates/');">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="$('#addStateDiag').modal('show');">Add</button> + + <table cellpadding="0" cellspacing="0" border="0" class="display" id="propertiesTable"> + <thead> + <tr> + <th>State</th> + </tr> + </thead> + <tbody> + <c:forEach var="t" items="${it.instanceStates}"> + <tr> + <td>${t}</td> + </tr> + </c:forEach> + </tbody> + </table> +</div> + +<script> +var propertiesTableInfo = { + id: '#propertiesTable' +}; + +require(["winery-support"], function(ws) { + ws.initTable(propertiesTableInfo); +}); + +function createState() { + $.ajax({ + url: "instancestates/", + type: "POST", + async: false, + data: $('#addPropertyForm').serialize(), + error: function(jqXHR, textStatus, errorThrown) { + vShowError("Could not add instancestate: " + errorThrown + "<br/>" + jqXHR.responseText); + }, + success: function(data, textStatus, jqXHR) { + var dataToAdd = [$('#state').val()]; + propertiesTableInfo.table.fnAddData(dataToAdd); + $('#addStateDiag').modal('hide'); + } + }); +} +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/nodetype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/nodetype.jsp new file mode 100644 index 0000000..f9d52d7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/nodetype.jsp @@ -0,0 +1,44 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#visualappearance", "Visual Appearance"); +subMenus.add(data); + +data = new SubMenuData("#instancestates", "Instance States"); +subMenus.add(data); + +data = new SubMenuData("#interfaces", "Interfaces"); +subMenus.add(data); + +data = new SubMenuData("#implementations", "Implementations"); +subMenus.add(data); + +data = new SubMenuData("#requirementdefinitions", "Requirement Definitions"); +subMenus.add(data); + +data = new SubMenuData("#capabilitydefinitions", "Capability Definitions"); +subMenus.add(data); + +%> + +<t:entitytype cssClass="nodeType" selected="NodeType" subMenus="<%=subMenus%>" image="true" twolines="true"> +</t:entitytype> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/reqandcapdefs/capdefs.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/reqandcapdefs/capdefs.jsp new file mode 100644 index 0000000..7f2cc7d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/reqandcapdefs/capdefs.jsp @@ -0,0 +1,17 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags/entitytypes/nodetypes/reqandcapdefs" %> + +<t:reqandcapdefs allTypes="${it.allTypes}" allSubResources="${it.allEntityResources}" url="capabilitydefinitions/" labelForSingleItem="Capability Definition" typeClass="<%=org.eclipse.winery.model.tosca.TCapabilityType.class%>"/> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/reqandcapdefs/reqdefs.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/reqandcapdefs/reqdefs.jsp new file mode 100644 index 0000000..08657a1 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/reqandcapdefs/reqdefs.jsp @@ -0,0 +1,17 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags/entitytypes/nodetypes/reqandcapdefs" %> + +<t:reqandcapdefs allTypes="${it.allTypes}" allSubResources="${it.allEntityResources}" url="requirementdefinitions/" labelForSingleItem="Requirement Definition" typeClass="<%=org.eclipse.winery.model.tosca.TRequirementType.class%>"/> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/visualappearance.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/visualappearance.jsp new file mode 100644 index 0000000..b432be6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/nodetypes/visualappearance.jsp @@ -0,0 +1,68 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<script type='text/javascript' src='${pageContext.request.contextPath}/components/raphael/raphael.js'></script> +<script type='text/javascript' src='${pageContext.request.contextPath}/components/colorwheel/javascripts/colorwheel.js'></script> + +<script> +<%-- Required for multiple upload dialogs + see https://github.com/blueimp/jQuery-File-Upload/wiki/Options --%> +$(document).bind('drop dragover', function (e) { + e.preventDefault(); +}); +</script> + +<ul class="nav nav-tabs" id="myTab"> + <li class="active"><a href="#icons">Icons</a></li> + <li><a href="#color">Color</a></li> +</ul> + +<div class="tab-content"> + <div class="tab-pane active" id="icons"> + <br /> + <t:imageUpload + label="Icon (16x16) used in palette" + URL="visualappearance/16x16" + id="upSmall" + width="16px" + resize="16" + accept="image/*"/> + + <t:imageUpload + label="Icon (50x50) used in the node template shapes" + URL="visualappearance/50x50" + id="upBig" + width="50px" + resize="50" + accept="image/*"/> + </div> + <div class="tab-pane" id="color"> + <br /> + <form> + <fieldset> + <t:colorwheel label="Border Color" color="${it.borderColor}" id="bordercolor" url="bordercolor" /> + </fieldset> + </form> + </div> +</div> + +<script> +$('#myTab a').click(function (e) { + e.preventDefault(); + $(this).tab('show'); +}); +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/appliesto.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/appliesto.jsp new file mode 100644 index 0000000..ff15a39 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/appliesto.jsp @@ -0,0 +1,25 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + +<c:if test="${empty it.policyType.appliesTo.nodeTypeReference}">–</c:if> + +<ul> +<c:forEach items="${it.policyType.appliesTo.nodeTypeReference}" var="nodeTypeReference"> +<li>${nodeTypeReference.typeRef}</li> +</c:forEach> +</ul> + + +Update not yet implemented. diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/language.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/language.jsp new file mode 100644 index 0000000..c1815bd --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/language.jsp @@ -0,0 +1,21 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + +<c:choose> + <c:when test="${empty it.language}">–</c:when> + <c:otherwise>${it.language}</c:otherwise> +</c:choose> + +Update not yet implemented. diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/policytype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/policytype.jsp new file mode 100644 index 0000000..694abad --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/policytypes/policytype.jsp @@ -0,0 +1,32 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#language", "Language"); +subMenus.add(data); + +data = new SubMenuData("#appliesto", "Applies To"); +subMenus.add(data); + +%> + +<t:entitytype cssClass="policyType" selected="PolicyType" subMenus="<%=subMenus%>"> +</t:entitytype> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/properties/propertiesDefinition.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/properties/propertiesDefinition.jsp new file mode 100644 index 0000000..a0e22df --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/properties/propertiesDefinition.jsp @@ -0,0 +1,320 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags"%> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common"%> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<%-- createResource of winery-support.js could be used. However, currently selects are not supported --%> +<div class="modal fade" id="addPropertyDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add Property</h4> + </div> + <div class="modal-body"> + <form id="addPropertyForm"> + <div class="form-group"> + <label class="control-label" for="propName">Name</label> + <input name="key" class="form-control" id="propName" type="text" /> + </div> + + <div class="form-group"> + <label class="control-label" for="propType">Type</label> + <select name="type" class="form-control" id="propType"> + <c:forEach var="t" items="${it.availablePropertyTypes}"> + <option value="${t}">${t}</option> + </c:forEach> + </select> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" onclick="createProperty();">Add</button> + </div> + </div> + </div> +</div> + +<script> +function noneClicked() { + disableKVproperties(); + clearXSDElementSelection(); + clearXSDTypeSelection(); + $.ajax({ + url: "propertiesdefinition/", + type: 'DELETE', + async: true, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not remove properties definition", jqXHR, errorThrown); + } + }); +} + +function clearXSDElementSelection() { + $("#xsdelement").editable('setValue', "", true); +} + +function clearXSDTypeSelection() { + $("#xsdtype").editable('setValue', "", true); +} + +$(function(){ + $("#xsdelement").editable({ + type: "select", + url: "post/", + pk: 1, + source: ${w:allXSDElementDefinitionsForTypeAheadSelection()} + }); + $("#xsdelement").on("click", function(e){ + $("#xsdelementradio").prop("checked", true); + }); + + $("#xsdtype").editable({ + type: "select", + source: ${w:allXSDTypeDefinitionsForTypeAheadSelection()} + }); + $("#xsdtype").on("click", function(e){ + $("#xsdtyperadio").prop("checked", true); + }); + + /* make UI more nice: enable click on label */ + $("#textnone").on("click", function(e){ + $("#nopropdef").prop("checked", true); + noneClicked(); + }); + $("#textxmlelement").on("click", function(e){ + $("#xsdelementradio").prop("checked", true); + disableKVproperties(); + clearXSDTypeSelection(); + }); + $("#textxmltype").on("click", function(e){ + $("#xsdtyperadio").prop("checked", true); + disableKVproperties(); + clearXSDElementSelection(); + }); + $("#textcustomkv").on("click", function(e){ + $("#customkv").prop("checked", true); + updateKVpropertiesVisibility(); + setKVPropertiesOnServer(); + clearXSDElementSelection(); + clearXSDTypeSelection(); + }); + + $('#kvPropsTabs a').click(function (e) { + e.preventDefault(); + $(this).tab('show'); + }); + + $("#addPropertyDiag").on("shown.bs.modal", function() { + $("#propName").focus(); + }); +}); +</script> + +<p> + <%-- TODO: if clicked on the "label" of the input field (i.e., the content of the input tag), the input should be selected. This is not the default at HTML5 - see http://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_radio --%> + + <input id="nopropdef" type="radio" name="kind" value="none" <c:if test="${not it.isWineryKeyValueProperties and empty it.entityType.propertiesDefinition.element and empty t.entityType.propertiesDefinition.type}">checked="checked"</c:if>><span class="cursorpointer" id="textnone">(none)</span></input> + <br/> + + <input id="xsdelementradio" type="radio" name="kind" value="element" <c:if test="${not empty it.entityType.propertiesDefinition.element}">checked="checked"</c:if>><span class="cursorpointer" id="textxmlelement">XML element</span></input> + <a href="#" id="xsdelement" data-url="propertiesdefinition/" data-send="always" data-title="Select XSD Element" data-value="${it.entityType.propertiesDefinition.element}"><c:if test="${not empty it.entityType.propertiesDefinition.element}">${it.entityType.propertiesDefinition.element.localPart}</c:if></a> + <br/> + + <input id="xsdtyperadio" type="radio" name="kind" value="type" <c:if test="${not empty it.entityType.propertiesDefinition.type}">checked="checked"</c:if>><span class="cursorpointer" id="textxmltype">XML type</span></input> + <a href="#" id="xsdtype" data-url="propertiesdefinition/" data-send="always" data-title="Select XSD Type" data-value="${it.entityType.propertiesDefinition.type}"><c:if test="${not empty it.entityType.propertiesDefinition.type}">${it.entityType.propertiesDefinition.type.localPart}</c:if></a> + <br/> + + + <input id="customkv" type="radio" name="kind" value="KV" <c:if test="${it.isWineryKeyValueProperties and not it.isWineryKeyValuePropertiesDerivedFromXSD}">checked="checked"</c:if>><span class="cursorpointer" id="textcustomkv">Custom key/value pairs</span></input> +</p> + +<div id="Properties" style="display:none; margin-left:20px;"> + <ul class="nav nav-tabs" id="kvPropsTabs"> + <li class="active"><a href="#kvProps">Properties</a></li> + <li><a href="#wrapper">Wrapping</a></li> + </ul> + + <div class="tab-content"> + <div class="tab-pane active" id="kvProps"> + + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOnServerAndInTable(propertiesTableInfo, 'Property', 'propertiesdefinition/winery/list/');">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="$('#addPropertyDiag').modal('show');">Add</button> + + <table cellpadding="0" cellspacing="0" border="0" class="display" id="propertiesTable"> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + </tr> + </thead> + <tbody> + <c:if test="${it.isWineryKeyValueProperties}"> + <c:forEach var="t" items="${it.propertyDefinitionKVList}"> + <tr> + <td>${t.key}</td> + <%-- FIXME: t.type is the short type, but we need the full type. Currently, there is no way to get the full type for a short type --%> + <td>${t.type}</td> + </tr> + </c:forEach> + </c:if> + </tbody> + </table> + </div> + + <div class="tab-pane" id="wrapper"> + <form id="wrapperelementform" enctype="multipart/form-data"> + <fieldset> + <div style="width:400px;"> + <div class="form-group"> + <label for="wrapperelement_name">Name of Wrapper Element</label> + <a href="#" class="form-control" id="wrapperelement_name" data-url="propertiesdefinition/winery/elementname" data-send="always" data-title="Local Name" data-type="text" data-value="${it.elementName}"></a> + </div> + <t:namespaceChooser idOfInput="wrapperelement_ns" selected="${it.namespace}" allNamespaces="${w:allNamespaces()}"></t:namespaceChooser> + </div> + </fieldset> + </form> + </div> + </div> +</div> + +<script> +function disableKVproperties() { + $("#Properties").hide(); +} + +function enableKVproperties() { + $("#Properties").show(); +} + +function updateKVpropertiesVisibility() { + if ($("input[name='kind']:checked").val() == "KV") { + enableKVproperties(); + } else { + disableKVproperties(); + } +} + +function setKVPropertiesOnServer() { + $.ajax({ + url: "propertiesdefinition/winery/", + type: "POST", + async: true, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could change to custom key/value pairs", jqXHR, errorThrown); + } + }); +} + +$(function() { + // put change function on all inputs to get notified of any change by the user + $("input[name='kind']").on("change", function(e) { + // we do not POST something to the server as only concrete values really trigger a change on server side + var target = e.currentTarget.value; + if (target == "none") { + noneClicked(); + } else if (target == "element") { + disableKVproperties(); + clearXSDTypeSelection(); + } else if (target == "type") { + disableKVproperties(); + clearXSDElementSelection(); + enableKVproperties(); + } else if (target == "KV") { + <c:if test="${not it.isWineryKeyValuePropertiesDerivedFromXSD}"> + <%-- only empty the k/v properties if not derived from XSD--%> + setKVPropertiesOnServer(); + </c:if> + clearXSDElementSelection(); + clearXSDTypeSelection(); + } else { + vShowError("UI not consistent to code"); + } + }); + + // initialization - display the custom box to enter k/vs only if KV is selected + updateKVpropertiesVisibility(); + + $("#wrapperelement_name").editable({ + ajaxOptions: { + type: 'put' + }, + params: function(params) { + // adjust params according to Winery's expectations + delete params.pk; + params.name = params.value; + delete params.value; + return params; + } + }).on("save", function(e, params) { + vShowSuccess("Successfully updated local name of wrapper element"); + }); + + $("#wrapperelement_ns").on("change", function(e) { + $.ajax({ + url: "propertiesdefinition/winery/namespace", + type: "PUT", + async: true, + contentType: "text/plain", + processData: false, + data: e.val, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not update namespace", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + vShowSuccess("Successfully updated namespace"); + } + }); + }); +}); + +var propertiesTableInfo = { + id: '#propertiesTable' +}; + +require(["winery-support"], function(ws) { + ws.initTable(propertiesTableInfo); +}); + +function createProperty() { + var data = { + key: $("#propName").val(), + type: $('#propType :selected').text() + } + $.ajax({ + url: "propertiesdefinition/winery/list/", + type: "POST", + async: true, + contentType: "application/json", + processData: false, + data: JSON.stringify(data), + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add property", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + var name = $('#propName').val(); + var type = $('#propType :selected').text(); + var dataToAdd = [name, type]; + propertiesTableInfo.table.fnAddData(dataToAdd); + vShowSuccess("Property successfully added"); + $('#addPropertyDiag').modal('hide'); + } + }); +} +</script> + diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/relationshiptype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/relationshiptype.jsp new file mode 100644 index 0000000..ba2e6cc --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/relationshiptype.jsp @@ -0,0 +1,44 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#visualappearance", "Visual Appearance"); +subMenus.add(data); + +data = new SubMenuData("#instancestates", "Instance States"); +subMenus.add(data); + +data = new SubMenuData("#sourceinterfaces", "Source Interfaces"); +subMenus.add(data); + +data = new SubMenuData("#targetinterfaces", "Target Interfaces"); +subMenus.add(data); + +data = new SubMenuData("#validendings", "Valid Sources and Targets"); +subMenus.add(data); + +data = new SubMenuData("#implementations", "Implementations"); +subMenus.add(data); + +%> + +<t:entitytype cssClass="relationshipType" selected="RelationshipType" subMenus="<%=subMenus%>" twolines="true"> +</t:entitytype> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/validendings.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/validendings.jsp new file mode 100644 index 0000000..4bf2145 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/validendings.jsp @@ -0,0 +1,39 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="rt" tagdir="/WEB-INF/tags/relationshiptype" %> + +<h4>Valid Source</h4> +<input type="radio" name="SourceKind">Node Type:</input> +<rt:validnodetypeendingsselect shortName="source" currentSelection="${it.validSource}" possibleValidEndings="${it.possibleValidEndings}"> +</rt:validnodetypeendingsselect> +<br/> +<input type="radio" name="SourceKind">Requirement Type:</input> +<select> + <option>Not yet implemented. Please edit in the XML view</option> +</select> + + +<br/> +<br/> +<h4>Valid Target</h4> +<input type="radio" name="TargetKind">Node Type:</input> +<rt:validnodetypeendingsselect shortName="target" currentSelection="${it.validTarget}" possibleValidEndings="${it.possibleValidEndings}"> +</rt:validnodetypeendingsselect> +<br/> +<input type="radio" name="TargetKind">Capability Type:</input> +<select> + <option>Not yet implemented. Please edit in the XML view</option> +</select> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/visualappearance.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/visualappearance.jsp new file mode 100644 index 0000000..d30ea01 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/relationshiptypes/visualappearance.jsp @@ -0,0 +1,193 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<script type='text/javascript' src='${pageContext.request.contextPath}/components/raphael/raphael.js'></script> +<script type='text/javascript' src='${pageContext.request.contextPath}/components/colorwheel/javascripts/colorwheel.js'></script> + +<ul class="nav nav-tabs" id="myTab"> + <li class="active"><a href="#icon">Icon</a></li> + <li><a href="#colors">Colors</a></li> + <li><a href="#arrow">Arrow</a></li> +</ul> + +<div class="tab-content"> + <div class="tab-pane active" id="icon"> + <br /> + <t:imageUpload + label="Icon (16x16) used in palette" + URL="visualappearance/16x16" + id="upSmall" + width="16px" + resize="16" + accept="image/*"/> + </div> + + <div class="tab-pane" id="colors"> + <br /> + <form> + <fieldset> + <t:colorwheel label="Line Color" color="${it.color}" id="color" url="color" /> + <t:colorwheel label="Hover Color" color="${it.hoverColor}" id="hovercolor" url="hovercolor" /> + </fieldset> + </form> + </div> + + <div class="tab-pane" id="arrow"> + <br /> + <form> + <fieldset> + <div class="form-group"> + <label for="arrow">Arrow appearance</label> + <div style="width:100%" id="arrow"> + <div style="float:left; width:50px;"> + <!-- Same values as the beginning of the file names in src\main\webapp\images\relationshiptype --> + <select id="dropDownSourceHead"> + <option value="none"></option> + <option value="PlainArrow"></option> + <option value="Diamond"></option> + <!-- not yet supported + <option value="simpleArrow"></option> + <option value="doubleArrow"></option> + <option value="circle"></option> + <option value="square"></option> --> + </select> + </div> + <div style="float:left; width:80px;"> + <select id="lineSelect"> + <option value="plain"></option> + <option value="dotted"></option> + <option value="dotted2"></option> + </select> + </div> + <div style="float:left; width:50px;"> + <select id="dropDownTargetHead"> + <option value="none"></option> + <option value="PlainArrow"></option> + <option value="Diamond"></option> + <!-- not yet supported + <option value="simpleArrow"></option> + <option value="doubleArrow"></option> + <option value="circle"></option> + <option value="square"></option> --> + </select> + </div> + </div> + </div> + </fieldset> + </form> + </div> +</div> + +<script> +$('#myTab a').click(function (e) { + e.preventDefault(); + $(this).tab('show'); +}); + +/** + * @param sourceOrTarget "Source" or "Target" + */ +function formatArrow(config, sourceOrTarget) { + var path = "${pageContext.request.contextPath}/images/relationshiptype/" + config.id + sourceOrTarget + ".png"; + return "<img src='" + path +"' />"; +} + +var globalAJAXParamsForSelect2VisualAppearance = { + type : "PUT", + contentType : "text/plain", + success : function() { + vShowSuccess("Successfully updated arrow appearance"); + }, + error : function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not supdate arrow appearance", jqXHR, errorThrown); + } +} + +/* source arrow head */ + +function formatArrowSource(config) { + return formatArrow(config, "Source"); +} + +// set stored value +$("#dropDownSourceHead").val("${it.sourceArrowHead}") +// enable storage on change of element +.on("change", function(e) { + params = globalAJAXParamsForSelect2VisualAppearance; + params.url = "visualappearance/sourcearrowhead"; + params.data = e.val; + $.ajax(params); +}) +// make the selection box show arrows +.select2({ + formatResult: formatArrowSource, + formatSelection: formatArrowSource, + escapeMarkup: function(m) { return m; }, + minimumResultsForSearch: -1 +}); + + +/* line */ +function formatLine(config) { + var path = "${pageContext.request.contextPath}/images/relationshiptype/" + config.id + "Line.png"; + return "<img src='" + path +"' />"; +} + +//set stored value +$("#lineSelect").val("${it.dash}") +//enable storage on change of element +.on("change", function(e) { + params = globalAJAXParamsForSelect2VisualAppearance; + params.url = "visualappearance/dash"; + params.data = e.val; + $.ajax(params); +}) +//make the selection box show arrows +.select2({ + formatResult: formatLine, + formatSelection: formatLine, + escapeMarkup: function(m) { return m; }, + minimumResultsForSearch: -1 +}); + + + +/* target arrow head */ + +function formatArrowTarget(config) { + return formatArrow(config, "Target"); +} + +//set stored value +$("#dropDownTargetHead").val("${it.targetArrowHead}") +//enable storage on change of element +.on("change", function(e) { + params = globalAJAXParamsForSelect2VisualAppearance; + params.url = "visualappearance/targetarrowhead"; + params.data = e.val; + $.ajax(params); +}) +//make the selection box show arrows +.select2({ + formatResult: formatArrowTarget, + formatSelection: formatArrowTarget, + escapeMarkup: function(m) { return m; }, + minimumResultsForSearch: -1 +}); + +</script> + diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/requirementtypes/requiredcapabilitytype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/requirementtypes/requiredcapabilitytype.jsp new file mode 100644 index 0000000..0b10277 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/requirementtypes/requiredcapabilitytype.jsp @@ -0,0 +1,56 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> + +<c:choose> + <c:when test="${empty it.requirementType.requiredCapabilityType}"> + <c:set var="selected" value="(none)" /> + </c:when> + <c:otherwise> + <c:set var="selected" value="${it.requirementType.requiredCapabilityType}" /> + </c:otherwise> +</c:choose> + +<ct:QNameChooser allQNames="${it.allCapabilityTypes}" idOfSelectField="requiredCapabilityType" labelOfSelectField="" includeNONE="true" selected="${selected}"/> + +<script> +$("#requiredCapabilityType").on("change", function(e) { + var val = $("#requiredCapabilityType").val(); + if (val == "(none)") { + // remove required capability type assignment + $.ajax({ + url: 'requiredcapabilitytype', + type: "DELETE" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not remove required capability type assignment.", jqXHR, errorThrown); + }).done(function(data, textStatus, jqXHR) { + vShowSuccess("Successfully updated required capability type assignment."); + }); + } else { + // put new capability type + $.ajax({ + url: 'requiredcapabilitytype', + data: val, + contentType: "text/plain", + type: "PUT" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not update required capability type assignment.", jqXHR, errorThrown); + }).done(function(data, textStatus, jqXHR) { + vShowSuccess("Successfully updated required capability type assignment."); + }); + } +}); +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/requirementtypes/requirementtype.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/requirementtypes/requirementtype.jsp new file mode 100644 index 0000000..a8b6f43 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/entitytypes/requirementtypes/requirementtype.jsp @@ -0,0 +1,30 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(); + +SubMenuData data; + +data = new SubMenuData("#requiredcapabilitytype", "Required Capability Type"); +subMenus.add(data); + +%> + + +<t:entitytype cssClass="requirementType" selected="RequirementType" subMenus="<%=subMenus%>"> +</t:entitytype> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/genericcomponentpage.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/genericcomponentpage.jsp new file mode 100644 index 0000000..0439904 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/genericcomponentpage.jsp @@ -0,0 +1,209 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="v" uri="http://www.eclipse.org/winery/repository/functions" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> + +<%-- In English, one can usually form a plural by adding an "s". Therefore, we resue the label to form the window title --%> +<t:genericpage windowtitle="${it.label}s" selected="${it.type}" cssClass="${it.CSSclass}"> + +<c:choose> +<c:when test="${empty pageContext.request.contextPath}"> +<c:set var="URL" value="/" /> +</c:when> +<c:otherwise> +<c:set var="URL" value="${pageContext.request.contextPath}/" /> +</c:otherwise> +</c:choose> +<t:simpleSingleFileUpload + title="Upload CSAR" + text="CSAR file" + URL="${URL}" + type="POST" + id="upCSAR" + accept="application/zip,.csar"/> + +<t:addComponentInstance + label="${it.label}" + typeSelectorData="${it.typeSelectorData}" + /> + +<div class="middle" id="ccontainer"> + <br /> + + <table cellpadding=0 cellspacing=0 style="margin-top: 0px; margin-left: 30px;"> + <tr> + <td valign="top" style="padding-top: 25px; width: 680px;"> + + <div id="searchBoxContainer"> + + <input id="searchBox" /> + + <script> + + $('#searchBox').keyup(function() { + var searchString = $(this).val(); + searchString = searchString.toLowerCase(); + + $(".entityContainer").each (function() { + var name = $(this).find(".informationContainer > .name").text(); + var namespace = $(this).find(".informationContainer > .namespace").text(); + + var t = name + namespace; + t = t.toLowerCase(); + + if (t.indexOf(searchString) == -1) { + $(this).hide(); + } else { + $(this).show(); + } + + }); + + }); + + </script> + + </div> + + <c:forEach var="t" items="${it.componentInstanceIds}"> + <%-- even though the id is an invalid XML, it is used for a simple implementation on a click on the graphical rendering to trigger opening the editor --%> + <div class="entityContainer ${it.CSSclass}" id="${v:URLencode(t.namespace.encoded)}/${v:URLencode(t.xmlId.encoded)}/"> + <div class="left"> + <c:if test="${it.type eq 'NodeType'}"> + <a href="./${v:URLencode(t.namespace.encoded)}/${v:URLencode(t.xmlId.encoded)}/?edit"> + <img src='./${v:URLencode(t.namespace.encoded)}/${v:URLencode(t.xmlId.encoded)}/visualappearance/50x50' style='margin-top: 21px; margin-left: 30px; height: 40px; width: 40px;' /> + </a> + </c:if> + </div> + <div class="center"> + <div class="informationContainer"> + <div class="name"> + ${wc:escapeHtml4(t.xmlId.decoded)} + </div> + <div class="namespace" alt="${wc:escapeHtml4(t.namespace.decoded)}"> + ${wc:escapeHtml4(t.namespace.decoded)} + </div> + </div> + <div class="buttonContainer"> + <a href="${v:URLencode(t.namespace.encoded)}/${v:URLencode(t.xmlId.encoded)}/?csar" class="exportButton"></a> + <a href="${v:URLencode(t.namespace.encoded)}/${v:URLencode(t.xmlId.encoded)}/?edit" class="editButton"></a> + <%-- we need double encoding of the URL as the passing to javascript: decodes the given string once --%> + <a href="javascript:deleteCI('${wc:escapeHtml4(t.xmlId.decoded)}', '${v:URLencode(v:URLencode(t.namespace.encoded))}/${v:URLencode(v:URLencode(t.xmlId.encoded))}/');" class="deleteButton" onclick="element = $(this).parent().parent().parent();"></a> + </div> + </div> + <div class="right"></div> + </div> + </c:forEach> + </td> + <td id="gcprightcolumn" valign="top"> + <div id="overviewtopshadow"></div> + <div id="overviewbottomshadow"></div> + </td> + <td valign="top"> + <div class="btn-group-vertical" id="buttonList"> + <button type="button" class="btn btn-default" onclick="openNewCIdiag();">Add new</button> + <button type="button" class="btn btn-default" onclick="importCSAR();">Import CSAR</button> + </div> + </td> + </tr> + </table> +</div> + +<script> + +function entityContainerClicked(e) { + var target = $(e.target); + if (target.is("a")) { + // do nothing as a nested a element is clicked + } else { + var ec = target.parents("div.entityContainer"); + var url = ec.attr('id'); + if (e.ctrlKey) { + // emulate browser's default behavior to open a new tab + window.open(url); + } else { + window.location = url; + } + } +} + +$("div.entityContainer").on("click", entityContainerClicked); + +/** + * deletes given component instance + * uses global variable "element", which stores the DOM element to delete upon successful deletion + */ +function deleteCI(name, URL) { + deleteResource(name, URL, function() { + element.remove(); + }); +} + +function importCSAR() { + $('#upCSARDiag').modal('show'); +} + +// If export button is clicked with "CTRL", the plain XML is shown, not the CSAR +// We use "on" with filters instead as new elements could be added when pressing "Add new" (in the future) +// contained code is the same as the code of the CSAR button at the topology modeler (see index.jsp) +$(document).on("click", ".exportButton", function(evt) { + var url = $(this).attr("href"); + if (evt.ctrlKey) { + url = url.replace(/csar$/, "definitions"); + } + window.open(url); + return false; +}); + +<%-- Special feature in the case of the service template --%> +<c:if test="${it.type eq 'ServiceTemplate'}"> +//If edit button is clicked with "CTRL", the topology modeler is opened, not the service template editor +//We use "on" with filters instead as new elements could be added when pressing "Add new" (in the future) +$(document).on("click", ".editButton", function(evt) { + var url = $(this).attr("href"); + if (evt.ctrlKey) { + url = url.replace(/\?edit$/, "topologytemplate/?edit"); + // open in new tab + var newWin = window.open(url); + // focussing the new window does not work in Chrome + newWin.focus(); + } else { + // normal behavior + window.location = url; + } + evt.preventDefault(); +}); +</c:if> + +$(".exportButton").tooltip({ + placement: 'bottom', + html: true, + title: "Export CSAR.<br/>Hold CTRL key to export XML only." +}); +$(".editButton").tooltip({ + placement: 'bottom', + html: true, + title: <c:if test="${it.type eq 'ServiceTemplate'}">"Edit.<br/>Hold CTRL key to directly open the topology modeler."</c:if><c:if test="${not (it.type eq 'ServiceTemplate')}">"Edit"</c:if> +}); +$(".deleteButton").tooltip({ + placement: 'bottom', + title: "Delete" +}); +</script> + +</t:genericpage> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/hashloading.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/hashloading.jsp new file mode 100644 index 0000000..eb5bbfa --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/hashloading.jsp @@ -0,0 +1,140 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<script> + function switchStyledTabSelection(element, onSuccess) { + target = element.attr("href"); + target = target.replace('#',''); + target += "/"; + $(".styledTabMenuButton2ndlevel").removeClass("selected"); + element.addClass("selected"); + $("#ccontainer").html('<div id="loading" style="display:none;">loading...</div>'); + $("#loading").fadeIn(3000); + $("#ccontainer").load(target, function(response, status, xhr) { + if (status == "error") { + vShowError("Could not load tab content: " + xhr.status + " " + xhr.statusText); + } else { + if (onSuccess) { + onSuccess(); + } + } + }); + } + + /** + * @param onSuccess called if subTabs are available and the super tab could be loaded + */ + function doTheTabSelection(onSuccess) { + var hash = window.location.hash; + + // get rid of ";" additions + var posColon = hash.indexOf(";"); + var subTab; + if (posColon >= 0) { + subTab = hash.substr(posColon + 1); + hash = hash.substr(0, posColon); + } + + if ($.inArray(hash, ${param.validpages}) == -1) { + hash = "${param.defaultpage}"; + } + + var callBack = onSuccess; + if (subTab) { + var posColon = subTab.indexOf(";"); + if (posColon > 0) { + // more information added, for instance xmltree data + // the first part is the subtab + subTab = subTab.substr(0, posColon); + } + callBack = function () { + $('#myTab a[href="#' + subTab + '"]').tab('show'); + if (onSuccess) { + onSuccess(); + } + }; + } + + switchStyledTabSelection($(".styledTabMenuButton2ndlevel[href='" + hash + "']"), callBack); + } + + // Firefox does not fire the "popstate" event at the first load, + // but Chrome does + // Because of Firefox, we have to call the refresh here + doTheTabSelection(); + + // see http://blog.mgm-tp.com/2011/10/must-know-url-hashtechniques-for-ajax-applications/ for a broad discussion + $(window).on("hashchange", function(e) { + if (internalHashChange) { + // we do nothing + internalHashChange = false; + } else { + // we have to check whether only additional data changed and thus no real change is required + var oldURL = e.originalEvent.oldURL; + var idx = oldURL.indexOf("#"); + if (idx != -1) { + var oldHash = oldURL.substr(idx); + var newURL = e.originalEvent.newURL; + // get the hash value only + idx = newURL.indexOf("#"); + if (idx != -1) { + var newHash = newURL.substr(idx); + // search for the first ";" + idx = oldHash.indexOf(";"); + if (idx != -1) { + // search for the second ";" + idx = oldHash.indexOf(";", idx+1); + if (idx == -1) { + // The new hash is only a refinement of the old hash: + // Only a new ";" has been added + // We do not need to reload + return; + } else { + if (oldHash.substr(0, idx) == newHash.substr(0, idx)) { + // the two hashes equal until the second ";" + // we don't have to do any reload + return; + } + } + } + } + } + + // switch to the new tab + doTheTabSelection(); + } + }); + + var internalHashChange = false; + + $(document).on('shown.bs.tab', "ul.nav-tabs > li > a", function (e) { + var id = $(e.target).attr("href").substr(1); + var hash = window.location.hash; + var additionalData = ""; + var posColon = hash.indexOf(";"); + if (posColon >= 0) { + // search for additionalData + secondColon = hash.indexOf(";", posColon+1); + if (secondColon > 0) { + // include the ";" in the additional data + additionalData = hash.substr(secondColon); + } + + // wipe everything after the colon + hash = hash.substr(0, posColon); + } + hash = hash + ";" + id + additionalData; + internalHashChange = true; + window.location.hash = hash; + }); +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/imports/xsdimports/xsdimport.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/imports/xsdimports/xsdimport.jsp new file mode 100644 index 0000000..452e7ad --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/imports/xsdimports/xsdimport.jsp @@ -0,0 +1,50 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%-- Quick hack without XML view --%> + +<%-- +FIXME: parameters cssClass and selected are somehow ignored, but replaced by the data provided by GenericComponentPageData or similar... +Symptom: in header.jsp "param.selected" is "XSDImport" instead of "xsdimport" +--%> +<t:genericpage windowtitle="XSD Imports" cssClass="mainContentContainer xsdimport" selected="xsdimport"> + + <div class="top"> + <%@ include file="/jsp/componentnaming.jspf" %> + <!-- + <div style="float:right; margin-right:29px; margin-top: -20px; position:relative;"> + <div style="float:right;"> + <a href="?definitions" class="btn btn-info">XML</a> + <a href="?csar" class="btn btn-info">ZIP</a> + </div> + </div> --> + </div> + + <div class="middle" id="ccontainer"> + +Associated file: +<c:if test="${empty it.location}">none</c:if> +<c:if test="${not empty it.location}"><a href="${it.location}">${it.location}</a></c:if> + +<br /> + +Modification not yet implemented + + </div> + +</t:genericpage> + + diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/inheritance.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/inheritance.jsp new file mode 100644 index 0000000..8d1d535 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/inheritance.jsp @@ -0,0 +1,55 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + +<div class="form-group"> + <label class="control-label" for="abstract">Abstract</label> + <select class="form-control" style="width:100px;" id="isAbstract" onchange="updateValue('abstract', this.options[this.selectedIndex].value);"> + <option value="yes"<c:if test="${it.isAbstract=='yes'}"> selected="selected"</c:if>>yes</option> + <option value="no"<c:if test="${it.isAbstract=='no'}"> selected="selected"</c:if>>no</option> + </select> +</div> + +<div class="form-group"> + <label class="control-label">Final</label> + <select class="form-control" style="width:100px;" id="isFinal" onchange="updateValue('final', this.options[this.selectedIndex].value);"> + <option value="yes"<c:if test="${it.isFinal=='yes'}"> selected="selected"</c:if>>yes</option> + <option value="no"<c:if test="${it.isFinal=='no'}"> selected="selected"</c:if>>no</option> + </select> +</div> + +<div class="form-group"> + <label class="control-label">Derived from</label> + <div style="display: block; width: 100%"> + <select class="form-control" style="width:600px; display:inline; margin-right: 10px;" id="derivedFrom" onchange="updateValue('derivedFrom', this.options[this.selectedIndex].value);"> + <option value=""<c:if test="${empty it.derivedFrom}"> selected="selected"</c:if>>(none)</option> + <c:forEach items="${it.possibleSuperTypes}" var="type"> + <c:set var="value" value="${type.QName}" /> + <option value="${value}"<c:if test="${value==it.derivedFrom}"> selected="selected"</c:if>>${type.xmlId.decoded}</option> + </c:forEach> + </select> + <button type="button" class="btn btn-info btn-sm" onclick="openSuperType();">Open</button> + </div> +</div> + +<script> +function openSuperType() { + require(["winery-support-common"], function(w) { + var qname = $("#derivedFrom").val(); + var fragment = w.getURLFragmentOutOfFullQName(qname); + var url = "../../" + fragment + "/"; + window.location = url; + }); +} +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/interfaces/interfaces.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/interfaces/interfaces.jsp new file mode 100644 index 0000000..07ed928 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/interfaces/interfaces.jsp @@ -0,0 +1,489 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - port to bootstrap 3 + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> +<%@taglib prefix="p" tagdir="/WEB-INF/tags/parameters" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<%@page import="org.eclipse.winery.common.Util" %> +<%@page import="org.eclipse.winery.repository.Constants" %> + +<link type="text/css" href="${pageContext.request.contextPath}/components/bootstrap-switch/build/css/bootstrap3/bootstrap-switch.css" rel="stylesheet" /> +<script type="text/javascript" src="${pageContext.request.contextPath}/components/bootstrap-switch/build/js/bootstrap-switch.js"></script> + +<%-- include basic parameters support --%> +<p:parametersJS afterLoad="interfaceSelectionChanged();"></p:parametersJS> + +<script> +<%final String URI_LIFECYCLE_INTERFACE = "http://www.example.com/interfaces/lifecycle";%> +var URI_LIFECYCLE_INTERFACE = "<%=URI_LIFECYCLE_INTERFACE%>"; + +/** + * @param noUpdate if given, then the selection is not updated. This is required when Winery itself creates interfaces without user intervention. For instance, that is the case at the lifecycle interface + */ +function afterInterfaceCreation(serializedArray, resData, textStatus, jqXHR, noUpdate) { + var text = serializedArray[0].value; + if (text == URI_LIFECYCLE_INTERFACE) { + // lifecycle interface has been generated + // disable button to generate lifecycle interface + $("#generatelifecycleifacetn").attr("disabled", "disabled"); + } + addSortedSelectionItem($("#interfaces"), text, text); + if (!noUpdate) { + interfaceSelectionChanged(); + } +} + +function afterOperationCreation(serializedArray, resData, textStatus, jqXHR) { + var text = serializedArray[0].value; + addSortedSelectionItem($("#operations"), text, text); + operationSelectionChanged(); +} + +function getIfaceURL() { + var iface = $("#interfaces").find(":selected").val(); + return "${it.urlPrefix}interfaces/" + encodeID(iface) + "/"; +} + +function getOperationURL() { + var op = $("#operations").find(":selected").val(); + return getIfaceURL() + "operations/" + encodeID(op) + "/"; +} + +function createInterface() { + createResource('Interface', [{'label': 'Name', 'name':'interfaceName'}], '${it.urlPrefix}interfaces/', afterInterfaceCreation); +} + +function createOperation() { + var url = getIfaceURL() + "operations/"; + createResource('Operation', [{'label':'Name', 'name':'name'}], url, afterOperationCreation); +} + +function disableAllOperationButtons() { + $("#addOpBtn").attr("disabled", "disabled"); + $("#removeOpBtn").attr("disabled", "disabled"); +} + +function disableAllInputButtons() { + $("#addInParBtn").attr("disabled", "disabled"); + $("#removeInParBtn").attr("disabled", "disabled"); +} + +function disableAllOutputButtons() { + $("#addOutParBtn").attr("disabled", "disabled"); + $("#removeOutParBtn").attr("disabled", "disabled"); +} + +function interfaceSelectionChanged(noupdate) { + iface = $("#interfaces").find(":selected"); + if (iface.length == 0) { + // nothing selected + $("#operations").empty(); + inputParametersTableInfo.table.fnClearTable(); + outputParametersTableInfo.table.fnClearTable(); + disableAllOperationButtons(); + disableAllInputButtons(); + disableAllOutputButtons(); + $("#removeIfBtn").attr("disabled", "disabled"); + $("#generateiabtn").attr("disabled", "disabled"); + } else { + $.ajax({ + "url": getIfaceURL() + "operations/", + dataType: "JSON", + success: function(data, textStatus, jqXHR) { + var operations = $("#operations"); + operations.empty(); + $.each(data, function(number, item) { + var selected; + if (number == 0) { + selected = ' selected="selected"'; + } else { + selected = ""; + } + operations.append('<option value="' + item + '"' + selected + '>' + item + '</option>'); + }); + operationSelectionChanged(); + $("#removeIfBtn").removeAttr("disabled"); + $("#generateiabtn").removeAttr("disabled"); + } + }); + } +} + +function operationSelectionChanged() { + if ($("#operations").find(":selected").length == 0) { + inputParametersTableInfo.table.fnClearTable(); + outputParametersTableInfo.table.fnClearTable(); + disableAllInputButtons(); + disableAllOutputButtons(); + $("#removeOpBtn").attr("disabled", "disabled"); + if ($("#interfaces").children("option").length == 0) { + // no interfaces available + $("#addOpBtn").attr("disabled", "disabled"); + } else { + $("#addOpBtn").removeAttr("disabled"); + } + } else { + updateInputAndOutputParameters(getOperationURL()); + $("#addOpBtn").removeAttr("disabled"); + $("#removeOpBtn").removeAttr("disabled"); + } +} + + +function determineNextItemToSelect(currentItem) { + var nextToSelect; + nextToSelect = currentItem.next(); + if (nextToSelect.length == 0) { + nextToSelect = currentItem.prev(); + // even if nothing found, the following code works: + // X.attr("selected", "selected") does not throw any error if X is empty + } + return nextToSelect; +} + +function deleteThing(thingId, thingName, urlDetermination, changedFunction) { + var thing = $("#" + thingId).find(":selected"); + if (thing.length == 0) { + vShowError("UI in wrong state"); + } else { + deleteResource( + thingName + " " + thing.text(), + urlDetermination(), + function() { + nextToSelect = determineNextItemToSelect(thing); + thing.remove(); + nextToSelect.attr("selected", "selected"); + changedFunction(); + } + ); + } +} + +function deleteInterface() { + var iface = $("#interfaces").find(":selected").text(); + + // if the lifecycle interface is going to be removed, + // enable the button to generate the lifecycle interface again + var changedFunction; + if (iface == URI_LIFECYCLE_INTERFACE) { + changedFunction = function() { + $("#generatelifecycleifacetn").removeAttr("disabled"); + interfaceSelectionChanged(); + } + } else { + changedFunction = interfaceSelectionChanged; + } + + deleteThing("interfaces", "Interface", getIfaceURL, changedFunction); +} + +function deleteOperation() { + deleteThing("operations", "Operation", getOperationURL, operationSelectionChanged); +} + +function createArtifactTemplate() { + // we use the quick way at implementationartifacts/ to auto-generate an artifact template + // see org.eclipse.winery.repository.resources.artifacts.GenericArtifactsResource<ArtifactResource, ArtifactT> for the REST-interface description; + + var url = getTypeImplementationURL() + "implementationartifacts/"; + var data = $("#artifactTemplateNS, #artifactTemplateName, #autoCreateArtifactTemplate, #artifactType, #autoGenerateIA, #interfaces, #javapackage").serialize(); + + // we use the artifact template name as artifact name + var artifactName = $("#artifactTemplateName").serialize(); + artifactName = "artifact" + artifactName.substring(16); + data = data + "&" + artifactName; + + $.ajax({ + url: url, + data: data, + type: "POST" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create artifact template", jqXHR, errorThrown); + $("#generateiabtn").button("reset"); + }).done(function(data, textStatus, jqXHR) { + var location = jqXHR.getResponseHeader("location"); + + vShowSuccess('Successfully generated IA. It is currently downloaded and available <a href="' + location + '/../../">here</a>'); + + // open the downloaded file + window.open(location, "_blank"); + + $("#generateiamodal").modal("hide"); + }); +} + +function generateIA() { + $("#generateiabtn").button("loading"); + + // create type implementation if necessary + var typeImplementationHasToBeCreated = $("#nodeTypeImplCreationSwitch").bootstrapSwitch('status'); // "status" instead of "state" (!) + if (typeImplementationHasToBeCreated) { + var url = "${pageContext.request.contextPath}/${it.relationshipTypeOrNodeTypeURLFragment}implementations/"; + var data = $("#nodetypeimplementationName, #nodetypeimplementationNS, #qnameOfType").serialize(); + $.ajax({ + url: url, + type: "POST", + data: data + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create type implementation", jqXHR, errorThrown); + $("#generateiabtn").button("reset"); + }).done(function() { + createArtifactTemplate(); + }); + } else { + createArtifactTemplate(); + } +} + +$(function() { + $("#generateiamodal").on("show.bs.modal", function() { + // check whether the required artifact type exists + $.ajax({ + url: "${pageContext.request.contextPath}/artifacttypes/<%=Util.DoubleURLencode(Constants.NAMESPACE_ARTIFACTTYPE_WAR)%>/<%=Util.DoubleURLencode(Constants.LOCALNAME_ARTIFACTTYPE_WAR)%>/", + type: "HEAD" + }).fail(function(jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 404) { + vShowError("WAR artifact type does not exist. Please create artifact type WAR"); + $("#generateiabtn").attr("disabled", "disabled"); + } else { + vShowAJAXError("Could not check for existance of WAR artifact type", jqXHR, errorThrown); + } + }).success(function() { + $("#generateiabtn").removeAttr("disabled"); + }); + + // dialog is reset at each show + $("#generateiabtn").button("reset"); + + // set java package + $("#javapackage").val("${w:namespaceToJavaPackage(it.namespace)}"); + + // set node type implementation name + $("#nodetypeimplementationName").val("${it.name}_impl"); + + // reset node type implementation namespace + $("#nodetypeimplementationNS").val("${it.namespace}").attr("selected", "selected"); + + // the default type impl could exist + checkNodeTypeImplName(); + + // reset artifact template namespace + $("#artifactTemplateNS").val("${it.namespace}").attr("selected", "selected"); + + require(["artifacttemplateselection", "winery-support"], function(ats, ws) { + // set artifact template name + var iface = $("#interfaces").find(":selected"); + var initialATName = "${it.name}_" + ws.makeNCName(iface.text()) + "_IA"; + $("#artifactTemplateName").val(initialATName); + + // check if artifact template is a valid name + ats.checkArtifactTemplateName(); + }); + }); + + $("#nodetypeimplementationNS").on("blur", checkNodeTypeImplName).on("change", checkNodeTypeImplName).on("focus", flagNodeTypeImplAsUpdating); + $("#nodetypeimplementationName").typing({ + start: function(event, $elem) { + flagNodeTypeImplAsUpdating(); + }, + stop: function(event, $elem) { + checkNodeTypeImplName(); + } + }); + +}); + +<%-- adapted from artifacttemplateselection.tag --%> + +function getTypeImplementationURL() { + var ns = $("#nodetypeimplementationNS").val(); + var name = $("#nodetypeimplementationName").val(); + var url = "${pageContext.request.contextPath}/${it.relationshipTypeOrNodeTypeURLFragment}implementations/" + encodeID(ns) + "/" + encodeID(name) + "/"; + return url; +} + +function checkNodeTypeImplName() { + var name = $("#nodetypeimplementationName").val(); + if (name == "") { + var valid = false; + var invalidReason = "No name provided"; + // TODO: setNodeTypeImplNameValidityStatus(valid, invalidReason); + } else { + url = getTypeImplementationURL(); + $.ajax(url, { + type: 'HEAD', + dataType: 'html', + error: function(jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 404) { + // node type implementation does not exist + $("#nodeTypeImplCreationSwitch").bootstrapSwitch('setState', true); + } else { + vShowAJAXError("Could not check for type implementation existance", jqXHR, errorThrown); + // Alternative: setValidityStatus(false, textStatus); + } + }, + success: function(data, textStatus, jqXHR) { + // node type implementation exists + $("#nodeTypeImplCreationSwitch").bootstrapSwitch('setState', false); + } + }); + } +} + +function flagNodeTypeImplAsUpdating() { + // not yet implemented +} + +function generateLifeCycleInterface() { + var data = "interfaceName=" + encodeURIComponent(URI_LIFECYCLE_INTERFACE); + $.ajax({ + url: '${it.urlPrefix}interfaces/', + data: data, + type: "POST" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create interface", jqXHR, errorThrown); + }).done(function(data, textStatus, jqXHR) { + var serializedArray = [{value:URI_LIFECYCLE_INTERFACE}]; + afterInterfaceCreation(serializedArray, data, textStatus, jqXHR, true); + + var operations = ["install", "configure", "start", "stop", "uninstall"]; + var errorOccurred = false; + + $(operations).each(function(i, operationName) { + // we have to go through one-by-one to keep the order of operations + // no parallel creation possible + // Therefore also "async: false" at the AJAX call + + var data = "name=" + operationName; + + var url = getIfaceURL() + "operations/"; + $.ajax({ + url: url, + data: data, + type: "POST", + async: false + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create operation " + operationName, jqXHR, errorThrown); + errorOccurred = true; + }).done(function(data, textStatus, jqXHR) { + serializedArray = [{value:operationName}]; + afterOperationCreation(serializedArray, data, textStatus, jqXHR); + }); + }); + + if (!errorOccurred) { + vShowSuccess('Successfully generated lifecycle interface'); + } + }); +} + +</script> + +<div id="generateiamodal" class="modal fade"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Generate Implementation Artifact</h4> + </div> + <div class="modal-body"> + <form role="form"> + <div class="form-group"> + <label for="javapackage">Java Package</label> + <input class="form-control" id="javapackage" name="javapackage" placeholder="Enter java package name" required="required"> + </div> + + <div class="form-group-grouping typeimplementation"> + <div class="form-group"> + <label for="nodetypeimplementationName">${it.relationshipTypeOrNodeType} Implementation Name</label> + <input required="required" class="form-control" id="nodetypeimplementationName" name="name" placeholder="Enter name for node type implementation" pattern="[\i-[:]][\c-[:]]*"><!-- name is an NCName --> + </div> + + <t:namespaceChooser nameOfInput="namespace" idOfInput="nodetypeimplementationNS" allNamespaces="${w:allNamespaces()}" selected="${it.namespace}"></t:namespaceChooser> + + <div id="nodeTypeImplCreationSwitch" class="make-switch" data-on-label="will be created" data-off-label="will be reused" style="height:30px; width:250px;"> + <input type="checkbox" disabled="disabled" checked="checked"> + </div> + + <input type="hidden" name="type" id="qnameOfType" value="${it.typeQName}"> + </div> + + <p class="text-warning">There is no check for the name of the implementation artifact. The artifact template name will be reused as implementation artifact name without any further check.</p> + + <ct:artifacttemplateselection repositoryURL="${pageContext.request.contextPath}" defaultNSForArtifactTemplate="${it.namespace}" allNamespaces="${w:allNamespaces()}"></ct:artifacttemplateselection> + <input type="hidden" name="autoCreateArtifactTemplate" value="true" id="autoCreateArtifactTemplate"> + + <div class="form-group"> + <label for="artifacttype">Artifact Type</label> + <a class="form-control" target="_blank" href="${pageContext.request.contextPath}/artifacttypes/<%=Util.DoubleURLencode(Constants.NAMESPACE_ARTIFACTTYPE_WAR)%>/<%=Util.DoubleURLencode(Constants.LOCALNAME_ARTIFACTTYPE_WAR)%>/">WAR</a> + <input type="hidden" name="artifactType" id="artifactType" value="{<%=Constants.NAMESPACE_ARTIFACTTYPE_WAR%>}<%=Constants.LOCALNAME_ARTIFACTTYPE_WAR%>"> + </div> + + <input type="hidden" name="autoGenerateIA" id="autoGenerateIA" value="true"> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" id="generateiabtn" onclick="generateIA();" data-loading-text="Generating...">Generate</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> + + +<div><!-- we do not use bootstrap's "container" as the container leads to an overflow --> + <div class="col-xs-4 bordered"> + <div class="listheading"> + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteInterface();" disabled="disabled" id="removeIfBtn">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="createInterface();" id="addIfBtn">Add</button> + <label>Interfaces</label> + </div> + <select class="listcontent" id="interfaces" size="18" onchange="interfaceSelectionChanged();" name="interfaceName"> + <c:set var="generatelifcecycleifactebtnDisabled" value=""></c:set> + <c:set var="URI_LIFECYCLE_INTERFACE" value="<%=URI_LIFECYCLE_INTERFACE%>"></c:set> + <!-- ${URI_LIFECYCLE_INTERFACE} --> + <c:forEach var="iface" varStatus="count" items="${it.listOfAllEntityIdsAsList}"> + <c:set var="selected" value=""></c:set> + <c:if test="${count.index == 0}"> + <c:set var="selected" value=" selected=\"selected\""></c:set> + </c:if> + <c:if test="${iface == URI_LIFECYCLE_INTERFACE}"> + <c:set var="generatelifcecycleifactebtnDisabled" value=" disabled=\"disabled\""></c:set> + </c:if> + <option value="${iface}"${selected}>${iface}</option> + </c:forEach> + </select> + <button id="generateiabtn" class="btn btn-default btn-xs" data-toggle="modal" data-target="#generateiamodal">Generate Implementation Artifact</button> + <button id="generatelifecycleifacetn" class="btn btn-default btn-xs" onclick="generateLifeCycleInterface();"${generatelifcecycleifactebtnDisabled}>Generate lifecycle interface</button> + </div> + + <div class="col-xs-4 middlebox bordered"> + <div class="listheading"> + <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOperation();" id="removeOpBtn">Remove</button> + <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="createOperation();" id="addOpBtn">Add</button> + <label>Operations</label> + </div> + <select class="listcontent" id="operations" size="18" onchange="operationSelectionChanged();"> + </select> + </div> + + <div class="col-xs-4 bordered"> + <p:parametersInput baseURL="getOperationURL()"></p:parametersInput> + <br /><br /> + <p:parametersOutput baseURL="getOperationURL()"></p:parametersOutput> + </div> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/otherElements.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/otherElements.jsp new file mode 100644 index 0000000..15d3e7d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/otherElements.jsp @@ -0,0 +1,44 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<t:genericpage windowtitle="Other Elements" selected="OtherElements" cssClass="otherelements"> + +<p> +The following items list TOSCA elements contained in TOSCA's <code>Definitions</code> element, which are not listed as separate tabs. +</p> + +<h4>Artifacts</h4> +<a class="btn btn-default" href="${pageContext.request.contextPath}/artifacttypes/">Artifact Types</a> +<a class="btn btn-default" href="${pageContext.request.contextPath}/artifacttemplates/">Artifact Templates</a> + +<h4>Requirements and Capabilities</h4> +<a class="btn btn-default" href="${pageContext.request.contextPath}/requirementtypes/">Requirement Types</a> +<a class="btn btn-default" href="${pageContext.request.contextPath}/capabilitytypes/">Capability Types</a> + +<h4>Implementations</h4> +<a class="btn btn-default" href="${pageContext.request.contextPath}/nodetypeimplementations/">Node Type Implementations</a> +<a class="btn btn-default" href="${pageContext.request.contextPath}/relationshiptypeimplementations/">Relationship Type Implementations</a> + +<h4>Policies</h4> +<a class="btn btn-default" href="${pageContext.request.contextPath}/policytypes/">Policy Types</a> +<a class="btn btn-default" href="${pageContext.request.contextPath}/policytemplates/">Policy Templates</a> + +<h4>Imports</h4> +<a class="btn btn-default" href="${pageContext.request.contextPath}/imports/http%253A%252F%252Fwww.w3.org%252F2001%252FXMLSchema">XML Schema Definitions</a> +<a class="btn btn-default" href="${pageContext.request.contextPath}/imports/http%253A%252F%252Fschemas.xmlsoap.org%252Fwsdl%252F">WSDLs</a> + +</t:genericpage> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/boundarydefinitions/boundarydefinitions.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/boundarydefinitions/boundarydefinitions.jsp new file mode 100644 index 0000000..aadec72 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/boundarydefinitions/boundarydefinitions.jsp @@ -0,0 +1,1080 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Tobias Binz - communication with the nested iframe + *******************************************************************************/ +--%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="w" tagdir="/WEB-INF/tags"%> +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> +<%@taglib prefix="b" tagdir="/WEB-INF/tags/servicetemplates/boundarydefinitions"%> +<%@taglib prefix="pol" tagdir="/WEB-INF/tags/common/policies" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> +<%@taglib prefix="wr" uri="http://www.eclipse.org/winery/repository/functions"%> + +<%@page import="org.eclipse.winery.common.ModelUtilities"%> + +<pol:policydiag allPolicyTypes="${it.allPolicyTypes}" repositoryURL="${it.repositoryURL}" /> + +<b:browseForServiceTemplatePropertyReqOrCap definedPropertiesAsJSONString="${it.definedPropertiesAsJSONString}" /> + +<div class="modal fade" id="propertyMappingDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add property mapping</h4> + </div> + <div class="modal-body"> + <form id="propertyMappingForm" enctype="multipart/form-data"> + <fieldset> + <div class="form-group"> + <label for="serviceTemplatePropertyRef">Service Template Property</label> + <div class="row"> + <div class="col-xs-10"> + <input name="serviceTemplatePropertyRef" id="serviceTemplatePropertyRef" class="form-control" type="text" required="required"> + </div> + <div class="col-xs-2"> + <button type="button" class="btn btn-default btn-sm" onclick="browseForServiceTemplateProperty($('#serviceTemplatePropertyRef'));">Browse</button> + </div> + </div> + </div> + + <div class="form-group"> + <label for="targetObjectRef">Target: Node Template, Requirement, Capability, or Relationship Template</label> + <div class="row"> + <div class="col-xs-4"> + <input name="targetObjectRef" id="targetObjectRef" class="form-control" type="text" required="required"> + </div> + <div class="col-xs-2"> + <button type="button" class="btn btn-default btn-sm" onclick="browseForTemplateAndProperty();">Browse</button> + </div> + </div> + </div> + + <div class="form-group"> + <label for="targetPropertyRef">Target Property</label> + <input name="targetPropertyRef" id="targetPropertyRef" class="form-control" type="text" required="required"/> + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button id="addPropertyMapping" type="button" class="btn btn-primary" onclick="addPropertyMapping()">Add</button> + <button id="updatePropertyMapping" type="button" class="btn btn-primary" onclick="updatePropertyMapping()">Update</button> + </div> + </div> + </div> +</div> + +<div class="modal fade" id="propertyConstraintDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add property constraint</h4> + </div> + <div class="modal-body"> + <form id="propertyMappingForm" enctype="multipart/form-data"> + <fieldset> + <div class="form-group"> + <label for="serviceTemplatePropertyRef">Service Template Property</label> + <div class="row"> + <div class="col-xs-10"> + <input name="serviceTemplatePropertyRef" id="serviceTemplatePropertyRefForConstraint" class="form-control" type="text" /> + </div> + <div class="col-xs-2"> + <button type="button" class="btn btn-default btn-sm" onclick="browseForServiceTemplateProperty($('#serviceTemplatePropertyRefForConstraint'));">Browse</button> + </div> + </div> + </div> + + <w:typeswithshortnameasselect label="Constraint Type" selectname="constraintType" type="constrainttype" typesWithShortNames="${it.constraintTypes}"/> + + <div class="form-group"> + ... constraint fragment ... + </div> + </fieldset> + </form> + </div> + + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button id="addPropertyConstraint" type="button" class="btn btn-primary" onclick="addPropertyMapping()">Add</button> + <button id="updatePropertyConstraint" type="button" class="btn btn-primary" onclick="updatePropertyMapping()">Update</button> + </div> + </div> + </div> +</div> + + + +<div id="alltabswithcontent"> +<ul class="nav nav-tabs" id="myTab"> + <li class="active"><a href="#properties">Properties</a></li> + <li><a href="#propertymappings">Property Mappings</a></li> + <li><a href="#propertyconstraints">Property Constraints</a></li> + <li><a href="#requirements">Requirements</a></li> + <li><a href="#capabilities">Capabilities</a></li> + <li><a href="#policies">Policies</a></li> + <li><a href="#interfaces">Interfaces</a></li> + <li><a href="#xml">XML</a></li> +</ul> + +<div class="tab-content"> + + <div class="tab-pane active" id="properties"> + <%-- reloadAfterSuccess is necessary as the XMLtree has to be changed --%> + <o:orioneditorarea areaid="XMLtextarea" url="boundarydefinitions/properties" reloadAfterSuccess="true">${it.definedPropertiesAsEscapedHTML}</o:orioneditorarea> + </div> + + <div class="tab-pane" id="propertymappings"> + <c:choose> + <c:when test="${empty it.definedPropertiesAsEscapedHTML}"> + <p>No properties available. Thus, no properties can be mapped. Please define properties.</p> + </c:when> + <c:otherwise> + <button id="deleteRequirement" class="rightbutton btn btn-xs btn-danger" onclick="deleteOnServerAndInTable(propertyMappingsTableInfo, 'Property Mapping', 'boundarydefinitions/propertymappings/');">Remove</button> + <button class="rightbutton btn btn-xs btn-info" onclick="openAddPropertyMappingDiag();">Add</button> + <button class="rightbutton btn btn-xs btn-primary" onclick="openUpdatePropertyMappingDiag();">Edit</button> + <table id="propertyMappingsTable"> + <thead> + <tr> + <th>Service Template Property</th> + <th>Target</th> + <th>Target Property</th> + </tr> + </thead> + <tbody> + <c:if test="${not empty it.defs.properties and not empty it.defs.properties.propertyMappings and not empty it.defs.properties.propertyMappings.propertyMapping}"> + <c:forEach items="${it.defs.properties.propertyMappings.propertyMapping}" var="propertyMapping"> + <tr> + <td>${propertyMapping.serviceTemplatePropertyRef}</td> + <td>${propertyMapping.targetObjectRef.id}</td> <%-- .name cannot be used as it is not an Id. Future work: Store the id in a seperate field and show the name to the user --%> + <td>${propertyMapping.targetPropertyRef}</td> + </tr> + </c:forEach> + </c:if> + </tbody> + </table> + </c:otherwise> + </c:choose> + </div> + + <%-- TODO: provide this as .tag. The property constraint resource should also be provided as tag --%> + <div class="tab-pane" id="propertyconstraints"> + <button class="rightbutton btn btn-xs btn-danger" onclick="deleteOnServerAndInTable(propertyConstraintsTableInfo, 'Property Constraint', 'propertyconstraints/');">Remove</button> + <button class="rightbutton btn btn-xs btn-info" onclick="openAddPropertyConstraintDiag();">Add</button> + <button class="rightbutton btn btn-xs btn-primary" onclick="openUpdatePropertyConstraintDiag();">Edit</button> + <table id="propertyconstraintstable"> + <thead> + <tr> + <th>(internal id)</th> + <th>Service Template Property</th> + <th>Constraint Type</th> + <th>Constraint</th> + </tr> + </thead> + <tbody> + <tr> + <td>example</td> + <td>/demo</td> + <td>http://www.example.com/accessrestrictions</td> + <td>(not yet implemented)</td> + </tr> + </tbody> + </table> + </div> + + <div class="tab-pane" id="requirements"> + <button class="rightbutton btn btn-xs btn-danger" onclick="deleteOnServerAndInTable(requirementsTableInfo, 'Requirement', 'boundarydefinitions/requirements/');">Remove</button> + <button class="rightbutton btn btn-xs btn-info" onclick="openReqEditor(false);">Add</button> + <button class="rightbutton btn btn-xs btn-primary" onclick="openReqEditor(true);">Edit</button> + <table id="requirementstable"> + <thead> + <tr> + <th>(Id)</th><%-- of the boundary requirement, also used as the id of this element--%> + <th>Name</th> + <th>Reference</th> + </tr> + </thead> + <tbody> + <c:forEach var="item" items="${it.defs.requirements.requirement}"> + <tr> + <td>${wr:determineIdUsingHashCode(item)}</td> + <td>${item.name}</td> + <td>${item.ref.id}</td> + </tr> + </c:forEach> + </tbody> + </table> + </div> + + <div class="tab-pane" id="capabilities"> + <%-- mirrored from requirements --%> + <button class="rightbutton btn btn-xs btn-danger" onclick="deleteOnServerAndInTable(capabilitiesTableInfo, 'Capability', 'boundarydefinitions/capabilities/');">Remove</button> + <button class="rightbutton btn btn-xs btn-info" onclick="openCapEditor(false);">Add</button> + <button class="rightbutton btn btn-xs btn-primary" onclick="openCapEditor(true);">Edit</button> + <table id="capabilitiestable"> + <thead> + <tr> + <th>(Id)</th><%-- of the boundary requirement, also used as the id of this element--%> + <th>Name</th> + <th>Reference</th> + </tr> + </thead> + <tbody> + <c:forEach var="item" items="${it.defs.capabilities.capability}"> + <tr> + <td>${wr:determineIdUsingHashCode(item)}</td> + <td>${item.name}</td> + <td>${item.ref.id}</td> + </tr> + </c:forEach> + </tbody> + </table> + </div> + + <div class="tab-pane" id="policies"> + <pol:policies list="${it.defs.policies.policy}" repositoryURL="${it.repositoryURL}" /> + <br /> + <button class="btn btn-default btn-sm btn-primary" onclick="savePolicies();">Save</button> + </div> + <script> + // work around for topology modeler's policy usage + $(".addnewpolicy").show(); + + // required for the policy addition dialog + winery.repositoryURL = "${it.repositoryURL}"; + + function savePolicies() { + require(["winery-support-common", "XMLWriter"], function(wsc) { + var xmlw = new XMLWriter("utf-8"); + xmlw.writeStartDocument(); + + wsc.writeCollectionDefinedByATextArea(xmlw, + $("div.policiesContainer").children("div.content").children("div.policy"), + "Policies"); + + xmlw.writeEndDocument(); + + var data = xmlw.flush(); + + $.ajax({ + url: "boundarydefinitions/policies", + data: data, + type: "PUT", + contentType: "application/xml", + }).done(function (result) { + vShowSuccess("Sucessfully saved policies"); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not save policies", jqXHR, errorThrown); + }); + }); + } + </script> + + <b:browseForX XLong="node template" XShort="NodeTemplate"/> + <script> + /** + * called from browseForX + */ + function setNodeTemplateRef() { + var newRef = $("#NodeTemplateReferenceField").val(); + $("#nodeTemplateRefForOperation").val(newRef); + storeNewReference(newRef); + updateTargetInterfaceAndOperation(true); + $("#browseForNodeTemplateDiag").modal("hide"); + } + + function browseForNodeTemplate() { + $("#NodeTemplateReferenceField").val($("#nodeTemplateRefForOperation").val()); + $("#browseForNodeTemplateDiag").modal("show"); + } + </script> + + <b:browseForX XLong="relationship template" XShort="RelationshipTemplate"/> + <script> + /** + * called from browseForX + */ + function setRelationshipTemplateRef() { + var newRef = $("#RelationshipTemplateReferenceField").val(); + $("#relationshipTemplateRefForOperation").val(newRef); + storeNewReference(newRef); + updateTargetInterfaceAndOperation(false); + $("#browseForRelationshipTemplateDiag").modal("hide"); + } + + function browseForRelationshipTemplate() { + $("#RelationshipTemplateReferenceField").val($("#relationshipTemplateRefForOperation").val()); + $("#browseForRelationshipTemplateDiag").modal("show"); + } + </script> + + <script> + function browseForPlan() { + vShowError("not yet implemented."); + } + </script> + + <div class="tab-pane" id="interfaces"> + <h4>Provided Interface and Operation</h4> + + <form class="form-horizontal"> + <div class="form-group"> + <label for="interface" class="col-sm-1 control-label">Interface</label> + <div class="col-sm-8"> + <input id="interface" class="form-control" placeholder="NCName or URI"> + </div> + <button type="button" class="btn btn-danger btn-sm col-sm-1" onclick="deleteCurrentlySelectedInterface();">Delete</button> + </div> + <div class="form-group"> + <label for="operation" class="col-sm-1 control-label">Operation</label> + <div class="col-sm-8"> + <input id="operation" class="form-control" placeholder="NCName"> + </div> + <button type="button" class="btn btn-danger btn-sm col-sm-1" onclick="deleteCurrentlySelectedOperation();">Delete</button> + </div> + </form> + + <h4>Target</h4> + + <form id="reftargettypeForm"> + <label> + <input id="nodeRadio" type="radio" name="reftargettype" value="node" checked="checked"> + Node Template + </label> + <label> + <input id="relationshipRadio" type="radio" name="reftargettype" value="relationship"> + Relationship Template + </label> + <label> + <input id="planRadio" type="radio" name="reftargettype" value="plan"> + Plan + </label> + </form> + + <form class="form-horizontal"> + <div class="form-group" id="selectNodeTemplateDiv"> + <label for="nodeTemplateRefForOperation" class="col-sm-1 control-label">Reference</label> + <div class="col-sm-8"> + <input id="nodeTemplateRefForOperation" class="form-control"> + </div> + <button type="button" class="btn btn-default btn-sm col-sm-1" onclick="browseForNodeTemplate();">Browse</button> + </div> + + <div class="form-group" id="selectRelationshipTemplateDiv" style="display:none;"> + <label for="relationshipTemplateRefForOperation" class="col-sm-1 control-label">Reference</label> + <div class="col-sm-8"> + <input id="relationshipTemplateRefForOperation" class="form-control"> + </div> + <button type="button" class="btn btn-default btn-sm col-sm-1" onclick="browseForRelationshipTemplate();">Browse</button> + </div> + + <div class="form-group" id="selectPlanDiv" style="display:none;"> + <label for="planRefForOperation" class="col-sm-1 control-label">Reference</label> + <div class="col-sm-8"> + <c:choose> + <c:when test="${empty it.listOfAllPlans}"> + <p>No plans available> + </c:when> + <c:otherwise> + <a id="planRefForOperation" href="#"></a> + </c:otherwise> + </c:choose> + </div> + </div> + </form> + + <h4>Target Interface and Operation</h4> + <form class="form-horizontal"> + <div class="form-group" id="selectInterfaceNameDiv"> + <label for="TargetInterface" class="col-sm-1 control-label">Interface</label> + <div class="col-sm-8"> + <input id="TargetInterface" class="form-control"> + </div> + </div> + + <div class="form-group" id="selectOperationNameDiv"> + <label for="TargetOperation" class="col-sm-1 control-label">Operation</label> + <div class="col-sm-8"> + <input id="TargetOperation" class="form-control"> + </div> + </div> + </form> + + <div id="notApplicableDiv" style="display:none;"> + <p>not applicable in the case of plans</p> + </div> + + </div> + + <script> + // initialize interface selection + require(["winery-support-common"], function(wsc) { + wsc.fetchSelect2DataAndInitSelect2("interface", "boundarydefinitions/interfaces/?select2", function() { + $("#interface").on("change", function() { + updateOperationsField(); + }); + if ($("#interface").select2("val") != "") { + updateOperationsField(); + } + }, true); + }); + + function getInterfacesAndInterfaceURLs() { + var iface = $("#interface").select2("val"); + iface = encodeID(iface); + + var ifacesURL = "boundarydefinitions/interfaces/"; + var ifaceURL = ifacesURL + iface + "/"; + return { + ifacesURL: ifacesURL, + ifaceURL: ifaceURL + } + } + + function getOperationsAndOperationURLs() { + var ifaceURL = getInterfacesAndInterfaceURLs().ifaceURL; + var operation = $("#operation").select2("val"); + operation = encodeID(operation); + + var operationsURL = ifaceURL + "exportedoperations/"; + var operationURL = operationsURL + operation + "/"; + return { + operationsURL: operationsURL, + operationURL: operationURL + } + } + + /** + * Updates the field of the exported operation + */ + function updateOperationsField() { + var iface = $("#interface").select2("val"); + var urls = getInterfacesAndInterfaceURLs(); + + $.ajax({ + url: urls.ifaceURL, + type: "HEAD", + async: false, + error: function(jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 404) { + // everything allright -> user entered a new interface + $.ajax({ + url: urls.ifacesURL, + async: false, + type: "POST", + data: JSON.stringify({name: iface}), + contentType: "application/json" + }).done(function (result) { + vShowSuccess("Sucessfully created interface"); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create interface", jqXHR, errorThrown); + }); + } else { + vShowAJAXError("Could not check for interface existance", jqXHR, errorThrown); + } + } + }); + + var url = urls.ifaceURL + "exportedoperations/?select2"; + require("winery-support-common").fetchSelect2DataAndInitSelect2("operation", url, function(){ + updateTarget(); + }, true); + } + + $("#operation").on("change", function() { + var operation = $("#operation").select2("val"); + var urls = getOperationsAndOperationURLs(); + $.ajax({ + url: urls.operationURL, + type: "HEAD", + async: false, + error: function(jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 404) { + // everything allright -> user entered a new operation + $.ajax({ + url: urls.operationsURL, + async: false, + type: "POST", + data: JSON.stringify({name: operation}), + contentType: "application/json" + }).done(function (result) { + vShowSuccess("Sucessfully created operation"); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create interface", jqXHR, errorThrown); + }); + } else { + vShowAJAXError("Could not check for interface operation", jqXHR, errorThrown); + } + } + }); + + updateTarget(); + }) + + /** + * Updates the content at "Target": Reference and Target Interface/Operation + */ + function updateTarget() { + var operation = $("#operation").select2("val"); + if (operation != "") { + var urls = getOperationsAndOperationURLs(); + // At the beginning of the usage, there is no operation selected + // Just fill the data if an operation is chosen + var url = urls.operationURL; + + // store URL for later use - this avoids global JavaScript variables + $("#operation").data("url", url); + + $.ajax({ + url: url, + dataType: "json" + }).done(function (data) { + if ((data.type == "NodeOperation") || (data.type == "RelationshipOperation")) { + if (data.type == "NodeOperation") { + $("#nodeRadio").prop("checked", true); + $("#nodeTemplateRefForOperation").val(data.ref); + updateTargetInterfaceAndOperation(true, data.interfacename, data.operationname); + } else { + $("#relationshipRadio").prop("checked", true); + $("#relationshipTemplateRefForOperation").val(data.ref); + updateTargetInterfaceAndOperation(false, data.interfacename, data.operationname); + } + } else if (data.type == "Plan") { + $("#planRadio").prop("checked", true); + $("#planRefForOperation").editable("setValue", data.ref); + } else if (data.type == null) { + // nothing set yet; set node as type + putType("NodeOperation"); + $("#nodeRadio").prop("checked", true); + // no reference is set if no type is set -> clear field + $("#nodeTemplateRefForOperation").val(""); + } else { + vShowError("Unexpected type '" + data.type + "'."); + return; + } + adaptVisibilityOfDivsAccordingToReferenceType(); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch data of exported operation from " + url, jqXHR, errorThrown); + }); + } + + } + + function adaptVisibilityOfDivsAccordingToReferenceType() { + var checked = $('input[name=reftargettype]:checked').val(); + if (checked == "node") { + $("#selectNodeTemplateDiv").show(); + $("#selectRelationshipTemplateDiv").hide(); + $("#selectPlanDiv").hide(); + $("#selectInterfaceNameDiv").show(); + $("#selectOperationNameDiv").show(); + $("#notApplicableDiv").hide(); + } else if (checked == "relationship") { + $("#selectNodeTemplateDiv").hide(); + $("#selectRelationshipTemplateDiv").show(); + $("#selectPlanDiv").hide(); + $("#selectInterfaceNameDiv").show(); + $("#selectOperationNameDiv").show(); + $("#notApplicableDiv").hide(); + } else if (checked == "plan") { + $("#selectNodeTemplateDiv").hide(); + $("#selectRelationshipTemplateDiv").hide(); + $("#selectPlanDiv").show(); + $("#selectInterfaceNameDiv").hide(); + $("#selectOperationNameDiv").hide(); + $("#notApplicableDiv").show(); + } else { + vShowError("UI in inconsistent state: wrong branch in adaptVisibilityOfDivsAccordingToReferenceType"); + } + } + </script> + + <div class="tab-pane" id="xml"> + <o:orioneditorarea areaid="XML" url="boundarydefinitions/" reloadAfterSuccess="true">${it.boundaryDefinitionsAsXMLStringEncoded}</o:orioneditorarea> + </div> +</div> +</div> + +<script> +$('#myTab a').click(function (e) { + e.preventDefault(); + $(this).tab('show'); +}); + +function openPropertyConstraintEditor() { + vShowError("not yet implemented"); + // TODO: fill diag with the values of the table + // $('#addPropertyConstraintDiag').modal('show'); +} + + +var propertyConstraintsTableInfo = { + id: '#propertyconstraintstable' +}; +var requirementsTableInfo = { + id: '#requirementstable' +}; +var capabilitiesTableInfo = { + id: '#capabilitiestable' +}; +var interfacesTableInfo = { + id: '#interfacestable' +}; +var propertyMappingsTableInfo = { + id: '#propertyMappingsTable' + }; + +require(["winery-support"], function(ws) { + var firstColumnIsHidden = { + aoColumnDefs: [ + { "bSearchable": false, "bVisible": false, "aTargets": [ 0 ] } + ] + }; + + ws.initTable(propertyConstraintsTableInfo, firstColumnIsHidden); + ws.initTable(requirementsTableInfo, firstColumnIsHidden); + ws.initTable(capabilitiesTableInfo, firstColumnIsHidden); + + ws.initTable(interfacesTableInfo); + ws.initTable(propertyMappingsTableInfo); +}); + +<%-- === BEGIN: Property Constraints === --%> + +function openUpdatePropertyConstraintDiag() { + if (propertyConstraintsTableInfo.selectedRow) { + require(["winery-support"], function(ws) { + if (ws.isEmptyTable(propertyConstraintsTableInfo)) { + vShowError("No property constraints available"); + return; + } + + $("#addPropertyConstraint").hide(); + $("#updatePropertyConstraint").show(); + + // put value in fields + var children = $(propertyMappingsTableInfo.selectedRow).children("td"); + $("#serviceTemplatePropertyRefForConstraint").val($(children[1]).text()); + $("#constraintType").val($(children[2]).text()); + // TODO: value of the constraint + + $('#propertyConstraintDiag').modal('show'); + + vShowError("Not yet implemented."); + }); + } else { + vShowError("No property constraint selected"); + } +} + +function openAddPropertyConstraintDiag() { + $("#addPropertyConstraint").show(); + $("#updatePropertyConstraint").hide(); + + // reset all fields + $("#serviceTemplatePropertyRefForConstraint").val(""); + // TODO: value of the constraint + + $('#propertyConstraintDiag').modal('show'); + + vShowError("Not yet implemented."); +} + +<%-- === END: Property Constraints === --%> + + +<%-- === BEGIN: Property Mapping === --%> + +function openUpdatePropertyMappingDiag() { + if (propertyMappingsTableInfo.selectedRow) { + require(["winery-support"], function(ws) { + if (ws.isEmptyTable(propertyMappingsTableInfo)) { + vShowError("No property mappings available"); + return; + } + + $("#addPropertyMapping").hide(); + $("#updatePropertyMapping").show(); + + // put value in fields + var children = $(propertyMappingsTableInfo.selectedRow).children("td"); + $("#serviceTemplatePropertyRef").val($(children[0]).text()); + $("#targetObjectRef").val($(children[1]).text()); + $("#targetPropertyRef").val($(children[2]).text()); + + $('#propertyMappingDiag').modal('show'); + }); + } else { + vShowError("No property mapping selected"); + } +} + +function openAddPropertyMappingDiag() { + $("#addPropertyMapping").show(); + $("#updatePropertyMapping").hide(); + + // reset all fields + $("#serviceTemplatePropertyRef").val(""); + $("#targetObjectRef").val(""); + $("#targetPropertyRef").val(""); + + $('#propertyMappingDiag').modal('show'); +} + +function addOrUpdatePropertyMapping(add) { + var serviceTemplatePropertyRef = $("#serviceTemplatePropertyRef").val(); + var targetObjectRef = $("#targetObjectRef").val(); + var targetPropertyRef = $("#targetPropertyRef").val(); + + $.ajax({ + url: "boundarydefinitions/propertymappings", + type: "POST", + async: false, + data: { + serviceTemplatePropertyRef: serviceTemplatePropertyRef, + targetObjectRef: targetObjectRef, + targetPropertyRef: targetPropertyRef + }, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not POST property mapping", jqXHR, errorThrown); + }, + success: function(data, textSTatus, jqXHR) { + // put value from fields into table + if (add) { + propertyMappingsTableInfo.table.fnAddData([serviceTemplatePropertyRef, targetObjectRef, targetPropertyRef]); + } else { + var children = $(propertyMappingsTableInfo.selectedRow).children("td"); + $(children[0]).text(serviceTemplatePropertyRef); + $(children[1]).text(targetObjectRef); + $(children[2]).text(targetPropertyRef); + } + + $('#propertyMappingDiag').modal('hide'); + + vShowSuccess("Successfully posted property mapping."); + } + }); +} + +function addPropertyMapping() { + addOrUpdatePropertyMapping(true); +} + +function updatePropertyMapping() { + addOrUpdatePropertyMapping(false); +} + +<%-- === END: Property Mapping === --%> + + +//window.addEventListener('message', function(event){var v = document.getElementById('%s');if(v){v=v.firstChild; if(v && v.contentWindow === event.source){%s}}}) +window.addEventListener('message', function(event) { + if (event.data) { + if (event.data.targetObjectRef) { + // current API expects both fields + $(".newObjectRef").val(event.data.targetObjectRef); + $("#newObjectPropertyRef").val(event.data.targetPropertyRef); + } else if (event.data.reqRef) { + $("#ReqReferenceField").val(event.data.reqRef); + } else if (event.data.capRef) { + $("#CapReferenceField").val(event.data.capRef); + } else if (event.data.targetRelationshipTemplateRef) { + $("#RelationshipTemplateReferenceField").val(event.data.targetRelationshipTemplateRef); + } + } +}); + +function storeNewReference(ref) { + var url = $("#operation").data("url") + "/ref"; + $.ajax({ + url: url, + data: ref, + type: "PUT", + contentType: "text/plain", + }).done(function (result) { + vShowSuccess("Sucessfully saved reference"); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not set reference", jqXHR, errorThrown); + }); +} + +<c:if test="${not empty it.listOfAllPlans}"> +$("#planRefForOperation").editable({ + type: "select", + source: [ + <c:forEach var="item" items="${it.listOfAllPlans}"> + {value: "${item.id}", + text: "${item.text}"}, + </c:forEach> + ] +}).on("save", function(e, params) { + var newRef = params.newValue; + storeNewReference(newRef) +}); +</c:if> + +function putType(type) { + var url = $("#operation").data("url") + "/type"; + $.ajax({ + url: url, + data: type, + type: "PUT", + contentType: "text/plain", + }).done(function (result) { + vShowSuccess("Sucessfully changed reference type"); + adaptVisibilityOfDivsAccordingToReferenceType(); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not set new reference type", jqXHR, errorThrown); + }); +} + +function getInterfaceDataFromURL(ifaceURL) { + var select2data = null; + $.ajax({ + url: ifaceURL + "?select2", + async: false, + type: "GET", + dataType: "json", + success: function (data) { + select2data = data; + }, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not get interface data", jqXHR, errorThrown); + } + }); + return select2data; +} + +function getDataForUpdateTargetOperation(url, showError) { + var select2data = null; + $.ajax({ + url: url + "?select2", + async: false, + type: "GET", + dataType: "json", + success: function (data) { + select2data = data; + }, + error: function(jqXHR, textStatus, errorThrown) { + if (showError) { + vShowAJAXError("Could not get operation data", jqXHR, errorThrown); + } + } + }); + return select2data; +} + +function updateTargetOperation(operationNameToSelect) { + var ifaceURL = $("#TargetInterface").data("url2"); + var select2data = null; + var operationsURL; + + // we don't store the interface-URL at #TargetInterface, but do a quick hack here + if (ifaceURL != null) { + operationsURL = ifaceURL + "/" + encodeID($("#TargetInterface").val()) + "/operations/"; + select2data = getDataForUpdateTargetOperation(operationsURL, false); + } + + // either only one URL or nothing found at second URL --> try first URL + if (select2data == null) { + ifaceURL = $("#TargetInterface").data("url1"); + operationsURL = ifaceURL + "/" + encodeID($("#TargetInterface").val()) + "/operations/"; + select2data = getDataForUpdateTargetOperation(operationsURL, true); + } + + if (select2data != null) { + $("#TargetOperation").select2({ + data:select2data + }); + var valueToSelect = null; + if ((typeof operationNameToSelect !== "undefined") && (operationNameToSelect != null)) { + valueToSelect = operationNameToSelect; + } else { + // called without existing data --> insert pseudo data and store it at the backend to ensure consistency + if (select2data.length > 0) { + valueToSelect = select2data[0].id; + storeTargetOperation(valueToSelect); + } + } + if (valueToSelect != null) { + $("#TargetOperation").select2('val', valueToSelect); + } + } + +} + +function updateTargetInterfaceAndOperationFromInterfaceURL(ifaceURL, interfaceNameToSelect, operationNameToSelect) { + var select2data; + if (typeof ifaceURL === "string") { + select2data = getInterfaceDataFromURL(ifaceURL); + $("#TargetInterface").data("url1", ifaceURL); + $("#TargetInterface").data("url2", null); + } else { + // TODO: instead of hacking with two urls (especially at other places in the code), we should prefix the entries with S| at the source interface and T| at the target interface + select2data = getInterfaceDataFromURL(ifaceURL[0]); + var select2data2 = getInterfaceDataFromURL(ifaceURL[1]); + $.merge(select2data, select2data2); + $("#TargetInterface").data("url1", ifaceURL[0]); + $("#TargetInterface").data("url2", ifaceURL[1]); + } + $("#TargetInterface").select2({data:select2data}); + + var valueToSelect = null; + if ((typeof interfaceNameToSelect !== "undefined") && (interfaceNameToSelect != null)) { + valueToSelect = interfaceNameToSelect; + } else { + // called without existing data --> insert pseudo data and store it at the backend to ensure consistency + if (select2data.length > 0) { + valueToSelect = select2data[0].id; + storeTargetInterface(valueToSelect); + } + } + if (valueToSelect != null) { + $("#TargetInterface").select2('val', valueToSelect); + } + + updateTargetOperation(operationNameToSelect); +} + +function updateTargetInterfaceAndOperation(isNodeTemplate, interfaceNameToSelect, operationNameToSelect) { + var url = "topologytemplate/"; + url = url + (isNodeTemplate ? "nodetemplates" : "relationshiptemplates" + "/"); + var templateId = isNodeTemplate ? $("#nodeTemplateRefForOperation").val() : $("#relationshipTemplateRefForOperation").val(); + if (templateId == "") { + // if no template is provided, we just return + return; + } + url = url + "/" + templateId + "/type"; + $.ajax({ + url: url, + type: "GET", + dataType: "text" + }).done(function (typeQName) { + require(["winery-support-common"], function(wsc) { + var urlDetermination = isNodeTemplate ? wsc.makeNodeTypeURLFromQName : wsc.makeRelationshipTypeURLFromQName; + var typeURL = urlDetermination("${it.repositoryURL}", typeQName) + if (isNodeTemplate) { + updateTargetInterfaceAndOperationFromInterfaceURL(typeURL + "/interfaces", interfaceNameToSelect, operationNameToSelect); + } else { + updateTargetInterfaceAndOperationFromInterfaceURL([typeURL + "/sourceinterfaces/", typeURL + "/targetinterfaces/"], interfaceNameToSelect, operationNameToSelect); + } + }); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not get type of node / relationship", jqXHR, errorThrown); + }); + +} + +$("#nodeRadio").on("change", function() { + putType("NodeOperation"); + updateTargetInterfaceAndOperation(true); +}); +$("#relationshipRadio").on("change", function() { + putType("RelationshipOperation"); + updateTargetInterfaceAndOperation(false); +}); +$("#planRadio").on("change", function() { + putType("Plan"); +}); + +$("#nodeTemplateRefForOperation").on("change", function() { + updateTargetInterfaceAndOperation(true); +}); + +$("#relationshipTemplateRefForOperation").on("change", function() { + updateTargetInterfaceAndOperation(false); +}); + +function storeTargetInterface(val) { + val = val || $("#TargetInterface").select2("val"); + var url = $("#operation").data("url") + "interfacename"; + // when selecting a new operation, both targetinterface and targetoperation are updated; this leads to race conditions at the backend and one chang would be lost. Therefore, we do the calls synchronously + $.ajax({ + url: url, + data: val, + type: "PUT", + contentType: "text/plain", + async:false + }).done(function (result) { + vShowSuccess("Sucessfully saved interface name"); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not set interface name", jqXHR, errorThrown); + }); +} + +function storeTargetOperation(val) { + val = val || $("#TargetOperation").select2("val"); + var url = $("#operation").data("url") + "operationname"; + // when selecting a new operation, both targetinterface and targetoperation are updated; this leads to race conditions at the backend and one chang would be lost. Therefore, we do the calls synchronously + $.ajax({ + url: url, + data: val, + type: "PUT", + contentType: "text/plain", + async:false + }).done(function (result) { + vShowSuccess("Sucessfully saved operation name"); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not set operation name", jqXHR, errorThrown); + }); +} + +$("#TargetInterface").on("change", function() { + storeTargetInterface(); + updateTargetOperation(); +}); + +$("#TargetOperation").on("change", function() { + storeTargetOperation(); +}); + +function deleteCurrentlySelectedInterface() { + vConfirmYesNo("Do you really want to delete this interface?", function() { + var url = getInterfacesAndInterfaceURLs().ifaceURL; + $.ajax({ + url: url, + type: "DELETE" + }).done(function () { + require(["winery-support-common"], function (wsc) { + wsc.removeItemFromSelect2Field($("#interface"), $("#interface").select2("data").id); + vShowSuccess("Successfully deleted interface"); + }); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not delete interface", jqXHR, errorThrown); + }); + }); +} + +function deleteCurrentlySelectedOperation() { + vConfirmYesNo("Do you really want to delete this operation?", function() { + var url = getOperationsAndOperationURLs().operationURL; + $.ajax({ + url: url, + type: "DELETE" + }).done(function () { + require(["winery-support-common"], function (wsc) { + wsc.removeItemFromSelect2Field($("#operation"), $("#operation").select2("data").id); + vShowSuccess("Successfully deleted operation"); + }); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not delete operation", jqXHR, errorThrown); + }); + }); +} + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/plans/plans.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/plans/plans.jsp new file mode 100644 index 0000000..ca50be4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/plans/plans.jsp @@ -0,0 +1,266 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="p" tagdir="/WEB-INF/tags/parameters" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<script> + +var embeddedPlansTableInfo = { + id: '#embeddedPlansTable' +}; + +var linkedPlansTableInfo = { + id: '#linkedPlansTable' +}; + +$(function() { + require(["winery-support"], function(ws) { + ws.initTable(embeddedPlansTableInfo, { + "aoColumns": [ + { "bVisible": false, "bSearchable": false}, // ID column + { "sTitle": "Precondition" }, + { "sTitle": "Name" }, + { "sTitle": "Type" }, + { "sTitle": "Language" } + ], + "aaData" : ${it.embeddedPlansTableData} + }); + + ws.initTable(linkedPlansTableInfo, { + "aoColumns": [ + { "bVisible": false, "bSearchable": false}, // ID column + { "sTitle": "Precondition" }, + { "sTitle": "Name" }, + { "sTitle": "Type" }, + { "sTitle": "Language" }, + { "sTitle": "Reference" } + ], + "aaData" : ${it.linkedPlansTableData} + }); + }); +}); + +function editIOParameters() { + if (embeddedPlansTableInfo.selectedRow) { + require(["winery-support"], function(ws) { + if (ws.isEmptyTable(embeddedPlansTableInfo)) { + vShowError("No plans available"); + return; + } + updateInputAndOutputParameters(getPlanURL()); + $("#editParametersDiag").modal("show"); + }); + } else { + vShowError("No plan selected"); + } +} + function createPlan(data) { + if (highlightRequiredFields()) { + vShowError("Please fill out all required fields"); + return; + } + data.submit(); + } + + function getPlanURL() { + var id = embeddedPlansTableInfo.table.fnGetData(embeddedPlansTableInfo.selectedRow, 0); + return "plans/" + encodeURIComponent(id) + "/"; + } + + function openPlanEditor() { + if (embeddedPlansTableInfo.selectedRow) { + var isEmptyTable = embeddedPlansTableInfo.table.children("tbody").children("tr").first().children("td").hasClass("dataTables_empty"); + if (isEmptyTable) { + vShowError("No plans available"); + return; + } + window.open(getPlanURL() + "?edit", "_blank"); + } else { + vShowError("No plan selected"); + } + } + + function letUserChooseAPlan() { + $('#planFileInput').trigger('click'); + $('#planChooseBtn').focus(); + } + + requirejs(["jquery.fileupload"], function(){ + $('#addPlanForm').fileupload().bind("fileuploadadd", function(e, data) { + $.each(data.files, function (index, file) { + $("#planFileText").val(file.name); + }); + $("#addPlanBtnFUP").off("click"); + $("#addPlanBtnFUP").on("click", function() { + createPlan(data); + }); + }).bind("fileuploadstart", function(e) { + $("#addPlanBtnFUP").button("loading"); + }).bind('fileuploadfail', function(e, data) { + vShowAJAXError("Could not add plan", data.jqXHR, data.errorThrown); + $("#addPlanBtnFUP").button("reset"); + }).bind('fileuploaddone', function(e, data) { + vShowSuccess("Plan created successfully"); + + // reset the add button + $("#addPlanBtnFUP").button("reset"); + // do not allow submission of the old files on a click if the dialog is opened another time + $("#addPlanBtnFUP").off("click"); + + // TODO: if id is already present in table, delete row in table + + embeddedPlansTableInfo.table.fnAddData(data.result.tableData); + + $('#addPlanDiag').modal('hide'); + }); + }); +</script> + +<div class="modal fade" id="addPlanDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add Plan</h4> + </div> + <div class="modal-body"> + <form id="addPlanForm" enctype="multipart/form-data" action="plans/" method="post"> + <div class="form-group"> + <label class="control-label">Name</label> + <input name="planName" id="planName" type="text" class="form-control" required="required"> + </div> + + <t:typeswithshortnameasselect label="Type" type="plantype" selectname="planType" typesWithShortNames="${it.planTypes}"> + </t:typeswithshortnameasselect> + + <t:typeswithshortnameasselect label="Language" type="planlanguage" selectname="planLanguage" typesWithShortNames="${it.planLanguages}"> + </t:typeswithshortnameasselect> + + <div class="form-group" id="fileDiv"> + <label class="control-label" for="planFileDiv">Archive</label> + <div style="display: block; width: 100%" id="planFileDiv"> + <input id="planFileInput" name="file" type="file" style="display:none"> + <input name="fileText" id="planFileText" type="text" class="form-control" style="width:300px; display:inline;" onclick="letUserChooseAPlan();" required="required"> + <button type="button" id="planChooseBtn" class="btn btn-default btn-xs" onclick="letUserChooseAPlan();">Choose</button> + </div> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" data-loading-text="Uploading..." id="addPlanBtnFUP">Add</button> + <button type="button" class="btn btn-primary" style="display:none;" id="addPlanBtnBPMN4TOSCA">Add</button> + </div> + </div> + </div> +</div> + +<script> +$("#planLanguage").on("change", function(e) { + var lang = $("#planLanguage").val(); + if (lang == "http://www.opentosca.org/bpmn4tosca") { + $("#fileDiv").hide(); + $("#addPlanBtnFUP").hide(); + $("#addPlanBtnBPMN4TOSCA").show(); + } else { + $("#fileDiv").show(); + $("#addPlanBtnFUP").show(); + $("#addPlanBtnBPMN4TOSCA").hide(); + } +}); + +$("#addPlanBtnBPMN4TOSCA").on("click", function() { + var data = new FormData(); + data.append("planName", $("#planName").val()); + data.append("planType", $("#planType").val()); + data.append("planLanguage", $("#planLanguage").val()); + + $.ajax({ + url: "plans/", + type: "POST", + async: false, + contentType: false, // jQuery automatically sets multipart/form-data; boundary=... + data: data, + processData: false, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add BPMN4TOSCSA plan", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + //typesTableInfo.table.fnAddData([$('#shortname').val(), $('#type').val()]); + $('#addPlanDiag').modal('hide'); + vShowSuccess("Successfully added plan. Please refresh the page."); + } + }); + +}); +</script> + +<p:parametersJS></p:parametersJS> + +<div class="modal fade" id="editParametersDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Edit Parameters</h4> + </div> + <div class="modal-body"> + <p:parametersInput baseURL="getPlanURL()"></p:parametersInput> + <p:parametersOutput baseURL="getPlanURL()"></p:parametersOutput> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> +</div> + + <div id="managementPlans"> + <h4>Embedded Plans</h4> + <button class="rightbutton btn btn-xs btn-danger" onclick="deleteOnServerAndInTable(embeddedPlansTableInfo, 'Plan', 'plans/', 0, 2);">Remove</button> + <button class="rightbutton btn btn-xs btn-info" onclick="$('#addPlanDiag').modal('show');">Add</button> + <button class="rightbutton btn btn-xs btn-default" onclick="editIOParameters();">I/O Parameters</button> + <button class="rightbutton btn btn-xs btn-primary" onclick="openPlanEditor();">Edit</button> +<% +if (org.eclipse.winery.repository.Prefs.INSTANCE.isPlanBuilderAvailable()) { +%> + <script> + function generateBuildPlan() { + $("#btnGenerateBuildPlan").button('loading'); + $.ajax({ + url: 'topologytemplate/', + // targeting method triggerGenerateBuildPlan in TopologyTemplateResource.java + dataType: "text" + }).fail(function(jqXHR, textStatus, errorThrown) { + $("#btnGenerateBuildPlan").button('reset'); + vShowAJAXError("Could not trigger plan generation.", jqXHR, errorThrown); + }).done(function(data, textStatus, jqXHR) { + $("#btnGenerateBuildPlan").button('reset'); + var resultText = "Successfully generated build plan. Please refresh the page."; + vShowSuccess(resultText); + }); + } + </script> + <button id="btnGenerateBuildPlan" class="btn btn-xs btn-default" data-loading-text="Generating..." onclick="generateBuildPlan();">Generate Build Plan</button> +<% +} +%> + <table cellpadding="0" cellspacing="0" border="0" class="display" id="embeddedPlansTable"></table> + + <br /><br /> + <h4>Linked Plans</h4> + <table cellpadding="0" cellspacing="0" border="0" class="display" id="linkedPlansTable"></table> + </div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/selfservicemetadata/selfservicemetadata.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/selfservicemetadata/selfservicemetadata.jsp new file mode 100644 index 0000000..d4d9233 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/selfservicemetadata/selfservicemetadata.jsp @@ -0,0 +1,256 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<%-- Upload functionality inspired by plans.jsp. That code could be generalized somehow in a .tag file --%> + +<ul class="nav nav-tabs" id="myTab"> + <li class="active"><a href="#description">Description</a></li> + <li><a href="#images">Images</a></li> + <li><a href="#options">Options</a></li> + <li><a href="#xml" id="showXMLTab">XML</a></li> +</ul> + +<div class="tab-content"> + + <div class="tab-pane active" id="description"> + <div class="form-group"> + <label class="label-form">Name</label> + <a href="#" class="form-control" data-send="always" id="displayName" data-url="selfserviceportal/displayname" data-tile="Enter Display Name">${it.application.displayName}</a> + </div> + + <div class="form-group"> + <label class="label-form">Description</label> + <div class="form-control" id="applicationDescriptionDiv">${it.application.description}</div> + </div> + </div> + + <div class="tab-pane" id="images"> + + <t:imageUpload + label="Icon" + URL="selfserviceportal/icon.jpg" + id="upIcon" + width="16px" + accept="image/*"/> + + <t:imageUpload + label="Preview" + URL="selfserviceportal/image.jpg" + id="upImage" + width="100px" + accept="image/*"/> + + </div> + + <div class="tab-pane" id="options"> + <button class="rightbutton btn btn-xs btn-danger" name="remove" onclick="deleteOnServerAndInTable(optionsTableInfo, 'Option', 'selfserviceportal/options/', 0, 1);">Remove</button> + <button class="rightbutton btn btn-xs btn-info" name="add" onclick="$('#addOptionDiag').modal('show');">Add</button> + <!-- <button class="rightbutton btn btn-xs btn-default" name="edit" onclick="openOptionEditor();">Edit</button> --> + + <table id="optionsTable"> + <thead> + <tr> + <th>Id</th> + <th>Name</th> + <th>Icon</th> + <th>Plan Service Name</th> + </tr> + </thead> + <tbody> + <c:if test="${not empty it.application}"> + <c:forEach var="option" items="${it.application.options.option}"> + <tr> + <td>${option.id}</td> + <td>${option.name}</td> + <td><img src="selfserviceportal/options/${w:URLencode(option.id)}/icon.jpg" style="width:50px;"></td> + <td>${option.planServiceName}</td> + </tr> + </c:forEach> + </c:if> + </tbody> + </table> + </div> + + <div class="tab-pane" id="xml"> + <o:orioneditorarea areaid="XML" url="selfserviceportal/" reloadAfterSuccess="true">${it.applicationAsXMLStringEncoded}</o:orioneditorarea> + </div> + +</div> + +<script> +function letUserChooseAFile() { + $('#fileInput').trigger('click'); + $('#chooseBtn').focus(); +} + +$('#showXMLTab').on('shown.bs.tab', function (e) { + window.winery.orionareas['XML'].fixEditorHeight(); +}); +</script> + +<div class="modal fade" id="addOptionDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add Option</h4> + </div> + <div class="modal-body"> + <form id="addOptionForm" enctype="multipart/form-data" action="selfserviceportal/options/" method="post"> + <div class="form-group"> + <label class="control-label">Name</label> + <input name="name" type="text" class="form-control" required="required"> + </div> + + <div class="form-group"> + <label class="control-label">Description</label> + <textarea id="optionDescription" name="description" class="form-control" required="required"></textarea> + </div> + + <div class="form-group"> + <label class="control-label" for="fileDiv">Icon</label> + <div style="display: block; width: 100%" id="iconDiv"> + <input id="fileInput" name="file" type="file" style="display:none" accept="image/*"> + <input name="fileText" id="fileText" type="text" class="form-control" style="width:300px; display:inline;" onclick="letUserChooseAFile();" required="required"> + <button type="button" id="chooseBtn" class="btn btn-default btn-xs" onclick="letUserChooseAFile();">Choose</button> + </div> + </div> + + <div class="form-group"> + <label class="control-label">Plan Service Name</label> + <input name="planServiceName" type="text" class="form-control" required="required"> + </div> + + <div class="form-group"> + <label class="control-label">Plan Input Message</label> + <textarea name="planInputMessage" class="form-control" required="required" rows="20"><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> +<soapenv:Header/> +<soapenv:Body> +</soapenv:Body> +</soapenv:Envelope></textarea> + </div> + + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" data-loading-text="Uploading..." id="addOptionBtn">Add</button> + </div> + </div> + </div> +</div> + + +<script> +$("#displayName").editable({ + ajaxOptions: {type: "PUT"}, + success: function() { + vShowSuccess("Successfully updated display name"); + }, + error: function(response) { + vShowError("Could not update display name: " + response.status + " " + response.responseText); + } +}); + +$("#applicationDescriptionDiv").editable({ + type: "wysihtml5", + send: "always", + url: "selfserviceportal/description", + ajaxOptions: {type: "PUT"}, + success: function() { + vShowSuccess("Successfully updated description"); + }, + error: function(response) { + vShowError("Could not update description: " + response.status + " " + response.responseText); + } +}); + +$("#optionDescription").wysihtml5(); + +var optionsTableInfo = { + id: '#optionsTable' +}; + +$('#myTab a').click(function (e) { + e.preventDefault(); + $(this).tab('show'); +}); + +$(function() { + // initialize table and hide first column + require(["winery-support"], function(ws) { + ws.initTable(optionsTableInfo, { + "aoColumnDefs": [ + { "bSearchable": false, "bVisible": false, "aTargets": [ 0 ] } + ] + }); + }); + + $("#addOptionDiag").on("hidden.bs.modal", function() { + // we currently do not send data back from the server + // we emulate the AJAX refresh by a reaload + doTheTabSelection(function() { + $('#myTab a[href="#options"]').tab('show'); + }); + }); +}); + +function createOption(data) { + if (highlightRequiredFields()) { + vShowError("Please fill out all required fields"); + return; + } + data.submit(); +} + +requirejs(["jquery.fileupload"], function(){ + $('#addOptionForm').fileupload({ + // dropping should only be available in the addOptionDialog. This, however, does not work correctly + dropZone: $("#addOptionDiag") + }).bind("fileuploadadd", function(e, data) { + $.each(data.files, function (index, file) { + $("#fileText").val(file.name); + }); + $("#addOptionBtn").off("click"); + $("#addOptionBtn").on("click", function() { + createOption(data); + }); + }).bind("fileuploadstart", function(e) { + $("#addOptionBtn").button("loading"); + }).bind('fileuploadfail', function(e, data) { + vShowAJAXError("Could not add option", data.jqXHR, data.errorThrown); + $("#addOptionBtn").button("reset"); + }).bind('fileuploaddone', function(e, data) { + vShowSuccess("Option created successfully."); + + // reset the add button + $("#addOptionBtn").button("reset"); + // do not allow submission of the old files on a click if the dialog is opened another time + $("#addOptionBtn").off("click"); + + // TODO: add data + //embeddedPlansTableInfo.table.fnAddData(data.result.tableData); + // current workaround: event on hidden.bs.modal + + $('#addOptionDiag').modal('hide'); + }); +}); + +</script> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/servicetemplate.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/servicetemplate.jsp new file mode 100644 index 0000000..b5349d6 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/servicetemplate.jsp @@ -0,0 +1,43 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013, 2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page import="org.eclipse.winery.repository.resources.SubMenuData"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%-- add submenus after the submenus defined for the type --%> +<% +java.util.List<SubMenuData> subMenus = new java.util.ArrayList<SubMenuData>(5); + +SubMenuData data; + +data = new SubMenuData("#topologytemplate", "Topology Template"); +subMenus.add(data); + +data = new SubMenuData("#plans", "Plans"); +subMenus.add(data); + +data = new SubMenuData("#selfserviceportal", "Self-service Portal"); +subMenus.add(data); + +data = new SubMenuData("#boundarydefinitions", "Boundary Definitions"); +subMenus.add(data); + +//Tags are currently not implemented -> Don't confuse users by showing the tab +//has to be enabled again, when tags are implemented +//data = new SubMenuData("#tags", "Tags"); +//subMenus.add(data); +%> + +<t:componentinstance cssClass="serviceTemplate" selected="ServiceTemplate" subMenus="<%=subMenus%>"> +</t:componentinstance> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/topologytemplates/topologytemplate.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/topologytemplates/topologytemplate.jsp new file mode 100644 index 0000000..b5424ae --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/topologytemplates/topologytemplate.jsp @@ -0,0 +1,23 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> + +<div> + <a class="btn btn-primary" id="newtab" style="cursor:pointer;" href="${it.location}" target="_blank" >Open Editor</a> + <a class="btn btn-info" href="topologytemplate/?view" target="_blank" >Open View</a> + <br> + <br> + <div id="loading" class="topologyTemplatePreviewSizing" style="position:absolute; background-color: white; z-index:5;">Loading preview...</div> + <iframe id="topologyTemplatePreview" class="topologyTemplatePreviewSizing" src="topologytemplate/?view=small" onload="$('#loading').hide(1000);"></iframe> +</div> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp new file mode 100644 index 0000000..789c174 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp @@ -0,0 +1,67 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@page buffer="none" %> + +<%@page import="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@page import="org.eclipse.winery.repository.Prefs" %> +<%@page import="org.eclipse.winery.repository.client.WineryRepositoryClientFactory"%> +<%@page import="org.eclipse.winery.repository.client.IWineryRepositoryClient"%> +<%@page import="org.eclipse.winery.repository.client.WineryRepositoryClient"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@taglib prefix="w" uri="http://www.eclipse.org/winery/repository/functions"%> + +<html> +<head> + <meta name="application-name" content="Winery" /> + <meta charset="UTF-8"> + <link rel="icon" href="${w:topologyModelerURI()}/favicon.png" type="image/png"> + + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/bootstrap/dist/css/bootstrap.css" /> + <link rel="stylesheet" href="${pageContext.request.contextPath}/components/bootstrap/dist/css/bootstrap-theme.css" /> + + <script type='text/javascript' src='${pageContext.request.contextPath}/components/requirejs/require.js'></script> + + <!-- jquery and jquery UI have to be loaded using the old fashioned way to avoid incompatibilities with bootstrap v3 --> + <script type='text/javascript' src='${pageContext.request.contextPath}/components/jquery/jquery.js'></script> + <script type='text/javascript' src='${pageContext.request.contextPath}/3rdparty/jquery-ui/js/jquery-ui.js'></script> + <script type='text/javascript' src='${pageContext.request.contextPath}/components/bootstrap/dist/js/bootstrap.js'></script> + <script> + require.config({ + baseUrl: "${pageContext.request.contextPath}/js", + paths: { + "datatables": "../components/datatables/media/js/jquery.dataTables", + "jquery": "../components/jquery/jquery", + + // required for jsplumb + "jquery.ui": "../3rdparty/jquery-ui/js/jquery-ui", + + "jsplumb": "../components/jsPlumb/dist/js/jquery.jsPlumb-1.5.4", + + "winery-sugiyamaLayouter": "${w:topologyModelerURI()}/js/winery-sugiyamaLayouter" + } + }); + </script> + <c:if test="${not empty it.additionalScript}"> + <script type='text/javascript' src='${it.additionalScript}'></script> + </c:if> +</head> +<body> + +<t:topologyTemplateRenderer topology="${it.topologyTemplate}" repositoryURL="<%=Prefs.INSTANCE.getResourcePath()%>" client="${it.client}" fullscreen="true" additonalCSS="${it.additonalCSS}" autoLayoutOnLoad="${it.autoLayoutOnLoad}"/> + +</body> +</html> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/setupTriggerRemoveByDELKey.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/setupTriggerRemoveByDELKey.jsp new file mode 100644 index 0000000..ea47832 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/setupTriggerRemoveByDELKey.jsp @@ -0,0 +1,28 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%-- +JavaScript snippet binding the delete button to a trigger of the "Remove" button in case there is only one such button and that no input field is selected +--%> + + var removeButtons = $("button:contains('Remove')"); + if (removeButtons.length == 1) { + requirejs(["keyboardjs"], function(KeyboardJS) { + KeyboardJS.on("del", function() { + if ($(document.activeElement).is("body")) { + // we are not in an input field etc. + removeButtons.trigger("click"); + } + }); + }); + } diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/tags/tags.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/tags/tags.jsp new file mode 100644 index 0000000..c47271d --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/tags/tags.jsp @@ -0,0 +1,14 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +Not yet implemented diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/test.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/test.jsp new file mode 100644 index 0000000..2fbfb99 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/test.jsp @@ -0,0 +1,33 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<t:genericpage windowtitle="Test" selected="Admin" cssClass="admin"> + +<input id="fileupload" type="file" name="files[]" multiple + data-url="/path/to/upload/handler.json" + data-sequential-uploads="true" + data-form-data='{"script": "true"}'> + +<script> +var fu = $("#fileupload"); +requirejs(["jquery.fileupload"], function() { + fu.fileupload({autoUpload:true}); +}); +</script> + + +</t:genericpage> diff --git a/winery/org.eclipse.winery.repository/src/main/webapp/jsp/xmlSource.jsp b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/xmlSource.jsp new file mode 100644 index 0000000..bec5e11 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/main/webapp/jsp/xmlSource.jsp @@ -0,0 +1,20 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> + +<o:orioneditorarea areaid="XML">${wc:escapeHtml4(it.definitionsAsXMLString)}</o:orioneditorarea> + +<p class="text-muted">Save leads to a synchronization with the other tabs</p>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/psd/Sorting icons.psd b/winery/org.eclipse.winery.repository/src/psd/Sorting icons.psd Binary files differnew file mode 100644 index 0000000..53b2e06 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/psd/Sorting icons.psd diff --git a/winery/org.eclipse.winery.repository/src/psd/header_background_plain.png b/winery/org.eclipse.winery.repository/src/psd/header_background_plain.png Binary files differnew file mode 100644 index 0000000..41015fe --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/psd/header_background_plain.png diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/librarytests/DateTest.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/librarytests/DateTest.java new file mode 100644 index 0000000..db4aea4 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/librarytests/DateTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.librarytests; + +import java.text.ParseException; +import java.util.Date; +import java.util.Locale; + +import org.apache.commons.lang3.time.DateUtils; + +/** + * Date parsing test, when the system locale is not ENGLISH + */ +public class DateTest { + + public static void main(String[] args) throws ParseException { + // In case the following line is commented, this method throws a ParseException + Locale.setDefault(Locale.ENGLISH); + String modified = "Fri, 23 Mar 2012 11:04:56 GMT"; + Date modifiedDate = DateUtils.parseDate(modified, org.apache.http.impl.cookie.DateUtils.DEFAULT_PATTERNS); + System.out.println(modifiedDate); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/librarytests/InheritanceIllustration.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/librarytests/InheritanceIllustration.java new file mode 100644 index 0000000..95601d7 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/librarytests/InheritanceIllustration.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.librarytests; +/** + * This class is intended to demonstrate static resolution of overloaded methods + * + * The output of this class is "Doing sth. with a followed by "Doing sth. with + * b" even if the passed "theObject" is of type B + */ +public class InheritanceIllustration { + + private static class A { + }; + + private static class B extends A { + }; + + private static class X { + + public static void doSomething(A a) { + System.out.println("Doing sth. with a"); + } + + public static void doSomething(B b) { + System.out.println("Doing sth. with b"); + } + } + + + /** + * @param args + */ + public static void main(String[] args) { + A theObject = new B(); + X.doSomething(theObject); + X.doSomething((B) theObject); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabled.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabled.java new file mode 100644 index 0000000..3e48592 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabled.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.io.IOException; + +public abstract class PrefsTestEnabled extends Prefs { + + /** + * @param initializeRepository true if the repository should be initialized + * as provided in winery.properties + * @throws IOException + */ + protected PrefsTestEnabled(boolean initializeRepository) throws IOException { + super(initializeRepository); + } + + @Override + public String getResourcePath() { + return "http://www.example.org/winery/test"; + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabledGitBackedRepository.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabledGitBackedRepository.java new file mode 100644 index 0000000..fc702d8 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabledGitBackedRepository.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.io.IOException; + +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; + +public class PrefsTestEnabledGitBackedRepository extends PrefsTestEnabled { + + public PrefsTestEnabledGitBackedRepository() throws IOException { + super(false); + // TODO: we should to a new clone of the repository + // currently, we rely on the right configuration of the preferences to use a file-based repository + + // code similar to org.eclipse.winery.repository.Prefs.doRepositoryInitialization() + String repositoryLocation = this.properties.getProperty("repositoryPath"); + this.repository = new GitBasedRepository(repositoryLocation); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabledUsingConfiguredRepository.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabledUsingConfiguredRepository.java new file mode 100644 index 0000000..0aea8ed --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/PrefsTestEnabledUsingConfiguredRepository.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.io.IOException; + +/** + * Initializes the preferences with the repository given in winery.preferences + * + * FIXME: no test should use this one. Each test should configure the repository + * by itself. + */ +public class PrefsTestEnabledUsingConfiguredRepository extends PrefsTestEnabled { + + public PrefsTestEnabledUsingConfiguredRepository() throws IOException { + super(true); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/TestWithRepositoryConnection.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/TestWithRepositoryConnection.java new file mode 100644 index 0000000..d2a2f88 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/TestWithRepositoryConnection.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import java.io.IOException; + +import org.junit.BeforeClass; + +public abstract class TestWithRepositoryConnection { + + @BeforeClass + public static void connectToProvider() throws IOException { + // Initialize preferences + // We do not need them, but constructing them has the side effect that Repository.INSTANCE is != null + new PrefsTestEnabledUsingConfiguredRepository(); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/UtilsTest.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/UtilsTest.java new file mode 100644 index 0000000..02f04f9 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/UtilsTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository; + +import org.junit.Assert; +import org.junit.Test; + +public class UtilsTest { + + @Test + public void testCreateID() { + Assert.assertEquals("Frank_s_test", Utils.createXMLid("Frank's test").getDecoded()); + Assert.assertEquals("MyNodeType", Utils.createXMLid("MyNodeType").getDecoded()); + Assert.assertEquals("A_Node_Type", Utils.createXMLid("A Node Type").getDecoded()); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/export/TestToscaExporter.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/export/TestToscaExporter.java new file mode 100644 index 0000000..5411cec --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/export/TestToscaExporter.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.StreamingOutput; +import javax.xml.bind.JAXBException; + +import org.apache.commons.io.output.NullOutputStream; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.eclipse.winery.common.ids.definitions.ServiceTemplateId; +import org.eclipse.winery.repository.PrefsTestEnabledGitBackedRepository; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; + +public class TestToscaExporter { + + //private static final TOSCAExportUtil toscaExporter = new TOSCAExportUtil(); + private static final CSARExporter csarExporter = new CSARExporter(); + + private static final ServiceTemplateId serviceTemplateId = new ServiceTemplateId("http://www.example.com/tosca/ServiceTemplates/Moodle", "Moodle", false); + + + /** + * Quick hack as we currently don't have a dedicated test service template + */ + @BeforeClass + public static void setServiceTemplateId() throws Exception { + // Initialize preferences + // We do not need them, but constructing them has the side effect that Repository.INSTANCE is != null + new PrefsTestEnabledGitBackedRepository(); + } + + @Before + public void setRevision() throws Exception { + ((GitBasedRepository) Repository.INSTANCE).setRevisionTo("97fa997b92965d8bc84e86274b0203f1db7495c5"); + } + + @Test + public void checkTOSCAExport() throws Exception { + @SuppressWarnings("unused") + StreamingOutput so = new StreamingOutput() { + + @Override + public void write(OutputStream output) throws IOException, WebApplicationException { + TOSCAExportUtil exporter = new TOSCAExportUtil(); + // we include everything related + Map<String, Object> conf = new HashMap<>(); + try { + exporter.exportTOSCA(TestToscaExporter.serviceTemplateId, output, conf); + } catch (JAXBException e) { + throw new WebApplicationException(e); + } + } + }; + + // TODO: check output contained in SO + } + + @Test + public void checkCSARExport() throws Exception { + NullOutputStream out = new NullOutputStream(); + TestToscaExporter.csarExporter.writeCSAR(TestToscaExporter.serviceTemplateId, out); + } +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/importing/TestCSARImporter.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/importing/TestCSARImporter.java new file mode 100644 index 0000000..f2778df --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/importing/TestCSARImporter.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.importing; + +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.repository.PrefsTestEnabledUsingConfiguredRepository; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestCSARImporter { + + /** + * Ensure that Repository.INSTANCE exists + */ + @BeforeClass + public static void setupPrefs() throws Exception { + // Initialize preferences + // We do not need them directly, but constructing them has the side effect that Repository.INSTANCE is != null + new PrefsTestEnabledUsingConfiguredRepository(); + } + + /** + * Quick hack to test Moodle Import + * + * Currently, no CSARs are put into the test resources, we rely on local + * CSARs + */ + @Test + public void testMoodleImport() throws Exception { + CSARImporter i = new CSARImporter(); + Path p = FileSystems.getDefault().getPath("C:\\Users\\Oliver\\BTSync\\Projects\\OpenTOSCA\\MoodleInteropCSAR\\trunk"); + List<String> errors = new ArrayList<String>(); + i.importFromDir(p, errors, true, false); + } +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/TestAbstractComponentInstanceResourceDefinitionsBacked.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/TestAbstractComponentInstanceResourceDefinitionsBacked.java new file mode 100644 index 0000000..1e65954 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/TestAbstractComponentInstanceResourceDefinitionsBacked.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import java.io.IOException; + +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.repository.backend.MockXMLElement; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.resources.entitytypes.capabilitytypes.CapabilityTypeResource; +import org.junit.Assert; +import org.junit.Test; + +public class TestAbstractComponentInstanceResourceDefinitionsBacked extends TestResource { + + private static final CapabilityTypeId id = new CapabilityTypeId(TestResource.NS, new XMLId("testCapabilityType", false)); + + + @Test + public void testPlainPersist() throws IOException { + // ensure that no test object exists + Repository.INSTANCE.forceDelete(TestAbstractComponentInstanceResourceDefinitionsBacked.id); + + CapabilityTypeResource res = new CapabilityTypeResource(TestAbstractComponentInstanceResourceDefinitionsBacked.id); + res.persist(); + Assert.assertTrue("Element has to exist", Repository.INSTANCE.exists(TestAbstractComponentInstanceResourceDefinitionsBacked.id)); + } + + @Test + public void testPersistWithData() throws IOException { + // ensure that no test object exists + Repository.INSTANCE.forceDelete(TestAbstractComponentInstanceResourceDefinitionsBacked.id); + + CapabilityTypeResource res = new CapabilityTypeResource(TestAbstractComponentInstanceResourceDefinitionsBacked.id); + res.getElement().getAny().add(new MockXMLElement()); + res.persist(); + Assert.assertTrue("Element has to exist", Repository.INSTANCE.exists(TestAbstractComponentInstanceResourceDefinitionsBacked.id)); + + // reload data + res = new CapabilityTypeResource(TestAbstractComponentInstanceResourceDefinitionsBacked.id); + + Assert.assertEquals(1, res.getElement().getAny().size()); + } +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/TestResource.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/TestResource.java new file mode 100644 index 0000000..2841942 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/TestResource.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources; + +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.repository.TestWithRepositoryConnection; + +public abstract class TestResource extends TestWithRepositoryConnection { + + protected static final String TESTNS = "http://www.example.org/winery/test/resources"; + protected static final Namespace NS = new Namespace(TestResource.TESTNS, false); + +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/TestArtifactTemplateResource.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/TestArtifactTemplateResource.java new file mode 100644 index 0000000..e7e3e5a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/TestArtifactTemplateResource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId; +import org.eclipse.winery.repository.PrefsTestEnabledGitBackedRepository; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; +import org.eclipse.winery.repository.resources.AbstractComponentsResource; + +public class TestArtifactTemplateResource { + + @BeforeClass + public static void init() throws Exception { + // enable git-backed repository + new PrefsTestEnabledGitBackedRepository(); + } + + @Before + public void setRevision() throws Exception { + ((GitBasedRepository) Repository.INSTANCE).setRevisionTo("97fa997b92965d8bc84e86274b0203f1db7495c5"); + } + + @Test + public void countMatches() { + ArtifactTemplateId id = new ArtifactTemplateId("http%3A%2F%2Fdocs.oasis-open.org%2Ftosca%2Fns%2F2011%2F12%2FToscaSpecificTypes", "at-0cd9ab5d-6c2e-4fc2-9cb0-3fee1e431f9f", true); + ArtifactTemplateResource res = (ArtifactTemplateResource) AbstractComponentsResource.getComponentInstaceResource(id); + Assert.assertEquals(1, res.getReferenceCount()); + } +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/TestCapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/TestCapabilityTypeResource.java new file mode 100644 index 0000000..098d59a --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/TestCapabilityTypeResource.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.capabilitytypes; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.eclipse.winery.common.ids.Namespace; +import org.eclipse.winery.common.ids.XMLId; +import org.eclipse.winery.common.ids.definitions.CapabilityTypeId; +import org.eclipse.winery.repository.PrefsTestEnabledGitBackedRepository; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; +import org.eclipse.winery.repository.resources.TestResource; + +public class TestCapabilityTypeResource extends TestResource { + + private static final CapabilityTypeId id = new CapabilityTypeId(new Namespace("http://docs.oasis-open.org/tosca/ns/2011/12/ToscaBaseTypes", false), new XMLId("ContainerCapability", false)); + + + @BeforeClass + public static void init() throws Exception { + // enable git-backed repository + new PrefsTestEnabledGitBackedRepository(); + } + + @Before + public void setRevision() throws Exception { + ((GitBasedRepository) Repository.INSTANCE).setRevisionTo("97fa997b92965d8bc84e86274b0203f1db7495c5"); + } + + @Test + public void getElementAsXMLString() throws IOException { + // ensure that no test object exists + Repository.INSTANCE.forceDelete(TestCapabilityTypeResource.id); + + CapabilityTypeResource res = new CapabilityTypeResource(TestCapabilityTypeResource.id); + String s = res.getDefinitionsAsXMLString(); + Assert.assertNotNull(s); + } +} diff --git a/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/TestRequirementDefinitions.java b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/TestRequirementDefinitions.java new file mode 100644 index 0000000..47ee3d0 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/TestRequirementDefinitions.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs; + +import javax.ws.rs.core.MediaType; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.eclipse.winery.repository.PrefsTestEnabledGitBackedRepository; +import org.eclipse.winery.repository.backend.Repository; +import org.eclipse.winery.repository.backend.filebased.GitBasedRepository; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.path.json.JsonPath; +import com.jayway.restassured.response.Response; + +//@formatter:off + +/* + * import static com.jayway.restassured.RestAssured.*; import static + * com.jayway.restassured.matcher.RestAssuredMatchers.*; import static + * org.hamcrest.Matchers.*; import static + * com.jayway.restassured.path.json.JsonPath.*; + */ + + +/** + * REST-based testing of requirement definitions + * + * We use a fixed method sort order as we create resources in one test and work + * with them in the next step + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestRequirementDefinitions { + + @BeforeClass + public static void init() throws Exception { + // enable git-backed repository + new PrefsTestEnabledGitBackedRepository(); + + // we use a half-filled repository + ((GitBasedRepository) Repository.INSTANCE).setRevisionTo("97fa997b92965d8bc84e86274b0203f1db7495c5"); + + // we test on the Amazon EC2 node type + // could be any other node type without requirement definitions + // + // the following URI is already encoded (copied from the browser URL field) + RestAssured.urlEncodingEnabled = false; + RestAssured.basePath = "/org.eclipse.winery.repository/nodetypes/http%253A%252F%252Fwww.example.org%252Ftosca%252Fnodetypes/Amazon_EC2/requirementdefinitions"; + } + + @Test + public void test01_NoRequirementDefinitions() throws Exception { + RestAssured.given() + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + .body(Matchers.equalTo("[]")) + .when() + .get(""); + } + + @Test + public void test02_CreateRequirementDefinition() throws Exception { + RestAssured.given() + .parameter("name", "test") + .expect() + .statusCode(204) + .when() + .post("/"); + } + + @Test + public void test03_NoConstraints() throws Exception { + RestAssured.given() + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + .body(Matchers.equalTo("[]")) + .when() + .get("test/constraints/"); + } + + @Test + public void test04_CreateConstraint() throws Exception { + RestAssured.given() + .body("<tosca:Constraint xmlns:tosca=\"http://docs.oasis-open.org/tosca/ns/2011/12\" xmlns:winery=\"http://www.opentosca.org/winery/extensions/tosca/2013/02/12\" constraintType=\"http://www.example.org/constrainttype\"/>") + .contentType(ContentType.XML) + .expect() + .statusCode(200) + .body(Matchers.notNullValue()) + .when() + .post("test/constraints/"); + } + + @Test + public void test05_GetConstraint() throws Exception { + Response response = RestAssured + .given() + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + .statusCode(200) + .when() + .get("test/constraints/"); + + // extract answer + JsonPath jsonPath = JsonPath.from(response.asString()); + + Assert.assertEquals("One id", jsonPath.getList("").size(), 1); + + String id = jsonPath.getString("[0]"); + + // TODO: check content + RestAssured + .given() + .header("Accept", MediaType.TEXT_XML) + .expect() + .statusCode(200) + .when() + .get("test/constraints/{id}/", id); + + // we also test the sub resource here + // otherwise we had to transport the id throught the code via a global variable + RestAssured + .expect() + .statusCode(200) + .body(Matchers.is("http://www.example.org/constrainttype")) + .when() + .get("test/constraints/{id}/type", id); + } + +} diff --git a/winery/org.eclipse.winery.repository/src/test/resources/.gitignore b/winery/org.eclipse.winery.repository/src/test/resources/.gitignore new file mode 100644 index 0000000..1249577 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/resources/.gitignore @@ -0,0 +1 @@ +/winery.properties diff --git a/winery/org.eclipse.winery.repository/src/test/resources/logback-test.xml b/winery/org.eclipse.winery.repository/src/test/resources/logback-test.xml new file mode 100644 index 0000000..8633194 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line %method - %msg%n</pattern> + </encoder> + </appender> + + <logger name="org.eclipse.winery" level="TRACE"/> + + <root level="DEBUG"> + <appender-ref ref="STDOUT" /> + </root> +</configuration>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.repository/src/test/resources/servicetemplate.tosca b/winery/org.eclipse.winery.repository/src/test/resources/servicetemplate.tosca new file mode 100644 index 0000000..5fd2a72 --- /dev/null +++ b/winery/org.eclipse.winery.repository/src/test/resources/servicetemplate.tosca @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<tosca:Definitions xmlns:tosca="http://docs.oasis-open.org/tosca/ns/2011/12" xmlns:winery="http://www.opentosca.org/winery/extensions/tosca/2013/02/12" xmlns:ns2="http://www.eclipse.org/winery/model/selfservice" id="winery-defs-for_ns26-TrustedCloudPresentation" targetNamespace="http://www.opentosca.org"> + <tosca:NodeType name="ApacheWebserver" targetNamespace="http://www.opentosca.org/types/nodetypes" winery:bordercolor="#3625c9"> + <tosca:Interfaces> + <tosca:Interface name="ApplicationManagement"> + <tosca:Operation name="DeployApplication"> + <tosca:InputParameters> + <tosca:InputParameter name="DeploymentArtifactRef" type="string" required="no"/> + </tosca:InputParameters> + <tosca:OutputParameters> + <tosca:OutputParameter name="ApplicationURL" type="string" required="no"/> + <tosca:OutputParameter name="ApplicationID" type="string" required="no"/> + </tosca:OutputParameters> + </tosca:Operation> + <tosca:Operation name="UndeployApplication"> + <tosca:InputParameters> + <tosca:InputParameter name="ApplicationID" type="string" required="no"/> + </tosca:InputParameters> + </tosca:Operation> + </tosca:Interface> + </tosca:Interfaces> + </tosca:NodeType> + <tosca:ServiceTemplate id="TrustedCloudPresentation" name="TrustedCloudPresentation" targetNamespace="http://www.opentosca.org"> + <tosca:TopologyTemplate> + <tosca:NodeTemplate xmlns:ns16="http://www.opentosca.org/types/nodetypes" name="ApacheWebserver" id="ApacheWebserver" type="ns16:ApacheWebserver" winery:x="296" winery:y="391"> + </tosca:NodeTemplate> + </tosca:TopologyTemplate> + </tosca:ServiceTemplate> + <!-- The artifact type is NOT imported in the Service Template. Some parsers might reject this TOSCA file --> + <tosca:ArtifactTemplate targetNamespace="http://www.example.com/ArtifactTemplates" xmlns:ns8="http://example.com/ArtifactTypes" name="ArtifactTemplate" id="ArtifactTemplate" type="ns8:AT1"> + <tosca:ArtifactReferences> + <tosca:ArtifactReference reference="http://www.example.com/artifacttemplates/http%253A%252F%252Fwww.example.com%252FArtifactTemplates/ArtifactTemplate/files/test.pdf"/> + </tosca:ArtifactReferences> + </tosca:ArtifactTemplate> +</tosca:Definitions> diff --git a/winery/org.eclipse.winery.topologymodeler/.bowerrc b/winery/org.eclipse.winery.topologymodeler/.bowerrc new file mode 100644 index 0000000..eb92b22 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory" : "src/main/webapp/components" +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/.gitattributes b/winery/org.eclipse.winery.topologymodeler/.gitattributes new file mode 100644 index 0000000..03b2494 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/.gitattributes @@ -0,0 +1 @@ +bower.json eol=lf diff --git a/winery/org.eclipse.winery.topologymodeler/.gitignore b/winery/org.eclipse.winery.topologymodeler/.gitignore new file mode 100644 index 0000000..166eaf4 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/.gitignore @@ -0,0 +1,23 @@ +.classpath +/.gradle +.project +.settings/.jsdtscope +.settings/org.eclipse.core.resources.prefs +.settings/org.eclipse.jdt.core.prefs +.settings/org.eclipse.m2e.core.prefs +.settings/org.eclipse.wst.common.component +.settings/org.eclipse.wst.common.project.facet.core.xml +.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +.settings/org.eclipse.wst.jsdt.ui.superType.container +.settings/org.eclipse.wst.jsdt.ui.superType.name +.settings/org.eclipse.wst.validation.prefs +/.sonar +/bin +/build +sonar-project.properties +/src/main/java/rebel.xml +/src/main/resources/rebel.xml +/target + +#Generated by "bower install" +src/main/webapp/components/ diff --git a/winery/org.eclipse.winery.topologymodeler/README.md b/winery/org.eclipse.winery.topologymodeler/README.md new file mode 100644 index 0000000..f455e42 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/README.md @@ -0,0 +1,44 @@ +# Winery Topoloy Modeler + +This is the topology modeler component of Winery. + +## Installation + +See [README.md of Winery](../README.md). + +## Implementation hints + +* use `div.NodeTemplateShape` as selector for node templates + +## About the Code + +This code is in a prototypcial status. These are the main issues: +* Instead of using EL, it directly uses Java code in the JSPs. +* Instead of including the libraries using AMD, they are directly included via `script` tags. +* Instead of using [AngularJS] (or a similar framework), we manually do the life update from the properties section to the node +* Saving generates the XML manually (in index.jsp:save()). Therefore the extensibility of TOSCA is not supported here. +* We depend on both bootstrap and jquery UI as jsPlumb does not support a bootstrap binding. + +### Trouble shooting +When the topology modeler does not fully load (i.e., a white background is still there), look at the TOMCAT log file (of the repository). +You'll see something like `TOSCA component id class org.eclipse.winery.common.ids.definitions.NodeTypeId / {http://www.example.org/tosca/nodetypes}VirtualMachine not found`. +This is in indicator that you manually edited a `.definitions` file and did not change the location in the repository. +The directory structure and the namespace and id/name settings in the `.definitions` file have to be in sync. +As quick solution, you can open the type, switch to the XML tab and press "Save". +Then, the namespace and id/name setting in the `.definitions` is changed according to the storage. + +## License +Copyright (c) 2012-2014 University of Stuttgart. + +All rights reserved. This program and the accompanying materials +are made available under the terms of the [Eclipse Public License v1.0] +and the [Apache License v2.0] which both accompany this distribution, +and are available at http://www.eclipse.org/legal/epl-v10.html +and http://www.apache.org/licenses/LICENSE-2.0 + +Contributors: +* Oliver Kopp - initial API and implementation + + [AngularJS]: http://angularjs.org/ + [Apache License v2.0]: http://www.apache.org/licenses/LICENSE-2.0.html + [Eclipse Public License v1.0]: http://www.eclipse.org/legal/epl-v10.html diff --git a/winery/org.eclipse.winery.topologymodeler/about.html b/winery/org.eclipse.winery.topologymodeler/about.html new file mode 100644 index 0000000..2badd94 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about.html @@ -0,0 +1,604 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>January 24, 2014</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in (“Content”). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License Version 1.0 (“EPL”)</a> +and <a href="http://www.opensource.org/licenses/apache2.0.php">Apache License Version 2.0</a>. +A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> +and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>. +You may elect to redistribute this code under either of these licenses. +For purposes of the EPL, “Program” will mean the Content. +</p> + +<p> +If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party (“Redistributor”) and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor’s license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL and Apache License 2.0 still apply to any source code +in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>. +</p> + +<h3>Third Party Content</h3> + +<h4>JavaScript libraries</h4> + +<h5>biltong – Version 0.1</h5> +<table> + <tr> + <td>Files</td> + <td>The library is completely included in jsPlumb as “jsPlumbGeom v0.1”</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/jsplumb/biltong">https://github.com/jsplumb/biltong</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-biltong.txt" target="_blank">LICENSE-biltong.txt</a> and is also available at <a href="https://github.com/sporritt/biltong/blob/master/src/biltong-0.1.js" target="_blank">github</a></td> + </tr> +</table> + +<h5>Bootstrap – Version 3.1.1</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/bootstrap</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://getbootstrap.com/">http://getbootstrap.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-bootstrap.txt" target="_blank">LICENSE-bootstrap.txt</a> and is also available at <a href="https://github.com/twbs/bootstrap/blob/v3.1.0/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h5>bootstrap-spinedit – Version 1.0.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/bootstrap-spinedit</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/scyv/bootstrap-spinedit">https://github.com/scyv/bootstrap-spinedit</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="https://github.com/scyv/bootstrap-spinedit/blob/v1.0.0/LICENSE.txt" target="_blank">github</a></td> + </tr> +</table> + +<h5>JavaScript Canvas to Blob – Version 2.1.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-canvas-to-blob</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/JavaScript-Canvas-to-Blob">https://github.com/blueimp/JavaScript-Canvas-to-Blob</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>JavaScript Load Image – Version 1.11.0</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-load-image</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/JavaScript-Load-Image">https://github.com/blueimp/JavaScript-Load-Image</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>JavaScript Templates – Version 2.5.3</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-tmpl</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/JavaScript-Templates">https://github.com/blueimp/JavaScript-Templates</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>jQuery – Version 2.0.3</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jquery</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jquery.com/">http://jquery.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-jQuery.txt" target="_blank">LICENSE-jQuery.txt</a> and is also available at <a href="https://jquery.org/license/" target="_blank">https://jquery.org/license/</a></td> + </tr> +</table> + +<h5>jQuery Typing – v0.3.2-2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jquery-typing</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/tnajdek/jquery-typing">https://github.com/tnajdek/jquery-typing</a></td> + </tr> + <tr> + <td>License</td> + <td>Public domain. An explicit license is not provided, only a link to <a href="http://unlicense.org/" target="_blank">unlicense.org</a> is provided.</td> + </tr> +</table> + +<h5>jQuery File Upload Plugin – Version 9.5.3</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/blueimp-file-upload</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/blueimp/jQuery-File-Upload">https://github.com/blueimp/jQuery-File-Upload</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. The authors did not provide a separate variant of the MIT license. The generic MIT license is available at <a href="http://opensource.org/licenses/MIT" target="_blank">http://opensource.org/licenses/MIT</a></td> + </tr> +</table> + +<h5>jQuery UI – Version 1.10.3</h5> +This library is required by jsPlumb only +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jquery-ui</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jqueryui.com/">http://jqueryui.com/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-jQuery-UI.txt" target="_blank">LICENSE-jQuery-UI.txt</a> and is also available at <a href="https://github.com/jquery/jquery-ui/blob/master/MIT-LICENSE.txt" target="_blank">https://github.com/jquery/jquery-ui/blob/master/MIT-LICENSE.txt</a></td> + </tr> +</table> + +<h5>jsBezier – Version 0.6</h5> +<table> + <tr> + <td>Files</td> + <td>The library is completly included in jsPlumb</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/jsplumb/jsBezier">https://github.com/jsplumb/jsBezier</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. An explicit license is not provided, only an entry in the header of <a href="https://github.com/jsplumb/jsBezier/blob/master/js/0.6/jsBezier-0.6.js">jsBezier-0.6.js</a>.</td> + </tr> +</table> + + +<h5>jsPlumb – Version 1.5.4</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/jsPlumb</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://jsplumb.org/">http://jsplumb.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>All 1.x.x versions of jsPlumb are dual-licensed under both MIT and GPLv2 (<a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0">http://www.gnu.org/licenses/old-licenses/gpl-2.0</a>). + The Eclipse Foundation elects to include this software in this distribution under the MIT license. + A copy of the license is contained in the file <a href="about_files/LICENSE-jsPlumb-MIT" target="_blank">LICENSE-jsPlumb-MIT</a> and is also available at <a href="https://github.com/sporritt/jsPlumb/blob/1.5.4/jsPlumb-MIT-LICENSE.txt" target="_blank">github</a></td> + </tr> +</table> + +<h5>KeyboardJS – Version 0.4.2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/KeyboardJS</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/RobertWHurst/KeyboardJS/tree/v0.4.2">https://github.com/RobertWHurst/KeyboardJS/tree/v0.4.2</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD (2 clauses). A copy of the license is contained in the file <a href="about_files/LICENSE-KeyboardJS.txt" target="_blank">LICENSE-KeyboardJS.txt</a> and is also available at <a href="https://github.com/RobertWHurst/KeyboardJS/blob/v0.4.2/license.txt" target="_blank">https://github.com/RobertWHurst/KeyboardJS/blob/v0.4.2/license.txt</a></td> + </tr> +</table> + +<h5>Orion – Version 5.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/orion/editor/releases/5.0/built-editor.js">http://eclipse.org/orion/editor/releases/5.0/built-editor.js</a></td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://www.eclipse.org/orion/">http://www.eclipse.org/orion/</a></td> + </tr> + <tr> + <td>License</td> + <td>Eclipse Public License v1.0 and Eclipse Distribution License v1.0. + A copy of the licenses is contained in the files <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a> and <a href="about_files/EDL.txt" target="_blank">EDL.txt</a>. + A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the EDL is available at <a href="http://www.eclipse.org/org/documents/edl-v10.html">http://www.eclipse.org/org/documents/edl-v10.html</a>.</td> + </tr> +</table> + +<h5>PNotify – Version 1.3.1</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/pnotify</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://sciactive.com/pnotify/">http://sciactive.com/pnotify/</a></td> + </tr> + <tr> + <td>License</td> + <td>PNotify is distributed under the GPL (<a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>), + LGPL (<a href="http://www.gnu.org/licenses/lgpl.html">http://www.gnu.org/licenses/lgpl.html</a>), and + MPL (<a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the MPL license. + A copy of the license is contained in the file <a href="about_files/MPL-v1.1.txt" target="_blank">MPL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>RequireJS – Version 2.1.5</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/requirejs</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://requirejs.org/">http://requirejs.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD and MIT (see <a href="https://github.com/jrburke/requirejs/blob/master/LICENSE">https://github.com/jrburke/requirejs/blob/master/LICENSE</a>). + The Eclipse Foundation elects to include this software in this distribution under the MIT license. + A copy of the license is contained in the file <a href="about_files/LICENSE-requirejs.txt" target="_blank">LICENSE-requirejs.txt</a>.</td> + </tr> +</table> + +<h5>Select2 – Version 3.4.5</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/select2</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://ivaynberg.github.io/select2/">http://ivaynberg.github.io/select2/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0 (<a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>) and GPL2 (<a href="http://www.gnu.org/licenses/gpl-2.0.html">http://www.gnu.org/licenses/gpl-2.0.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the Apache 2.0 license. + A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a>.</td> + </tr> +</table> + +<h5>X-editable – Version 1.5.1</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/x-editable</td> + </tr> + <tr> + <td>URL</td> + <td><a href="http://vitalets.github.io/x-editable/">http://vitalets.github.io/x-editable/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-x-editable.txt" target="_blank">LICENSE-x-editable.txt</a> and is also available at <a href="https://github.com/vitalets/x-editable/blob/master/LICENSE-MIT" target="_blank">github</a></td> + </tr> +</table> + +<h5>XMLWriter – Version v1.0.2</h5> +<table> + <tr> + <td>Files</td> + <td>src/main/webapp/components/XMLWriter</td> + </tr> + <tr> + <td>URL</td> + <td><a href="https://github.com/flesler/XMLWriter">https://github.com/flesler/XMLWriter</a></td> + </tr> + <tr> + <td>License</td> + <td>BSD. A copy of the license is contained in the file <a href="about_files/LICENSE-XMLWriter.txt" target="_blank">LICENSE-XMLWriter.txt</a> and is also available at <a href="https://github.com/flesler/XMLWriter/blob/master/LICENSE" target="_blank">github</a></td> + </tr> +</table> + +<h4>Java Libraries</h4> + +<h5>Apache Commons Configuration – Version 1.9</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-configuration/">http://commons.apache.org/proper/commons-configuration/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons IO – Version 2.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-io/">http://commons.apache.org/proper/commons-io/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang – Version 2.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Apache Commons Lang3 – Version 3.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://commons.apache.org/proper/commons-lang/">http://commons.apache.org/proper/commons-lang/</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-annotations – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-annotations">https://github.com/FasterXML/jackson-annotations</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> + <tr> + <td>Note</td> + <td>The license was explictily added in version 2.2.3 and 2.3.0. See <a href="https://github.com/FasterXML/jackson-annotations/issues/14">Issue #14</a> and <a href="https://github.com/FasterXML/jackson-annotations/blob/master/src/main/resources/META-INF/LICENSE">LICENSE in the source repository</a>.</td> + </tr> +</table> + +<h5>jackson-core – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-core">https://github.com/FasterXML/jackson-core</a> and <a href="http://wiki.fasterxml.com/JacksonHome">http://wiki.fasterxml.com/JacksonHome</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-databind – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-databind">https://github.com/FasterXML/jackson-databind</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-jaxrs-base – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base">https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-jaxrs-json-provider – Version 2.2.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/json">https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/json</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>jackson-module-jaxb-annotations – Version 2.3.0</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://github.com/FasterXML/jackson-module-jaxb-annotations">https://github.com/FasterXML/jackson-module-jaxb-annotations</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a>. + The license is added via the <a href="https://github.com/FasterXML/oss-parent">oss-parent</a> project.</td> + </tr> +</table> + +<h5>Jersey Client – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Jersey Core – Version 1.17</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://jersey.java.net/">jersey.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>JSP Standard Tag Library – Version 1.2</h5> +<table> + <tr> + <td>URL</td> + <td><a href="https://jstl.java.net/">https://jstl.java.net/</a></td> + </tr> + <tr> + <td>License</td> + <td>CDDL and GPL with classpath exception (<a href="https://jersey.java.net/license.html" target="_blank">https://jersey.java.net/license.html</a>). + The Eclipse Foundation elects to include this software in this distribution under the CDDL license. + A copy of the license is available at <a href="about_files/CDDL-v1.1.txt" target="_blank">CDDL-v1.1.txt</a>.</td> + </tr> +</table> + +<h5>Logback Classic – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>Logback Core – Version 1.1.1</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://logback.qos.ch/">http://logback.qos.ch/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/LGPL dual license. + EPL: <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + LGPL v2.1: <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1">http://www.gnu.org/licenses/old-licenses/lgpl-2.1</a>. + A copy of the license is contained in the file <a href="about_files/LICENSE-logback.txt" target="_blank">LICENSE-logback.txt</a> and is also available at <a href="http://logback.qos.ch/license.html" target="_blank">http://logback.qos.ch/license.html</a>. + The Eclipse Foundation elects to include this software in this distribution under the EPL license.</td> + </tr> +</table> + +<h5>SLF4J: slf4j-api – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/">http://www.slf4j.org/</a></td> + </tr> + <tr> + <td>License</td> + <td>MIT. A copy of the license is contained in the file <a href="about_files/LICENSE-slf4j-api.txt" target="_blank">LICENSE-slf4j-api.txt</a> and is also available at <a href="http://www.slf4j.org/license.html" target="_blank">http://www.slf4j.org/license.html</a></td> + </tr> +</table> + +<h5>SLF4J: jcl-over-slf4j – Version 1.7.6</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></td> + </tr> + <tr> + <td>License</td> + <td>Apache 2.0. A copy of the license is contained in the file <a href="about_files/Apache-LICENSE-2.0.txt" target="_blank">Apache-LICENSE-2.0.txt</a> and is also available at <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a></td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.common – ${project.version}</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +<h5>Winery: org.eclipse.winery.model.tosca – Version 0.1.20</h5> +<table> + <tr> + <td>URL</td> + <td><a href="http://eclipse.org/winery/">http://eclipse.org/winery/</a></td> + </tr> + <tr> + <td>License</td> + <td>EPL/Apache 2.0. A copy of the licenses is contained in the files <a href="../LICENSE-ASL.txt" target="_blank">LICENSE-ASL.txt</a> and <a href="../LICENSE-EPL.txt" target="_blank">LICENSE-EPL.txt</a>. A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> and a copy of the Apache License Version 2.0 is available at <a href="http://www.opensource.org/licenses/apache2.0.php">http://www.opensource.org/licenses/apache2.0.php</a>.</td> + </tr> +</table> + +</body> +</html>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/Apache-LICENSE-2.0.txt b/winery/org.eclipse.winery.topologymodeler/about_files/Apache-LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/Apache-LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/CDDL-v1.1.txt b/winery/org.eclipse.winery.topologymodeler/about_files/CDDL-v1.1.txt new file mode 100644 index 0000000..7cc8719 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/CDDL-v1.1.txt @@ -0,0 +1,129 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL - Version 1.1) +1. Definitions. + + 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + + 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. + + 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. + + 1.4. “Executable” means the Covered Software in any form other than Source Code. + + 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + + 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. + + 1.7. “License” means this document. + + 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. “Modifications” means the Source Code and Executable form of any of the following: + + A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; + + B. Any new file that contains any part of the Original Software or previous Modification; or + + C. Any new file that is contributed or otherwise made available under the terms of this License. + + 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally released under this License. + + 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. + + 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-KeyboardJS.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-KeyboardJS.txt new file mode 100644 index 0000000..e71620b --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-KeyboardJS.txt @@ -0,0 +1,25 @@ +Copyright 2011 Robert Hurst. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY ROBERT HURST ''AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ROBERT HURST OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the +authors and should not be interpreted as representing official policies, either expressed +or implied, of Robert Hurst.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-XMLWriter.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-XMLWriter.txt new file mode 100644 index 0000000..2676da3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-XMLWriter.txt @@ -0,0 +1,27 @@ +Copyright (c) 2014, Ariel Flesler +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-biltong.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-biltong.txt new file mode 100644 index 0000000..11cb215 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-biltong.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Simon Porritt + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-boostrap.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-boostrap.txt new file mode 100644 index 0000000..8d94aa9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-boostrap.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2011-2014 Twitter, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jQuery-UI.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jQuery-UI.txt new file mode 100644 index 0000000..1c693e3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jQuery-UI.txt @@ -0,0 +1,26 @@ +Copyright 2013 jQuery Foundation and other contributors, +http://jqueryui.com/ + +This software consists of voluntary contributions made by many +individuals (AUTHORS.txt, http://jqueryui.com/about) For exact +contribution history, see the revision history and logs, available +at http://jquery-ui.googlecode.com/svn/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jQuery.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jQuery.txt new file mode 100644 index 0000000..957f26d --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jQuery.txt @@ -0,0 +1,21 @@ +Copyright 2013 jQuery Foundation and other contributors +http://jquery.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jsPlumb-MIT.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jsPlumb-MIT.txt new file mode 100644 index 0000000..b5bc650 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-jsPlumb-MIT.txt @@ -0,0 +1,20 @@ +Copyright (c) 2013 Simon Porritt, http://jsplumb.org/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-logback.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-logback.txt new file mode 100644 index 0000000..b4fe24e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-logback.txt @@ -0,0 +1,15 @@ +Logback LICENSE +--------------- + +Logback: the reliable, generic, fast and flexible logging framework. +Copyright (C) 1999-2012, QOS.ch. All rights reserved. + +This program and the accompanying materials are dual-licensed under +either the terms of the Eclipse Public License v1.0 as published by +the Eclipse Foundation + + or (per the licensee's choosing) + +under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation. + diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-requirejs.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-requirejs.txt new file mode 100644 index 0000000..de4ee29 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-requirejs.txt @@ -0,0 +1,58 @@ +RequireJS is released under two licenses: new BSD, and MIT. You may pick the +license that best suits your development needs. The text of both licenses are +provided below. + + +The "New" BSD License: +---------------------- + +Copyright (c) 2010-2013, The Dojo Foundation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the Dojo Foundation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +MIT License +----------- + +Copyright (c) 2010-2013, The Dojo Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-slf4j-api.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-slf4j-api.txt new file mode 100644 index 0000000..37050c9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-slf4j-api.txt @@ -0,0 +1,21 @@ + Copyright (c) 2004-2013 QOS.ch + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-x-editable.txt b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-x-editable.txt new file mode 100644 index 0000000..eeb9357 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/LICENSE-x-editable.txt @@ -0,0 +1,22 @@ +Copyright (c) 2012 Vitaliy Potapov + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/winery/org.eclipse.winery.topologymodeler/about_files/MPL-v1.1.txt b/winery/org.eclipse.winery.topologymodeler/about_files/MPL-v1.1.txt new file mode 100644 index 0000000..a8cd934 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/about_files/MPL-v1.1.txt @@ -0,0 +1,470 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the MPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/winery/org.eclipse.winery.topologymodeler/bower.json b/winery/org.eclipse.winery.topologymodeler/bower.json new file mode 100644 index 0000000..a8204ce --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/bower.json @@ -0,0 +1,44 @@ +{ + "name": "Winery topology modeler", + "version": "0.1.37-SNAPSHOT", + "author": "Oliver Kopp <kopp.dev@gmail.com>", + "contributors": [ + { + "name": "Uwe Breitenbücher" + }, + { + "name": "Kálmán Képes" + }, + { + "name": "Yves Schubert" + } + ], + "licenses": [ + { + "type": "EPL", + "url": "http://www.eclipse.org/legal/epl-v10.html" + }, + { + "type": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + ], + "dependencies": { + "blueimp-file-upload": "9.5.3", + "blueimp-tmpl": "2.5.3", + "bootstrap": "3.1.1", + "bootstrap-spinedit": "https://github.com/scyv/bootstrap-spinedit.git#1.0.0", + "jquery": "2.0.3", + "jquery-typing": "https://github.com/tnajdek/jquery-typing.git#0.3.2-2", + "jsPlumb": "1.5.4", + "KeyboardJS": "https://github.com/RobertWHurst/KeyboardJS.git#v0.4.2", + "pnotify": "1.3.1", + "requirejs": "2.1.5", + "select2": "https://github.com/ivaynberg/select2/archive/3.4.5.zip", + "x-editable": "1.5.1", + "XMLWriter": "1.0.2" + }, + "keywords": [ + "TOSCA" + ] +} diff --git a/winery/org.eclipse.winery.topologymodeler/package.json b/winery/org.eclipse.winery.topologymodeler/package.json new file mode 100644 index 0000000..b59dbe9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/package.json @@ -0,0 +1,22 @@ +{ + "name": "openo-winery", + "version": "1.0.0", + "description": "openo winery", + "dependencies": { + }, + "devDependencies": { + "bower": "~1.7.9" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "http://oip.zte.com.cn/oipgit/git/Open-O-Community/common-services-common-utilities.git" + }, + "keywords": [ + "openo-winery" + ], + "author": "openo", + "license": "Apache-2.0" +} diff --git a/winery/org.eclipse.winery.topologymodeler/pom.xml b/winery/org.eclipse.winery.topologymodeler/pom.xml new file mode 100644 index 0000000..7d6c9f3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/pom.xml @@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Unger - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.winery</groupId> + <artifactId>winery</artifactId> + <version>0.1.37-SNAPSHOT</version> + </parent> + <artifactId>org.eclipse.winery.topologymodeler</artifactId> + <packaging>war</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-server</artifactId> + <version>1.17.1</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + <version>1.17.1</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-core</artifactId> + <version>1.17.1</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.eclipse.winery</groupId> + <artifactId>org.eclipse.winery.repository.client</artifactId> + <version>0.1.37-SNAPSHOT</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.1</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <artifactId>commons-logging</artifactId> + <groupId>commons-logging</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.7.6</version> + <scope>compile</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>2.4</version> + <configuration> + <webResources> + <resource> + <directory>${basedir}/src/main/webapp/WEB-INF</directory> + <filtering>true</filtering> + <targetPath>WEB-INF</targetPath> + <includes> + <include>tags/about.tag</include> + </includes> + </resource> + </webResources> + <attachClasses>true</attachClasses> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>com.github.eirslett</groupId> + <artifactId>frontend-maven-plugin</artifactId> + <version>1.0</version> + <!-- optional --> + <configuration> + <nodeVersion>v4.5.0</nodeVersion> + <npmVersion>2.15.9</npmVersion> + <nodeDownloadRoot>https://nodejs.org/dist/</nodeDownloadRoot> + <npmDownloadRoot>https://registry.npmjs.org/npm/-/</npmDownloadRoot> + </configuration> + <executions> + <execution> + <id>install node and npm</id> + <!-- optional: default phase is "generate-resources" --> + <phase>initialize</phase> + <goals> + <goal>install-node-and-npm</goal> + <goal>npm</goal> + </goals> + </execution> + <execution> + <id>bower install</id> + <phase>initialize</phase> + <goals> + <goal>bower</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + <finalName>winery-topologymodeler</finalName> + <pluginManagement> + <plugins> + <plugin> + <!-- hint by http://wiki.eclipse.org/M2E_plugin_execution_not_covered --> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <versionRange>[1.0.0,)</versionRange> + <goals> + <goal>run</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore /> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> +</project> diff --git a/winery/org.eclipse.winery.topologymodeler/sonar-project.js.properties b/winery/org.eclipse.winery.topologymodeler/sonar-project.js.properties new file mode 100644 index 0000000..253705e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/sonar-project.js.properties @@ -0,0 +1,13 @@ +# required metadata +sonar.projectKey=org.eclipse.winery.topologymodeler-js +sonar.projectName=org.eclipse.winery.topologymodeler-js +sonar.projectVersion=0.1.2 + +# path to source directories (required) +sonar.sources=WebContent/ +sonar.exclusions=components/** + +# The value of the property must be the key of the language. +sonar.language=js + +sonar.sourceEncoding=UTF-8 diff --git a/winery/org.eclipse.winery.topologymodeler/sonar-project.web.properties b/winery/org.eclipse.winery.topologymodeler/sonar-project.web.properties new file mode 100644 index 0000000..b15e63d --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/sonar-project.web.properties @@ -0,0 +1,13 @@ +# required metadata +sonar.projectKey=org.eclipse.winery.topologymodeler-web +sonar.projectName=org.eclipse.winery.topologymodeler-web +sonar.projectVersion=0.1.2 + +# path to source directories (required) +sonar.sources=src/main/webapp/ +sonar.exclusions=components/** + +# The value of the property must be the key of the language. +sonar.language=web + +sonar.sourceEncoding=UTF-8 diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/WineryUtil.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/WineryUtil.java new file mode 100644 index 0000000..2dc7e27 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/WineryUtil.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation + *******************************************************************************/ +package org.eclipse.winery.topologymodeler; + +import java.util.List; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.eclipse.winery.common.interfaces.QNameWithName; + +public class WineryUtil { + + /** + * LocalName is the ID of the element, whereas Name is the speaking name + */ + public static class LocalNameNamePair implements Comparable<LocalNameNamePair> { + + String localName; + String name; + + + public LocalNameNamePair(String localName, String name) { + this.localName = localName; + this.name = name; + } + + public String getLocalName() { + return this.localName; + } + + public String getName() { + return this.name; + } + + /** + * Ordering according to name + */ + @Override + public int compareTo(LocalNameNamePair otherPair) { + return this.name.compareTo(otherPair.name); + } + + @Override + public int hashCode() { + return this.localName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof LocalNameNamePair) { + return this.localName.equals(((LocalNameNamePair) o).getLocalName()); + } else { + return false; + } + } + } + + + public static SortedMap<String, SortedSet<LocalNameNamePair>> convertQNameWithNameListToNamespaceToLocalNameNamePairList(List<QNameWithName> list) { + if (list == null) { + throw new IllegalArgumentException("list may not be null"); + } + SortedMap<String, SortedSet<LocalNameNamePair>> res = new TreeMap<>(); + for (QNameWithName qnameWithName : list) { + SortedSet<LocalNameNamePair> localNameNamePairSet = res.get(qnameWithName.qname.getNamespaceURI()); + if (localNameNamePairSet == null) { + localNameNamePairSet = new TreeSet<>(); + res.put(qnameWithName.qname.getNamespaceURI(), localNameNamePairSet); + } + LocalNameNamePair pair = new LocalNameNamePair(qnameWithName.qname.getLocalPart(), qnameWithName.name); + localNameNamePairSet.add(pair); + } + return res; + } + +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/DeferredAnalyzer.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/DeferredAnalyzer.java new file mode 100644 index 0000000..c4db9bb --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/DeferredAnalyzer.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Constants; + +/** + * This class contains a method to analyze a TOSCA {@link TTopologyTemplate} for + * the occurrence of "Deferred"-{@link TRelationshipTemplate}s. + * + * A "Deferred"-{@link TRelationshipTemplate} serves as place holder for any number of Node or Relationship + * Templates. + */ +public class DeferredAnalyzer { + + /** + * Iterates over all {@link TRelationshipTemplate} and checks if its type is "deferred". + * + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return a list of found deferred {@link TRelationshipTemplate}s + */ + public static List<TRelationshipTemplate> analyzeDeferredRelations(TOSCAAnalyzer toscaAnalyzer) { + + List<TRelationshipTemplate> foundDeferredRelations = new ArrayList<TRelationshipTemplate>(); + + for (TRelationshipTemplate relationshipTemplate : toscaAnalyzer.getRelationshipTemplates()) { + if (relationshipTemplate.getType() != null && relationshipTemplate.getType().getLocalPart().equals(Constants.DEFERRED_QNAME.getLocalPart()) && + relationshipTemplate.getType().getNamespaceURI().equals(Constants.DEFERRED_QNAME.getNamespaceURI())) { + + // TODO: This step has to be done until the "Provisioning-API" + // is implemented. The Deferred RelationshipTemplate can only be + // completed if Requirements exist at the source template. + TNodeTemplate source = (TNodeTemplate) relationshipTemplate.getSourceElement().getRef(); + + if (source.getRequirements() != null) { + foundDeferredRelations.add(relationshipTemplate); + } + } + } + return foundDeferredRelations; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/PlaceHolderAnalyzer.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/PlaceHolderAnalyzer.java new file mode 100644 index 0000000..ddf0e91 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/PlaceHolderAnalyzer.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Constants; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Utils; + +/** + * This class analyzes the occurrence of place holders in a topology and writes them to an {@link ArrayList}. + */ +public class PlaceHolderAnalyzer { + + /** + * This method searches {@link TNodeTemplate}s that are derived from the abstract "PlaceHolder" type and adds them to a list. + * + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return the found place holders of the topology as a list. + */ + public static List<TNodeTemplate> analyzePlaceHolders(TOSCAAnalyzer toscaAnalyzer) { + + List<TNodeTemplate> foundPlaceHolders = new ArrayList<TNodeTemplate>(); + + // Check the type of the NodeTemplates, write them to a list if the type is derived from the common place holder type. + for (TNodeTemplate nodeTemplate : toscaAnalyzer.getNodeTemplates()) { + + TNodeType nodeType = Utils.getNodeTypeForId(toscaAnalyzer.getNodeTypes(), nodeTemplate.getType()); + + if (nodeType != null && nodeType.getDerivedFrom() != null && nodeType.getDerivedFrom().getTypeRef().getLocalPart().equals(Constants.PLACE_HOLDER_QNAME.getLocalPart()) && + nodeType.getDerivedFrom().getTypeRef().getNamespaceURI().equals(Constants.PLACE_HOLDER_QNAME.getNamespaceURI())) { + foundPlaceHolders.add(nodeTemplate); + } + } + return foundPlaceHolders; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/RequirementAnalyzer.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/RequirementAnalyzer.java new file mode 100644 index 0000000..71f3961 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/RequirementAnalyzer.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementDefinition; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Utils; + +/** + * This class analyzes the occurrence of TOSCA {@link TRequirement}s in a {@link TTopologyTemplate} and checks whether they + * are already fulfilled or not. + */ +public class RequirementAnalyzer { + + /** + * This method checks if {@link TNodeTemplate}s contain {@link TRequirement}s and adds them to a {@link Map}. + * + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return a map containing {@link TNodeTemplate}s and their {@link TRequirement}s + */ + public static Map<TRequirement, TNodeTemplate> analyzeRequirements(TOSCAAnalyzer toscaAnalyzer) { + + // map containing entries for a Requirement and its corresponding NodeTemplate + Map<TRequirement, TNodeTemplate> unfulfilledRequirements = new HashMap<TRequirement, TNodeTemplate>(); + + for (TNodeTemplate nodeTemplate : toscaAnalyzer.getNodeTemplates()) { + + List<TRequirement> requirements = new ArrayList<>(); + + TNodeType nodeType = Utils.getNodeTypeForId(toscaAnalyzer.getNodeTypes(), nodeTemplate.getType()); + + if (nodeType.getRequirementDefinitions() != null && !nodeType.getRequirementDefinitions().getRequirementDefinition().isEmpty()) { + + List<TRequirementDefinition> requirementDefinitions = nodeType.getRequirementDefinitions().getRequirementDefinition(); + + // check the requirements of the type of the used NodeTemplate + for (TRequirementDefinition requirementDefinition: requirementDefinitions) { + TRequirement requirement = new TRequirement(); + requirement.setType(requirementDefinition.getRequirementType()); + requirement.setName(requirementDefinition.getName()); + requirement.setId(Utils.createRandomID()); + } + } + + if (nodeTemplate.getRequirements() != null && !nodeTemplate.getRequirements().getRequirement().isEmpty()) { + requirements.addAll(nodeTemplate.getRequirements().getRequirement()); + } + + if (!requirements.isEmpty()) { + // list containing the RelationshipTemplates connecting to the NodeTemplate + List<TRelationshipTemplate> connectors = new ArrayList<TRelationshipTemplate>(); + + // add the connected RelationshipTemplates + for (TRelationshipTemplate connector : toscaAnalyzer.getRelationshipTemplates()) { + if (connector.getSourceElement().getRef().equals(nodeTemplate)) { + connectors.add(connector); + } + } + + // add requirements of unconnected NodeTemplates to the map because they can't be fulfilled + if (connectors.size() == 0) { + for (TRequirement requirement : requirements) { + unfulfilledRequirements.put(requirement, nodeTemplate); + } + } else { + boolean fulfilled = false; + + // check if one of the connected NodeTemplates already fulfill the requirement + for (TRequirement requirement : requirements) { + for (TRelationshipTemplate connector : connectors) { + TNodeTemplate connectedNodeTemplate = (TNodeTemplate) connector.getTargetElement().getRef(); + if (connectedNodeTemplate.getCapabilities() != null) { + for (TCapability capa : connectedNodeTemplate.getCapabilities().getCapability()) { + for (TRequirementType reqType : toscaAnalyzer.getRequirementTypes()) { + if (requirement.getType().getLocalPart().equals(reqType.getName())) { + if (reqType.getRequiredCapabilityType().getLocalPart().equals(capa.getType().getLocalPart()) + && reqType.getRequiredCapabilityType().getNamespaceURI().equals(capa.getType().getNamespaceURI())) { + fulfilled = true; + } + } + } + } + } + } + if (!fulfilled) { + unfulfilledRequirements.put(requirement, nodeTemplate); + } + } + } + } + } + return unfulfilledRequirements; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/TOSCAAnalyzer.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/TOSCAAnalyzer.java new file mode 100644 index 0000000..45131a7 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/TOSCAAnalyzer.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; + +/** + * This class contains several methods to analyze the content of a TOSCA {@link TTopologyTemplate} and to fill a data model + * with the analyzed information. This class serves the access to all types and templates of a topology. + */ +public class TOSCAAnalyzer { + + // lists containing the elements of a topology + List<TNodeTemplate> nodeTemplates = new ArrayList<TNodeTemplate>(); + List<TRelationshipTemplate> relationshipTemplates = new ArrayList<TRelationshipTemplate>(); + List<TRequirement> requirements = new ArrayList<TRequirement>(); + + List<TNodeType> nodeTypes; + List<TRelationshipType> relationshipTypes; + List<TRequirementType> requirementTypes; + + /** + * This method analyzes the TOSCA {@link TTopologyTemplate} for {@link TNodeTemplate}s, {@link TRelationshipTemplate}s + * and existing {@link TRequirement}s and adds them to a list. + * + * @param topology + * the TOSCA {@link TTopologyTemplate} + */ + public void analyzeTOSCATopology(TTopologyTemplate topology) { + + // fill the data model with content of the topology + List<TEntityTemplate> templateNodes = topology.getNodeTemplateOrRelationshipTemplate(); + + for (TEntityTemplate entityTemplate : templateNodes) { + if (entityTemplate instanceof TNodeTemplate) { + // add the node templates and their requirements to the data model + nodeTemplates.add((TNodeTemplate) entityTemplate); + if (((TNodeTemplate) entityTemplate).getRequirements() != null) { + requirements.addAll(((TNodeTemplate) entityTemplate).getRequirements().getRequirement()); + } + } else if (entityTemplate instanceof TRelationshipTemplate) { + // add RelationshipTemplates + relationshipTemplates.add((TRelationshipTemplate) entityTemplate); + } + } + } + + /** + * Setter for the types received from the Winery repository. + * + * @param nodeTypeXMLStrings + * a list of {@link TNodeType}s from the Winery repository + * @param relationshipTypeXMLStrings + * a list of {@link TRelationshipType}s from the Winery repository + * @param requirementTypeList + * a list of {@link TRequirementType}s from the Winery repository + */ + public void setTypes(List<TNodeType> nodeTypes, List<TRelationshipType> relationshipTypes, List<TRequirementType> requirementTypes) { + this.nodeTypes = nodeTypes; + this.relationshipTypes = relationshipTypes; + this.requirementTypes = requirementTypes; + } + + /** + * Returns the {@link TNodeTemplate}s of the topology. + * + * @return the {@link TNodeTemplate}s as a list + */ + public List<TNodeTemplate> getNodeTemplates() { + return nodeTemplates; + } + + /** + * Returns the {@link TRelationshipTemplate}s of the topology. + * + * @return the {@link TRelationshipTemplate}s as a list + */ + public List<TRelationshipTemplate> getRelationshipTemplates() { + return relationshipTemplates; + } + + /** + * Returns the {@link TRequirement}s of the topology. + * + * @return the {@link TRequirement}s as a list + */ + public List<TRequirement> getRequirements() { + return requirements; + } + + /** + * Returns the {@link TRelationshipType}s of the topology. + * + * @return the {@link TRelationshipType}s as a list + */ + public List<TRelationshipType> getRelationshipTypes() { + return relationshipTypes; + } + + /** + * Returns the {@link TNodeType}s of the topology. + * + * @return the {@link TNodeType}s as a list + */ + public List<TNodeType> getNodeTypes() { + return nodeTypes; + } + + /** + * Returns the {@link TRequirementType}s of the topology. + * + * @return the {@link TRequirementType}s as a list + */ + public List<TRequirementType> getRequirementTypes() { + return requirementTypes; + } + + /** + * Clears all the templates from the data model before the analysis of a topology is restarted. + */ + public void clear() { + nodeTemplates.clear(); + relationshipTemplates.clear(); + requirements.clear(); + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/package-info.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/package-info.java new file mode 100644 index 0000000..5333b5e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/analyzer/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This package contains classes and methods to analyze a TOSCA {@link org.opentosca.model.tosca.TTopologyTemplate} for its content. + */ +package org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer; + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/Constants.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/Constants.java new file mode 100644 index 0000000..e45c11a --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/Constants.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.CompletionInterface; + +/** + * This class contains several constants used by the completion add-on. + */ +public class Constants { + + /** + * Constant for the QName of the "deferred" type. + */ + public static final QName DEFERRED_QNAME = new QName("http://www.opentosca.org", "deferred"); + + /** + * Constant for the QName of the "PlaceHolder" type. + */ + public static final QName PLACE_HOLDER_QNAME = new QName("http://www.opentosca.org", "PlaceHolder"); + + /** + * Contains possible types of expandable place holders. + */ + public enum PlaceHolders { + WEBSERVER, DATABASE, OPERATINGSYSTEM, CLOUDPROVIDER; + + /** + * Overwritten toString() method to return formatted strings. + */ + public String toString() { + + switch (this) { + case WEBSERVER: + return "Webserver"; + case DATABASE: + return "Database"; + case OPERATINGSYSTEM: + return "OperatingSystem"; + case CLOUDPROVIDER: + return "CloudProvider"; + default: + return null; + } + } + } + + /** + * The messages returned by the {@link CompletionInterface} + */ + public enum CompletionMessages { + TOPOLOGYCOMPLETE, USERINTERACTION, STEPBYSTEP, SUCCESS, USERTOPOLOGYSELECTION, FAILURE; + + /** + * Overwritten toString() method to return formatted strings. + */ + public String toString() { + + switch (this) { + case TOPOLOGYCOMPLETE: + return "topologyComplete"; + case USERINTERACTION: + return "userInteraction"; + case STEPBYSTEP: + return "stepByStep"; + case SUCCESS: + return "success"; + case USERTOPOLOGYSELECTION: + return "userTopologySelection"; + case FAILURE: + return "failure"; + default: + return null; + } + } + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/JAXBHelper.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/JAXBHelper.java new file mode 100644 index 0000000..84a3e28 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/JAXBHelper.java @@ -0,0 +1,374 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.common.Util; +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.TDefinitions; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * This class contains methods for marshalling and unmarshalling a topology XML string via JAXB. + * + */ +public class JAXBHelper { + + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JAXBHelper.class.getName()); + + /** + * This constant is used in the buildXML method which add coordinates to Node Templates so they + * are arranged properly in the Winery topology modeler. + * + * The x coordinate is constant because it is assumed that a stack of NodeTemplates is displayed. + */ + private static final String NODETEMPLATE_X_COORDINATE = "500"; + + /** + * This method creates an JAXB Unmarshaller used by the methods contained in this class. + * + * @return the JAXB unmarshaller object + * + * @throws JAXBException + * this exception can occur when the JAXBContext is created + */ + private static Unmarshaller createUnmarshaller() throws JAXBException { + // initiate JaxB context + JAXBContext context; + context = JAXBContext.newInstance(Definitions.class); + + return context.createUnmarshaller(); + } + + /** + * This method returns a {@link TTopologyTemplate} given as XML string as JaxBObject. + * + * @param xmlString + * the {@link TTopologyTemplate} to be unmarshalled + * + * @return the unmarshalled {@link TTopologyTemplate} + */ + public static TTopologyTemplate getTopologyAsJaxBObject(String xmlString) { + try { + + logger.info("Getting Definitions Document..."); + + StringReader reader = new StringReader(xmlString); + + // unmarshall the XML string + Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader); + TServiceTemplate serviceTemplate = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + + logger.info("Unmarshalling successful! "); + + return serviceTemplate.getTopologyTemplate(); + + } catch (JAXBException e) { + logger.error(e.getLocalizedMessage()); + } + return null; + } + + /** + * This method returns {@link TRelationshipTemplate}s as a JaxBObject. + * + * @param xmlString + * the {@link TRelationshipTemplate} to be unmarshalled + * + * @return the unmarshalled {@link TRelationshipTemplate} + */ + public static List<TRelationshipTemplate> getRelationshipTemplatesAsJaxBObject(String xmlString) { + try { + StringReader reader = new StringReader(xmlString); + + // unmarshall + Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader); + TServiceTemplate serviceTemplate = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + + List<TRelationshipTemplate> foundRTs = new ArrayList<>(); + for (TEntityTemplate entity : serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TRelationshipTemplate) { + foundRTs.add((TRelationshipTemplate) entity); + } + } + + return foundRTs; + + } catch (JAXBException e) { + logger.error(e.getLocalizedMessage()); + } + return null; + + } + + /** + * Turns XML Strings into {@link TEntityTemplate} objects using JaxB. + * + * @param xmlString + * the XMLString to be parsed + * @return the parsed XMLString as {@link TEntityTemplate} + */ + public static List<TEntityTemplate> getEntityTemplatesAsJaxBObject(String xmlString) { + try { + StringReader reader = new StringReader(xmlString); + + Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader); + TServiceTemplate serviceTemplate = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + + return serviceTemplate.getTopologyTemplate().getNodeTemplateOrRelationshipTemplate(); + + } catch (JAXBException e) { + logger.error(e.getLocalizedMessage()); + } + return null; + + } + + /** + * Converts any object of the TOSCA data model to a JaxBObject. + * + * @param xmlString + * the {@link Definitions} object to be converted + * + * @return the unmarshalled {@link Definitions} object + */ + public static Definitions getXasJaxBObject(String xmlString) { + try { + StringReader reader = new StringReader(xmlString); + Definitions jaxBDefinitions = (Definitions) createUnmarshaller().unmarshal(reader); + + return jaxBDefinitions; + + } catch (JAXBException e) { + logger.error(e.getLocalizedMessage()); + } + return null; + + } + + /** + * This method adds a selection of {@link TNodeTemplate}- and {@link TRelationshipTemplate}-XML-Strings to a {@link TTopologyTemplate}-XML-String using JAXB. + * After the templates have been added, the {@link TTopologyTemplate} object is re-marshalled to an XML-String. + * + * This method is called by the selectionHandler.jsp after several Node or RelationshipTemplates have been chosen in a dialog. + * + * @param topology + * the topology as XML string + * @param allTemplateChoicesAsXML + * all possible template choices as TOSCA-XML strings containing the complete templates + * @param selectedNodeTemplatesAsJSON + * the names of the selected NodeTemplates as JSONArray + * @param selectedRelationshipTemplatesAsJSON + * the names of the selected RelationshipTemplates as JSONArray + * + * @return the complete topology XML string + */ + public static String addTemplatesToTopology(String topology, String allTemplateChoicesAsXML, String selectedNodeTemplatesAsJSON, String selectedRelationshipTemplatesAsJSON) { + try { + + // initialization code for the jackson types used to convert JSON string arrays to a java.util.List + ObjectMapper mapper = new ObjectMapper(); + TypeFactory factory = mapper.getTypeFactory(); + + // convert the JSON array containing the names of the selected RelationshipTemplates to a java.util.List + List<String> selectedRelationshipTemplates = mapper.readValue(selectedRelationshipTemplatesAsJSON, factory.constructCollectionType(List.class, String.class)); + + // convert the topology and the choices to objects using JAXB + TTopologyTemplate topologyTemplate = getTopologyAsJaxBObject(topology); + List<TEntityTemplate> allTemplateChoices = getEntityTemplatesAsJaxBObject(allTemplateChoicesAsXML); + + // this distinction of cases is necessary because it is possible that only RelationshipTemplates have been selected + if (selectedNodeTemplatesAsJSON != null) { + + // convert the JSON string array containing the names of the selected NodeTemplates to a java.util.List + List<String> selectedNodeTemplates = mapper.readValue(selectedNodeTemplatesAsJSON, factory.constructCollectionType(List.class, String.class)); + + // search the selected NodeTemplate in the List of all choices by its name to receive its object which will ne added to the topology + for (String nodeTemplateName : selectedNodeTemplates) { + for (TEntityTemplate choice : allTemplateChoices) { + if (choice instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) choice; + // matching a name is usually unsafe because the uniqueness cannot be assured, + // however similar names are not possible at this location due to the implementation of the selection dialogs + if (nodeTemplateName.equals(nodeTemplate.getName())) { + // add the selected NodeTemplate to the topology + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(nodeTemplate); + + // due to the mapping of IDs in the selection dialog, the corresponding Relationship Template of the inserted Node Template misses its SourceElement. + // Re-add it to avoid errors. + for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TRelationshipTemplate) { + TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) entity; + if (relationshipTemplate.getSourceElement().getRef() == null) { + // connect to the added NodeTemplate + SourceElement sourceElement = new SourceElement(); + sourceElement.setRef(nodeTemplate); + relationshipTemplate.setSourceElement(sourceElement); + } + } + } + } + } + } + } + + // now search and add the selected RelationshipTemplate object connecting to the inserted NodeTemplate + for (String relationshipTemplateName : selectedRelationshipTemplates) { + for (TEntityTemplate toBeAdded : allTemplateChoices) { + if (toBeAdded instanceof TRelationshipTemplate) { + TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) toBeAdded; + if (relationshipTemplateName.equals(relationshipTemplate.getName())) { + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(relationshipTemplate); + } + } + } + } + + } else { + // in this case only Relationship Templates have been selected + List<TRelationshipTemplate> allRelationshipTemplateChoices = JAXBHelper.getRelationshipTemplatesAsJaxBObject(allTemplateChoicesAsXML); + + // add the target Node Template to the topology which is unique due to the implementation of the selection dialog + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add((TNodeTemplate) ((TRelationshipTemplate) allRelationshipTemplateChoices.get(0)).getTargetElement().getRef()); + + // search the JAXB object of the selected RelationshipTemplate and add it to the topology + for (String relationshipTemplateName : selectedRelationshipTemplates) { + for (TRelationshipTemplate choice : allRelationshipTemplateChoices) { + if (relationshipTemplateName.equals(choice.getName())) { + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(choice); + } + } + } + + for (TEntityTemplate entityTemplate : topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (entityTemplate instanceof TRelationshipTemplate) { + TRelationshipTemplate relationship = (TRelationshipTemplate) entityTemplate; + + // due to the mapping of IDs in the selection dialog, the corresponding Relationship Template of the inserted Node Template misses its SourceElement. + // Re-add it to avoid errors. + if (relationship.getSourceElement().getRef() == null) { + relationship.getSourceElement().setRef((TNodeTemplate) ((TRelationshipTemplate) allRelationshipTemplateChoices.get(0)).getTargetElement().getRef()); + } + } + } + } + + // re-convert the topology from a JAXB object to an XML string and return it + Definitions definitions = new Definitions(); + TServiceTemplate st = new TServiceTemplate(); + st.setTopologyTemplate(topologyTemplate); + definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(st); + JAXBContext context = JAXBContext.newInstance(Definitions.class); + Marshaller m = context.createMarshaller(); + StringWriter stringWriter = new StringWriter(); + + m.marshal(definitions, stringWriter); + + return stringWriter.toString(); + + } catch (JAXBException | IOException e) { + logger.error(e.getLocalizedMessage()); + } + + return null; + } + + + /** + * Marshalls a JAXB object of the TOSCA model to an XML string. + * + * @param clazz + * the class of the object + * @param obj + * the object to be marshalled + * + * @return + */ + public static String getXMLAsString(@SuppressWarnings("rawtypes") Class clazz, Object obj) { + try { + @SuppressWarnings("rawtypes") + JAXBElement rootElement = Util.getJAXBElement(clazz, obj); + JAXBContext context = JAXBContext.newInstance(TDefinitions.class); + Marshaller m; + + m = context.createMarshaller(); + + StringWriter w = new StringWriter(); + m.marshal(rootElement, w); + String res = w.toString(); + + return res; + } catch (JAXBException e) { + logger.error(e.getLocalizedMessage()); + } + return null; + } + + /** + * This methods alters the XML with JAXB so it can be imported in Winery. This is necessary because Winery needs additional information for the position of the templates in the + * Winery-Modeler-UI. + * + * This code is adapted from the org.eclipse.winery.repository.Utils.getXMLAsString() method. + * + * @param topology + * the {@link TTopologyTemplate} to be altered + * + * @return the altered {@link TTopologyTemplate} + */ + public static TTopologyTemplate buildXML(TTopologyTemplate topology) { + + // the coordinate of the NodeTemplate in Winery. Begin 100 pixel from the top to improve arrangement. + int yCoordinates = 100; + + for (TEntityTemplate template : topology.getNodeTemplateOrRelationshipTemplate()) { + // add node templates + if (template instanceof TNodeTemplate) { + + TNodeTemplate nodeTemplate = (TNodeTemplate) template; + + // remove the Requirements tag if necessary + if (nodeTemplate.getRequirements() != null && nodeTemplate.getRequirements().getRequirement() == null) { + nodeTemplate.setRequirements(null); + } + + ModelUtilities.setLeft(nodeTemplate, NODETEMPLATE_X_COORDINATE); + ModelUtilities.setTop(nodeTemplate, Integer.toString(yCoordinates)); + + yCoordinates += 150; + } + } + + return topology; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/NodeTemplateConnector.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/NodeTemplateConnector.java new file mode 100644 index 0000000..f1d4b6b --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/NodeTemplateConnector.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; + +/** + * This class searches a {@link TRelationshipType} which is able to connect two given {@link TNodeTemplate}s. + * + */ +public class NodeTemplateConnector { + + /** + * Searches a compatible {@link TRelationshipType} to connect two {@link TNodeTemplate}s. + * + * @param source + * the source {@link TNodeTemplate} + * @param target + * the target {@link TNodeTemplate} + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * @param requirement + * the {@link TRequirement} of the source {@link TNodeTemplate} + * + * @return a list of suitable {@link TRelationshipType}s + */ + public static List<TRelationshipType> findRelationshipType(TNodeTemplate source, TNodeTemplate target, TOSCAAnalyzer toscaAnalyzer, TRequirement requirement) { + + List<TRelationshipType> suitableRelationshipTypes = new ArrayList<TRelationshipType>(); + List<TRelationshipType> allRelationshipTypes = toscaAnalyzer.getRelationshipTypes(); + + // in case the connection to a placeholder is searched, no requirement exists + if (requirement != null) { + + List<TCapability> capabilities = target.getCapabilities().getCapability(); + + // check if a RelationshipType can connect a requirement of the source NodeTemplate to a capability of the target NodeTemplate + for (TRelationshipType relationshipType : allRelationshipTypes) { + if (relationshipType.getValidSource() != null && relationshipType.getValidTarget() != null) { + for (TCapability capability : capabilities) { + if ((relationshipType.getValidSource().getTypeRef().equals(requirement.getType()) && relationshipType.getValidTarget().getTypeRef().equals(capability.getType()))) { + suitableRelationshipTypes.add(relationshipType); + } + } + } + } + } + + // to extend the selection check if a RelationshipType can connect the type of the source NodeTemplate to the type of the target NodeTemplate + for (TRelationshipType rt : allRelationshipTypes) { + if (rt.getValidSource() != null && rt.getValidTarget() != null) { + if ((rt.getValidSource().getTypeRef().equals(source.getType()) && rt.getValidTarget().getTypeRef().equals(target.getType()))) { + suitableRelationshipTypes.add(rt); + } + } + } + + // in case no suitable relationship type could be found, search for generic types without the optional ValidSource / ValidTarget elements. + if (suitableRelationshipTypes.isEmpty()) { + for (TRelationshipType rt : allRelationshipTypes) { + if (rt.getValidSource() == null && rt.getValidTarget() == null) { + suitableRelationshipTypes.add(rt); + } + } + } + + return suitableRelationshipTypes; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/RESTHelper.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/RESTHelper.java new file mode 100644 index 0000000..789d529 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/RESTHelper.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; + + +import org.eclipse.winery.common.Util; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.slf4j.LoggerFactory; + +/** + * This class contains helper methods to call the REST API and PUT/POST information to it. + */ +public class RESTHelper { + + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(RESTHelper.class.getName()); + + /** + * This method uses a REST call to save the completed {@link TTopologyTemplate} to the repository. + * + * @param topology + * the {@link TTopologyTemplate} to be saved + * @param topologyTemplateURL + * the URL the {@link TTopologyTemplate} is saved to + * @param overwriteTopology + * whether the topology is overwritten or a new topology shall be created + * @param topologyName + * the name of the newly created topology to build the URL if a new topology shall be created + * @param topologyNamespace + * the name space of the newly created topology to build the URL if a new topology shall be created + * @param repositoryURL + * the URL to the repository to build the URL if a new topology shall be created + */ + public static void saveCompleteTopology(TTopologyTemplate topology, String topologyTemplateURL, boolean overwriteTopology, String topologyName, String topologyNamespace, String repositoryURL) { + try { + + URL url = null; + + if (overwriteTopology) { + url = new URL(topologyTemplateURL); + } else { + // this is necessary to avoid encoding issues + topologyNamespace = Util.DoubleURLencode(topologyNamespace); + // build the URL with the repositoryURL, the topology namespace and the topology name + url = new URL(repositoryURL + "/servicetemplates/" + topologyNamespace + "/" + topologyName + "/topologytemplate/"); + + logger.info("The URL the topology is saved to: " + url); + } + + // using SSL + System.setProperty("javax.net.ssl.trustStore", "jssecacerts.cert"); + + // configure message + HttpURLConnection urlConn; + urlConn = (HttpURLConnection) url.openConnection(); + + logger.info("Sending HTTP request..."); + + urlConn.setDoOutput(true); + urlConn.setRequestMethod("PUT"); + urlConn.setRequestProperty("Content-type", "text/xml"); + OutputStreamWriter out = new OutputStreamWriter(urlConn.getOutputStream()); + + // build the XML string to be saved + TTopologyTemplate outputTopology = JAXBHelper.buildXML(topology); + String outputString = JAXBHelper.getXMLAsString(outputTopology.getClass(), outputTopology); + + logger.info(outputString); + logger.info("Sending output to Winery."); + + out.write(outputString); + out.close(); + urlConn.getOutputStream().close(); + logger.info("Output sent, waiting for response..."); + urlConn.getInputStream(); + + logger.info("HTTP Response Code is: " + urlConn.getResponseCode()); + + } catch (IOException e) { + logger.error(e.getLocalizedMessage()); + } + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/Utils.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/Utils.java new file mode 100644 index 0000000..5f9826b --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/Utils.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import javax.xml.namespace.QName; + +import org.eclipse.winery.model.tosca.TCapabilityDefinition; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.slf4j.LoggerFactory; + +/** + * Contains methods to match requirements and capabilities and find elements in the {@link TTopologyTemplate} + */ +public class Utils { + + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Utils.class.getName()); + + /** + * This method searches {@link TNodeType}s in the repository that match a requirement. + * + * @param requirement + * the requirement to be matched + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return a list of the matched {@link TNodeType}s + */ + public static List<TNodeType> matchRequirementAndCapability(TRequirement requirement, TOSCAAnalyzer toscaAnalyzer) { + + List<TNodeType> possibleNodeTypes = new ArrayList<TNodeType>(); + + // find all matching Node Types for a requirement by the "requiredCapabilityType" attribute of its type + for (TRequirementType requirementType : toscaAnalyzer.getRequirementTypes()) { + if (requirementType.getName().equals(requirement.getType().getLocalPart())) { + + QName requiredCapabilityType = requirementType.getRequiredCapabilityType(); + for (TNodeType nodeType : toscaAnalyzer.getNodeTypes()) { + if (nodeType.getCapabilityDefinitions() != null) { + for (TCapabilityDefinition cd : nodeType.getCapabilityDefinitions().getCapabilityDefinition()) { + if (cd.getCapabilityType().getLocalPart().equals(requiredCapabilityType.getLocalPart())) { + possibleNodeTypes.add(nodeType); + } + } + } + } + } + } + + return possibleNodeTypes; + } + + /** + * Generates a random {@link UUID} exclusively used by the {@link TemplateBuilder}. + * + * @return the generated {@link UUID} id + */ + public static String createRandomID() { + return UUID.randomUUID().toString(); + } + + /** + * Returns a {@link TNodeTemplate} for a given Id. + * + * @param nodeTemplates + * all the {@link TNodeTemplate} in the {@link TTopologyTemplate} + * @param id + * the id of the {@link TNodeTemplate} to be found + * + * @return the found {@link TNodeTemplate} or null if not found + */ + public static TNodeTemplate getNodeTemplateForId(List<TNodeTemplate> nodeTemplates, String id) { + + for (TNodeTemplate nt : nodeTemplates) { + + if (nt.getId().equals(id)) { + return nt; + } + } + + logger.error("No NodeTemplate with " + id + " exists"); + + return null; + + } + + /** + * Returns a {@link TNodeType} for a given Id. + * + * @param nodeTypes + * All the {@link TNodeType} in the {@link TTopologyTemplate} + * @param Id + * The id of the {@link TNodeType} to be searched + * @return the {@link TNodeType} or null if not found + */ + public static TNodeType getNodeTypeForId(List<TNodeType> nodeTypes, QName id) { + + for (TNodeType nodeType : nodeTypes) { + if (nodeType.getName().equals(id.getLocalPart()) && nodeType.getTargetNamespace().equals(id.getNamespaceURI())) { + return nodeType; + } + } + + logger.error("No NodeType with " + id + " exists"); + + // no type could be found for the given ID, this case cannot occur if the topology was modelled in the Winery Topology Modeler + return null; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/package-info.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/package-info.java new file mode 100644 index 0000000..5d42210 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/helper/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This package contains helper classes and methods to assist the completion. + */ +package org.eclipse.winery.topologymodeler.addons.topologycompleter.helper; + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/package-info.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/package-info.java new file mode 100644 index 0000000..19e334e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * this package contains classes to complete a topology template + */ +package org.eclipse.winery.topologymodeler.addons.topologycompleter;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/placeholderhandling/PlaceHolderHandler.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/placeholderhandling/PlaceHolderHandler.java new file mode 100644 index 0000000..a384e91 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/placeholderhandling/PlaceHolderHandler.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.placeholderhandling; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Constants; + +/** + * This class finds suitable replacement types for a place holder. + */ +public class PlaceHolderHandler { + + /** + * This method returns a suitable {@link TNodeType} to replace a given {@link TNodeTemplate} placeholder. + * A suitable Node Type to replace a placeholder is matched by its type. If the type of a NodeType equals the identifier of a placeholder + * it can be used to replace it. + * + * @param nodeTemplate + * the placeholder to be replaced + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return a list of {@link TNodeType}s to replace the placeholder + */ + public static List<TNodeType> getSuitableNodeTypes(TNodeTemplate nodeTemplate, TOSCAAnalyzer toscaAnalyzer) { + + List<TNodeType> suitableNodeTypes = new ArrayList<>(); + + // TODO: matching the name without a name space is unsafe and only works assuming that no one creates generic NodeTemplates with the same name as the place holders. + // However a NodeTemplate name does not have a name space. + if (nodeTemplate.getName().equals(Constants.PlaceHolders.WEBSERVER.toString())) { + for (TNodeType nodeType : toscaAnalyzer.getNodeTypes()) { + if (nodeType.getDerivedFrom() != null && nodeType.getDerivedFrom().getTypeRef().getLocalPart().equals(Constants.PlaceHolders.WEBSERVER.toString())) { + suitableNodeTypes.add(nodeType); + } + } + } else if (nodeTemplate.getName().equals(Constants.PlaceHolders.DATABASE.toString())) { + for (TNodeType nodeType : toscaAnalyzer.getNodeTypes()) { + if (nodeType.getDerivedFrom() != null && nodeType.getDerivedFrom().getTypeRef().getLocalPart().equals(Constants.PlaceHolders.DATABASE.toString())) { + suitableNodeTypes.add(nodeType); + } + } + } else if (nodeTemplate.getName().equals(Constants.PlaceHolders.OPERATINGSYSTEM.toString())) { + for (TNodeType nodeType : toscaAnalyzer.getNodeTypes()) { + if (nodeType.getDerivedFrom() != null && nodeType.getDerivedFrom().getTypeRef().getLocalPart().equals(Constants.PlaceHolders.OPERATINGSYSTEM.toString())) { + suitableNodeTypes.add(nodeType); + } + } + } else if (nodeTemplate.getName().equals(Constants.PlaceHolders.CLOUDPROVIDER.toString())) { + for (TNodeType nodeType : toscaAnalyzer.getNodeTypes()) { + if (nodeType.getDerivedFrom() != null && nodeType.getDerivedFrom().getTypeRef().getLocalPart().equals(Constants.PlaceHolders.CLOUDPROVIDER.toString())) { + suitableNodeTypes.add(nodeType); + } + } + } + + return suitableNodeTypes; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/CompletionInterface.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/CompletionInterface.java new file mode 100644 index 0000000..e46d3b1 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/CompletionInterface.java @@ -0,0 +1,257 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion; + +import java.util.List; +import java.util.Map; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.repository.client.IWineryRepositoryClient; +import org.eclipse.winery.repository.client.WineryRepositoryClientFactory; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.DeferredAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.PlaceHolderAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.RequirementAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Constants; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.JAXBHelper; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.RESTHelper; +import org.slf4j.LoggerFactory; + +/** + * This class is the entry point of the TOSCA topology completion which is called by the Winery Topology Modeler. + * It receives an incomplete {@link TTopologyTemplate} from Winery. + * The completion of the incomplete {@link TTopologyTemplate} is managed by this class. + */ +public class CompletionInterface { + + /** + * Logger for debug reasons. + */ + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CompletionInterface.class.getName()); + + /** + * This global variable is returned to the Winery Topology Modelerer via getCurrentTopology() to display intermediate results when an user interaction is necessary. + */ + private TTopologyTemplate currentTopology; + + /** + * This list contains {@link TTopologyTemplate}s to be chosen by the user when the topology solution isn't unique. + */ + private List<TTopologyTemplate> topologyTemplateChoices; + + /** + * This List contains {@link TRelationshipTemplate}s to be chosen by the user. + */ + private List<TEntityTemplate> relationshipTemplateChoices; + + /** + * This Map contains {@link TNodeTemplate}s and {@link TRelationshipTemplate}s to be chosen by the user during the step-by-step approach. + */ + private Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> nodeTemplateChoices; + + /** + * String containing an error message to be displayed in Winery if necessary. + */ + private String errorMessage = ""; + + /** + * This method receives an incomplete {@link TTopologyTemplate} and the repository content from Winery. After analyzing the {@link TTopologyTemplate}, the topology is completed. This method will + * return a message after the completion whether the completion was successful, has failed or the user has to interact. + * + * @param topology + * (XMLString) the {@link TTopologyTemplate} to be completed as XMLString + * @param serviceTemplateName + * the name of the ServiceTemplate for REST calls + * @param topologyTemplateURL + * the URL where the template is saved to + * @param overwriteTopology + * determines in which way the {@link TTopologyTemplate} is saved. The current {@link TTopologyTemplate} can either be overwritten or a new topology can be created. + * @param topologyName + * the name of the {@link TTopologyTemplate} when a new {@link TTopologyTemplate} shall be created + * @param topologyNamespace + * the namespace of the {@link TTopologyTemplate} when a new {@link TTopologyTemplate} shall be created + * @param repositoryURL + * the URL to the repository to receive and write TOSCA specific information + * @param stepByStep + * whether the topology completion is processed step-by-step or not + * @param restarted + * whether the topology completion is restarted or started for the first time + * + * @return a message to Winery that contains information whether the topology is complete, the user has to interact or an error occurred. + */ + public String complete(String topology, String serviceTemplateName, String topologyTemplateURL, Boolean overwriteTopology, + String topologyName, String topologyNamespace, String repositoryURL, boolean stepByStep, boolean restarted) { + + logger.info("Starting completion..."); + + //////////////////////////////////////// + // STEP 1: Receive topology from Winery + //////////////////////////////////////// + + logger.info("Saving to: " + topologyTemplateURL); + + logger.info("The service template to be completed is: " + serviceTemplateName); + + // receive types from repository + IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + client.addRepository(repositoryURL); + + List<TNodeType> nodeTypeList = (List<TNodeType>) client.getAllTypes(TNodeType.class); + List<TRelationshipType> relationshipTypeList = (List<TRelationshipType>) client.getAllTypes(TRelationshipType.class); + List<TRequirementType> requirementTypeList = (List<TRequirementType>) client.getAllTypes(TRequirementType.class); + + ///////////////////////////////////// + // Step 2: Analyze topology content + ///////////////////////////////////// + + logger.info("The modelled topology as XML: " + topology); + + TTopologyTemplate topologyTemplate = JAXBHelper.getTopologyAsJaxBObject(topology); + + logger.info("Analyzing topology..."); + + // analyze the received topology + TOSCAAnalyzer toscaAnalyzer = new TOSCAAnalyzer(); + toscaAnalyzer.analyzeTOSCATopology(topologyTemplate); + toscaAnalyzer.setTypes(nodeTypeList, relationshipTypeList, requirementTypeList); + + // if the topology is already complete, a message is displayed + if (checkCompletnessOfTopology(toscaAnalyzer) && !restarted) { + return Constants.CompletionMessages.TOPOLOGYCOMPLETE.toString(); + } else { + + ///////////////////////////////////////// + // Step 3: Invoke the topology completion + ///////////////////////////////////////// + logger.info("Invoking Topology Completion..."); + + CompletionManager completionManager = new CompletionManager(toscaAnalyzer, stepByStep); + List<TTopologyTemplate> completedTopology = completionManager.manageCompletion(topologyTemplate); + + // the user has to interact by choosing a RelationshipTemplate, send message to Winery which will display a dialog + if (completionManager.getUserInteraction() && !stepByStep) { + currentTopology = completedTopology.get(0); + relationshipTemplateChoices = completionManager.getChoices(); + + return Constants.CompletionMessages.USERINTERACTION.toString(); + + } else if (completionManager.getNodeTemplateUserInteraction() && stepByStep) { + // the topology completion is processed Step-by-Step, the user has to choose Node and RelationshipTemplates to be inserted + currentTopology = completedTopology.get(0); + nodeTemplateChoices = completionManager.getTemplateChoices(); + + for (TNodeTemplate nodeTemplate : nodeTemplateChoices.keySet()) { + Map<TNodeTemplate, List<TEntityTemplate>> entityTemplates = nodeTemplateChoices.get(nodeTemplate); + + for (TNodeTemplate entity : entityTemplates.keySet()) { + for (TEntityTemplate relationshipTemplate : entityTemplates.get(entity)) { + // remove entity that has to be chosen next + if (currentTopology.getNodeTemplateOrRelationshipTemplate().contains(relationshipTemplate)) { + currentTopology.getNodeTemplateOrRelationshipTemplate().remove(relationshipTemplate); + } else if (currentTopology.getNodeTemplateOrRelationshipTemplate().contains(entity)) { + currentTopology.getNodeTemplateOrRelationshipTemplate().remove(entity); + } + } + } + } + + return Constants.CompletionMessages.STEPBYSTEP.toString(); + } + + logger.info("Completion successful!"); + + if (completedTopology.size() == 1) { + // solution is unique, save the topology + RESTHelper.saveCompleteTopology(completedTopology.get(0), topologyTemplateURL, overwriteTopology, topologyName, topologyNamespace, repositoryURL); + return Constants.CompletionMessages.SUCCESS.toString(); + } else if (completedTopology.size() > 1) { + // if there are several topology solutions, let the user choose + this.topologyTemplateChoices = completedTopology; + return Constants.CompletionMessages.USERTOPOLOGYSELECTION.toString(); + } else { + // an error occurred + errorMessage = "Error: No suitable NodeTemplate could be found for a Requirement or PlaceHolder."; + return Constants.CompletionMessages.FAILURE.toString(); + } + } + } + + /** + * This method checks if the topology is already complete. It will be called before executing the topology completion but + * only in case the topology completion isn't restarted after a user selection. + * + * @param toscaAnalyzer + * the topology to be checked + * @return whether the topology is complete or not + */ + public boolean checkCompletnessOfTopology(TOSCAAnalyzer toscaAnalyzer) { + + if (RequirementAnalyzer.analyzeRequirements(toscaAnalyzer).isEmpty() && PlaceHolderAnalyzer.analyzePlaceHolders(toscaAnalyzer).isEmpty() + && DeferredAnalyzer.analyzeDeferredRelations(toscaAnalyzer).isEmpty()) { + return true; + } else { + return false; + } + } + + /** + * Returns the current state of the completion. + * + * @return the current {@link TTopologyTemplate} + */ + public TTopologyTemplate getCurrentTopology() { + return currentTopology; + } + + /** + * Returns the choices whenever there are several possible complete {@link TTopologyTemplate}s. They will be displayed in Winery and chosen by the user. + * + * @return the possible {@link TTopologyTemplate} choices as a list. + */ + public List<TTopologyTemplate> getTopologyTemplateChoices() { + return topologyTemplateChoices; + } + + /** + * Returns the {@link TRelationshipTemplate} choices + * + * @return the {@link TRelationshipTemplate}s to be chosen + */ + public List<TEntityTemplate> getRelationshipTemplateChoices() { + return relationshipTemplateChoices; + } + + /** + * Returns several {@link TNodeTemplate} and {@link TRelationshipTemplate} choices when the user selected the step-by-step approach. + * + * @return the {@link TNodeTemplate} choices + */ + public Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> getNodeTemplateChoices() { + return nodeTemplateChoices; + } + + /** + * Returns a message when an error occurred during the completion. + * + * @return the error message + */ + public String getErrorMessage() { + return errorMessage; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/CompletionManager.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/CompletionManager.java new file mode 100644 index 0000000..1f47cf5 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/CompletionManager.java @@ -0,0 +1,358 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.DeferredAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.PlaceHolderAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.RequirementAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.DeferredCompleter; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.PlaceHolderCompleter; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.RequirementCompleter; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.StepByStepCompleter; + +/** + * This class manages the completion of a TOSCA {@link TTopologyTemplate}. + */ +public class CompletionManager { + + private static final Logger logger = Logger.getLogger(CompletionManager.class.getName()); + + /** + * {@link TOSCAAnalyzer} object to access the JAXB data model + */ + TOSCAAnalyzer toscaAnalyzer; + + /** + * Map containing the topology solutions. + * + * The first parameter of the map is an index used to traverse the map easily. The second parameter of the solutions map + * is another map containing a possible topology solution and a boolean value that determines if the topology is complete. + * When all topologies of the solution map are complete, it will be returned to Winery. + */ + Map<Integer, Map<TTopologyTemplate, Boolean>> solutions; + + /** + * Whether a step-by-step or an one-step approach is conducted + */ + boolean stepByStep; + + /** + * Map containing {@link TNodeTemplate}s and {@link TRelationshipTemplate}s to be chosen by the user in the step-by-step approach. + */ + private Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> templateChoices; + + /** + * Whether a user interaction for choosing inserted {@link TNodeTemplate}s and {@link TRelationshipTemplate}s is necessary or not. + */ + private boolean nodeTemplateUserInteraction = false; + + /** + * List containing {@link TRelationshipTemplate} to be chosen by the user. + */ + private List<TEntityTemplate> choices; + + /** + * Whether a user interaction for choosing inserted {@link TRelationshipTemplate}s is necessary or not. + */ + boolean userInteraction = false; + + /** + * The index of the topology solutions map. + */ + int index; + + /** + * The class constructor. + * + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * @param stepByStep + * whether the topology completion is processed step-by-step or not + */ + public CompletionManager(TOSCAAnalyzer toscaAnalyzer, boolean stepByStep) { + this.toscaAnalyzer = toscaAnalyzer; + this.stepByStep = stepByStep; + this.index = 0; + + // instantiate the solution map + solutions = new HashMap<Integer, Map<TTopologyTemplate, Boolean>>(); + } + + /** + * This recursive method analyzes and completes a TOSCA {@link TTopologyTemplate}. + * + * @param topology + * the TOSCA {@link TTopologyTemplate} to be completed + * + * @return the complete TOSCA {@link TTopologyTemplate} object + */ + public List<TTopologyTemplate> manageCompletion(TTopologyTemplate topology) { + + // ------------------------- + // Analyze topology template + // ------------------------- + + // the data model must be cleared before analyzing the topology + toscaAnalyzer.clear(); + + // analyze the content of the topology template + toscaAnalyzer.analyzeTOSCATopology(topology); + + // Note: The TOSCAAnalyzer object is used for the analysis to access the NodeTemplates or RelationshipTemplates directly, + // so no cast from the parent type TEntityTemplate is required + + // -------------------------------- + // Analyze unfulfilled requirements + // -------------------------------- + Map<TRequirement, TNodeTemplate> unfulfilledRequirements = RequirementAnalyzer.analyzeRequirements(toscaAnalyzer); + + // --------------------------------------- + // Analyze the occurrence of place holders + // --------------------------------------- + List<TNodeTemplate> placeHolders = PlaceHolderAnalyzer.analyzePlaceHolders(toscaAnalyzer); + + // -------------------------------------------------------- + // Analyze the occurrence of deferred RelationshipTemplates + // -------------------------------------------------------- + List<TRelationshipTemplate> deferredRelations = DeferredAnalyzer.analyzeDeferredRelations(toscaAnalyzer); + + // --------------------- + // Complete the topology + // --------------------- + + // with the step by step approach, a user interaction is always necessary. So the topology and + // the choices will be returned in every step. A combination of the step-by-step approach and a deferred topology is not + // possible because every path of the depth search can lead to a dead end. + if (stepByStep && deferredRelations.isEmpty()) { + logger.info("Completing topology step by step."); + + List<TTopologyTemplate> solutionList = new ArrayList<TTopologyTemplate>(); + + if (!unfulfilledRequirements.isEmpty() && placeHolders.isEmpty()) { + + // complete a topology containing requirements step by step using the StepByStepCompleter class + StepByStepCompleter stepByStepCompleter = new StepByStepCompleter(topology); + stepByStepCompleter.completeTopologyStepByStep(unfulfilledRequirements, toscaAnalyzer); + + // get the NodeTemplate choices for the user + templateChoices = stepByStepCompleter.getTemplateChoices(); + nodeTemplateUserInteraction = true; + + solutionList.add(topology); + + logger.info("Returning topology for user interaction"); + + return solutionList; + + } else if (unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty()) { + + // complete a topology containing place holders step by step using the StepByStepCompleter class + StepByStepCompleter stepByStepCompleter = new StepByStepCompleter(topology); + TRelationshipTemplate genericRelationship = stepByStepCompleter.completeWildcardTopologyStepByStep(placeHolders, toscaAnalyzer); + + // get the NodeTemplate selection for the user to choose + templateChoices = stepByStepCompleter.getTemplateChoices(); + nodeTemplateUserInteraction = true; + + TNodeTemplate toBeRemoved = stepByStepCompleter.getPlaceHolder(); + topology.getNodeTemplateOrRelationshipTemplate().remove(toBeRemoved); + topology.getNodeTemplateOrRelationshipTemplate().remove(genericRelationship); + + solutionList.add(topology); + logger.info("Returning topology for user interaction"); + + return solutionList; + } else if (unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) { + + // the topology is complete, return it to Winery + + logger.info("The topology is complete."); + + nodeTemplateUserInteraction = false; + solutionList.add(topology); + return solutionList; + } + } else { + // the one-step approach is chosen or the topology contains deferred-RelationshipTemplates + if (unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) { + // the topology does not contain any elements that have to completed, it can be defined as complete + if (solutions.isEmpty()) { + // no topology solutions found, topology could not be completed due to missing types. + // Return an empty list, an error message will be shown in Winery. + return new ArrayList<TTopologyTemplate>(); + } else { + // this topology is complete, set its boolean value in the map to true + for (Integer i : solutions.keySet()) { + for (TTopologyTemplate t : solutions.get(i).keySet()) { + if (t.equals(topology)) { + solutions.get(i).put(topology, true); + } + } + } + + // check if the map still contains any incomplete topologies. If this is the case, the recursion will continue. + // Otherwise the solutions map is returned. + if (!solutions.values().contains(false)) { + logger.info("The topology is complete."); + List<TTopologyTemplate> sol = new ArrayList<TTopologyTemplate>(); + + for (Integer i : solutions.keySet()) { + sol.addAll(solutions.get(i).keySet()); + } + return sol; + } + } + } else if (!unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) { + + logger.info("The topology contains Requirements, but no Place Holders."); + + // complete a topology containing Requirements in one step using the RequirementCompleter class + RequirementCompleter requirementCompleter = new RequirementCompleter(topology); + + List<TTopologyTemplate> completeTopology = requirementCompleter.completeRequirementTopology(unfulfilledRequirements, toscaAnalyzer); + + for (TTopologyTemplate topologySolution : completeTopology) { + Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>(); + topologyMap.put(topologySolution, false); + solutions.put(index, topologyMap); + } + + // complete all topology solutions recursively + for (TTopologyTemplate topologySolution : completeTopology) { + manageCompletion(topologySolution); + index++; + } + + } else if (unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty() || !unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty()) { + + logger.info("The topology contains one or more PlaceHolders."); + + // complete a topology containing place holders in one step using the PlaceHolderCompleter class + PlaceHolderCompleter placeHolderCompleter = new PlaceHolderCompleter(topology); + + List<TTopologyTemplate> completeTopology = placeHolderCompleter.completePlaceholderTopology(placeHolders, toscaAnalyzer); + + if (placeHolderCompleter.getUserInteraction()) { + choices = placeHolderCompleter.getChoices(); + userInteraction = true; + + // user interaction is necessary to choose a inserted Relationship Template, return the topology to winery + List<TTopologyTemplate> intermediateSolutions = new ArrayList<>(); + TRelationshipTemplate toBeRemoved = null; + for (TEntityTemplate entityTemplate : topology.getNodeTemplateOrRelationshipTemplate()) { + if (entityTemplate instanceof TRelationshipTemplate) { + TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) entityTemplate; + if (relationshipTemplate.getTargetElement().getRef().equals(placeHolderCompleter.getPlaceHolder())) { + toBeRemoved = relationshipTemplate; + } + } + } + + topology.getNodeTemplateOrRelationshipTemplate().remove(toBeRemoved); + topology.getNodeTemplateOrRelationshipTemplate().remove(placeHolderCompleter.getPlaceHolder()); + + intermediateSolutions.add(topology); + return intermediateSolutions; + } + + int i = 0; + + for (TTopologyTemplate topologySolution : completeTopology) { + Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>(); + topologyMap.put(topologySolution, false); + solutions.put(i, topologyMap); + i++; + } + + for (TTopologyTemplate topologySolution : completeTopology) { + manageCompletion(topologySolution); + } + } else if (!deferredRelations.isEmpty()) { + + logger.info("The topology contains deferred RelationshipTemplates."); + + // complete a topology containing deferred Relationship Templates in one step using the DeferredCompleter class + DeferredCompleter deferredCompleter = new DeferredCompleter(topology); + List<TTopologyTemplate> completeTopology = deferredCompleter.completeDeferredTopology(deferredRelations.get(0), toscaAnalyzer); + + int i = 0; + for (TTopologyTemplate solutionTemplate : completeTopology) { + Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>(); + topologyMap.put(solutionTemplate, false); + solutions.put(i, topologyMap); + i++; + } + + for (TTopologyTemplate topologySolution : completeTopology) { + manageCompletion(topologySolution); + } + } + List<TTopologyTemplate> sol = new ArrayList<TTopologyTemplate>(); + for (Integer i : solutions.keySet()) { + sol.addAll(solutions.get(i).keySet()); + } + return sol; + } + + return new ArrayList<TTopologyTemplate>(); + } + + /** + * Returns whether an user interaction is necessary or not + * + * @return the field userInteraction + */ + public boolean getUserInteraction() { + return userInteraction; + } + + /** + * The possible {@link TRelationshipTemplate} choices + * + * @return the field choices + */ + public List<TEntityTemplate> getChoices() { + return choices; + } + + /** + * A map of {@link TNodeTemplate}s and {@link TRelationshipTemplate}s when completing a topology step by step + * + * @return the field nodeTemplateChoices + */ + public Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> getTemplateChoices() { + return templateChoices; + } + + /** + * Returns whether user interaction by choosing {@link TNodeTemplate}s and {@link TRelationshipTemplate}s is necessary or not + * + * @return the field nodeTemplateUserInteraction + */ + public boolean getNodeTemplateUserInteraction() { + return nodeTemplateUserInteraction; + } + +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/DeferredCompleter.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/DeferredCompleter.java new file mode 100644 index 0000000..8bdf01e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/DeferredCompleter.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TCapability; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TRequirementType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.NodeTemplateConnector; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Utils; + +/** + * This class serves the completion of a topology containing Deferred {@link TRelationshipTemplate}s. + */ +public class DeferredCompleter { + + /** + * The TOSCA {@link TTopologyTemplate} document + */ + TTopologyTemplate topology; + + /** + * A Map containing the requirements removed during the algorithm and their corresponding {@link TNodeTemplate}. + */ + Map<TRequirement, TNodeTemplate> removedRequirements; + + /** + * Constructor of the class. + * + * @param topology + * the {@link TTopologyTemplate} to be completed + */ + public DeferredCompleter(TTopologyTemplate topology) { + this.topology = topology; + removedRequirements = new HashMap<TRequirement, TNodeTemplate>(); + } + + /** + * Completes a {@link TTopologyTemplate} that contains deferred {@link TRelationshipTemplate}s with a depth search algorithm. A deferred {@link TRelationshipTemplate} serves as place holder for a + * number of {@link TNodeTemplate}s and {@link TRelationshipTemplate}s. + * + * @param deferredRelation + * all found deferred {@link TRelationshipTemplate}s in the topology + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return the completed topology + */ + public List<TTopologyTemplate> completeDeferredTopology(TRelationshipTemplate deferredRelation, TOSCAAnalyzer toscaAnalyzer) { + + List<TTopologyTemplate> solutions = new ArrayList<TTopologyTemplate>(); + + TNodeTemplate source = (TNodeTemplate) deferredRelation.getSourceElement().getRef(); + TNodeTemplate target = (TNodeTemplate) deferredRelation.getTargetElement().getRef(); + + // TODO Remove this "if clause" after the Provisioning-API is implemented. At the moment Deferred RelationshipTemplates can't be completed + // without the existence of Requirements + if (source.getRequirements() != null && !source.getRequirements().getRequirement().isEmpty()) { + topology.getNodeTemplateOrRelationshipTemplate().remove(deferredRelation); + runDepthFirstSearch(source, target, new ArrayList<TEntityTemplate>(), solutions, toscaAnalyzer); + } + + /** + * Note: This code adds Requirements to NodeTemplates that has been removed during the algorithm but could not + * be used to replace the Deferred-RelationshipTemplates. If this step is not done, requirements could get lost. + * + * Therefore all removed Requirements are checked for fulfillment in the topology. If they have not been fulfilled + * they are re-added to the topology. + */ + Set<TRequirement> keySet = removedRequirements.keySet(); + + for (TTopologyTemplate topologyTemplate: solutions) { + boolean fulfilled = false; + for (TRequirement requirement: keySet) { + for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) entity; + if (nodeTemplate.getCapabilities() != null) { + for (TCapability capability: nodeTemplate.getCapabilities().getCapability()) { + String reqCapaType = ""; + for (TRequirementType reqType: toscaAnalyzer.getRequirementTypes()) { + if (reqType.getName().equals(requirement.getType().getLocalPart())) { + reqCapaType = reqType.getRequiredCapabilityType().getLocalPart(); + } + } + if (capability.getName().equals(reqCapaType)) { + fulfilled = true; + } + } + } + } + } + if (!fulfilled) { + for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) { + if (entity.equals(removedRequirements.get(requirement))) { + TNodeTemplate foundNT = (TNodeTemplate) entity; + foundNT.getRequirements().getRequirement().add(requirement); + } + } + } + } + } + + return solutions; + } + + /** + * Runs a recursive depth search to find the path to the target NodeTemplate. + * + * @param source + * the source node of a given {@link TRelationshipTemplate} + * @param target + * the target node of a given {@link TRelationshipTemplate} + * @param path + * the current path to the target (can be incomplete) + * @param solutions + * list containing all possible solutions of the completion + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return the path to the target NodeTemplate + */ + private void runDepthFirstSearch(TNodeTemplate source, TNodeTemplate target, List<TEntityTemplate> path, List<TTopologyTemplate> solutions, TOSCAAnalyzer toscaAnalyzer) { + + List<TNodeType> matchingNodeTypes = new ArrayList<TNodeType>(); + + if (source.getRequirements() != null) { + + List<TRequirement> requirementsOfTemplate = new ArrayList<>(); + for (TRequirement requirement : source.getRequirements().getRequirement()) { + requirementsOfTemplate.add(requirement); + } + + for (TRequirement requirement : requirementsOfTemplate) { + + // save the requirement to a list to avoid losing requirements (see line 83) + TRequirement sourceRequirement = new TRequirement(); + sourceRequirement.setId(requirement.getId()); + sourceRequirement.setName(requirement.getName()); + sourceRequirement.setType(requirement.getType()); + + // Remember the removed requirements. In case a requirement + // can't be used for completing the deferred RelationshipTemplate it has to be re-added to the topology. + removedRequirements.put(sourceRequirement, source); + + // search for matching NodeTypes for the requirement + matchingNodeTypes.addAll(Utils.matchRequirementAndCapability(requirement, toscaAnalyzer)); + + // remove the requirement so it is not handled again during the algorithm + source.getRequirements().getRequirement().remove(requirement); + } + } + for (TNodeType match : matchingNodeTypes) { + + if (match.getName().equals(target.getType().getLocalPart()) && match.getTargetNamespace().equals(target.getType().getNamespaceURI())) { + // the search was successful connect the target + List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(source, target, toscaAnalyzer, null); + + for (TRelationshipType rt : suitableRTs) { + TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, source, target); + path.add(relationship); + } + + TTopologyTemplate possiblePath = new TTopologyTemplate(); + possiblePath.getNodeTemplateOrRelationshipTemplate().addAll(topology.getNodeTemplateOrRelationshipTemplate()); + + // add the path to the topology + for (TEntityTemplate pathTemplate : path) { + possiblePath.getNodeTemplateOrRelationshipTemplate().add(pathTemplate); + } + + possiblePath.getNodeTemplateOrRelationshipTemplate().remove(target); + + // this is no good style, however the target has to be the last item in the list for a proper stack layouting + possiblePath.getNodeTemplateOrRelationshipTemplate().add(target); + solutions.add(possiblePath); + path.clear(); + } else { + + // the end of the path is not reached, add the found NodeTemplate and continue the depth search + TNodeTemplate instantiatedNodeTemplate = ModelUtilities.instantiateNodeTemplate(match); + + List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(source, instantiatedNodeTemplate, toscaAnalyzer, null); + + for (TRelationshipType rt : suitableRTs) { + TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, source, instantiatedNodeTemplate); + path.add(relationship); + } + path.add(instantiatedNodeTemplate); + runDepthFirstSearch(instantiatedNodeTemplate, target, path, solutions, toscaAnalyzer); + + } + } + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/PlaceHolderCompleter.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/PlaceHolderCompleter.java new file mode 100644 index 0000000..e76d897 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/PlaceHolderCompleter.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.NodeTemplateConnector; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.placeholderhandling.PlaceHolderHandler; + +/** + * This class completes a {@link TTopologyTemplate} containing place holders. + */ +public class PlaceHolderCompleter { + + /** + * The {@link TTopologyTemplate} to be completed + */ + TTopologyTemplate topology; + + /** + * List containing user choices for {@link TRelationshipTemplate}s + */ + List<TEntityTemplate> choices; + + /** + * Whether an user interaction is necessary or not + */ + boolean userInteraction; + + /** + * The last inserted place holder + */ + TNodeTemplate placeHolder; + + /** + * The constructor of the class PlaceHolderCompleter. + * + * @param topology + * the {@link TTopologyTemplate} to be completed + */ + public PlaceHolderCompleter(TTopologyTemplate topology) { + this.topology = topology; + userInteraction = false; + } + + /** + * This method completes a {@link TTopologyTemplate} containing place holders. + * + * @param placeHolders + * the contained place holders + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return the complete {@link TTopologyTemplate} + */ + public List<TTopologyTemplate> completePlaceholderTopology(List<TNodeTemplate> placeHolders, TOSCAAnalyzer toscaAnalyzer) { + + List<TTopologyTemplate> solutions = new ArrayList<TTopologyTemplate>(); + + for (TNodeTemplate placeHolder : placeHolders) { + + List<TNodeType> suitableNodeTypes = PlaceHolderHandler.getSuitableNodeTypes(placeHolder, toscaAnalyzer); + + // if there are more than one solution for an inserted NodeTemplate, + // create copies of the topology. The user can choose from them after the completion. + TTopologyTemplate topologyCopy = null; + + for (TNodeType suitableNodeType : suitableNodeTypes) { + topologyCopy = new TTopologyTemplate(); + topologyCopy.getNodeTemplateOrRelationshipTemplate().addAll(topology.getNodeTemplateOrRelationshipTemplate()); + + TNodeTemplate nodeTemplate = ModelUtilities.instantiateNodeTemplate(suitableNodeType); + + List<TNodeTemplate> sourceTemplates = new ArrayList<>(); + + // contains RelationshipTemplates connecting to a place holder. + // These Templates are generic and have to be replaced with + // concrete ones. + List<TRelationshipTemplate> placeholderConnections = new ArrayList<>(); + + TRelationshipTemplate foundTarget = null; + for (TEntityTemplate entity : topology.getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TRelationshipTemplate) { + TRelationshipTemplate rt = (TRelationshipTemplate) entity; + if (((TNodeTemplate) rt.getTargetElement().getRef()).getId().equals(placeHolder.getId())) { + TRelationshipTemplate placeHolderConnection = (TRelationshipTemplate) entity; + placeholderConnections.add(placeHolderConnection); + sourceTemplates.add((TNodeTemplate) placeHolderConnection.getSourceElement().getRef()); + } else if (((TNodeTemplate) rt.getSourceElement().getRef()).getId().equals(placeHolder.getId())) { + foundTarget = (TRelationshipTemplate) entity; + } + } + } + + // collect all possible RelationshipTemplates that can be used to connect to the placeholder + choices = new ArrayList<>(); + + for (TNodeTemplate sourceTemplate : sourceTemplates) { + // find matching RelationshipTypes to connect the Node Templates + List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(sourceTemplate, nodeTemplate, toscaAnalyzer, null); + for (TRelationshipType rt : suitableRTs) { + TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, sourceTemplate, nodeTemplate); + choices.add(relationship); + } + } + + // set the source elements of the RelationshipTemplates connecting from the replaced placeholder to other NodeTemplates + for (TEntityTemplate entityTemplate : topologyCopy.getNodeTemplateOrRelationshipTemplate()) { + if (entityTemplate instanceof TRelationshipTemplate) { + TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) entityTemplate; + if (relationshipTemplate.equals(foundTarget)) { + foundTarget.getSourceElement().setRef(nodeTemplate); + } + } + } + + // remove the generic connections to the place holder + topologyCopy.getNodeTemplateOrRelationshipTemplate().removeAll(placeholderConnections); + + // there are more than one possible Relationship Templates to connect to the inserted NodeTemplate(s), so + // interrupt the completion and ask the user which one to insert + if (choices.size() > 1 && sourceTemplates.size() == 1) { + + choices.add(sourceTemplates.get(0)); + choices.add(nodeTemplate); + topologyCopy.getNodeTemplateOrRelationshipTemplate().remove(placeHolder); + + userInteraction = true; + this.placeHolder = placeHolder; + break; + } else if (choices.size() == 1 || sourceTemplates.size() > 1) { + // replace the place holder with an actual NodeTemplate + topologyCopy.getNodeTemplateOrRelationshipTemplate().addAll(choices); + topologyCopy.getNodeTemplateOrRelationshipTemplate().add(nodeTemplate); + topologyCopy.getNodeTemplateOrRelationshipTemplate().remove(placeHolder); + } + solutions.add(topologyCopy); + } + } + return solutions; + } + + /** + * Returns the replaced place holder. + * + * @return the place holder + */ + public TNodeTemplate getPlaceHolder() { + return placeHolder; + } + + /** + * Returns whether an user interaction is necessary or not. + * + * @return the field userInteraction + */ + public boolean getUserInteraction() { + return userInteraction; + } + + /** + * Possible Relationship Template choices. + * + * @return the field choices + */ + public List<TEntityTemplate> getChoices() { + return choices; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/RequirementCompleter.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/RequirementCompleter.java new file mode 100644 index 0000000..b2e7c75 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/RequirementCompleter.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.NodeTemplateConnector; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Utils; + +public class RequirementCompleter { + + /** + * The TOSCA {@link TTopologyTemplate} document. + */ + TTopologyTemplate topology; + + /** + * The constructor the class. + * + * @param topology + * the topology to be completed + */ + public RequirementCompleter(TTopologyTemplate topology) { + this.topology = topology; + } + + /** + * This method completes a topology containing {@link TRequirement}s in one step (without user interaction). + * + * @param unfulfilledRequirements + * all the unfulfilled requirements that has been found in the topology + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + * + * @return the complete topology + */ + public List<TTopologyTemplate> completeRequirementTopology(Map<TRequirement, TNodeTemplate> unfulfilledRequirements, TOSCAAnalyzer toscaAnalyzer) { + + List<TTopologyTemplate> solutions = new ArrayList<TTopologyTemplate>(); + + Set<TRequirement> requirements = unfulfilledRequirements.keySet(); + + TNodeTemplate instantiatedNodeTemplate = null; + + // fulfill the Requirements + for (TRequirement requirement : requirements) { + + // remove the requirement from the NodeTemplate + TNodeTemplate requirementTemplate = unfulfilledRequirements.get(requirement); + for (TEntityTemplate element : topology.getNodeTemplateOrRelationshipTemplate()) { + if (requirementTemplate.getId().equals(element.getId())) { + ((TNodeTemplate) element).getRequirements().getRequirement().remove(requirement); + } + } + + List<TNodeType> possibleNodeTypes = Utils.matchRequirementAndCapability(requirement, toscaAnalyzer); + + // create a NodeTemplate for every matching Type, insert it into the topology and create a topology copy for each possible inserted NodeTemplate + TTopologyTemplate topologyCopy = null; + for (TNodeType possibleType : possibleNodeTypes) { + + topologyCopy = new TTopologyTemplate(); + topologyCopy.getNodeTemplateOrRelationshipTemplate().addAll(topology.getNodeTemplateOrRelationshipTemplate()); + + // instantiate the template + instantiatedNodeTemplate = ModelUtilities.instantiateNodeTemplate(possibleType); + topologyCopy.getNodeTemplateOrRelationshipTemplate().add(instantiatedNodeTemplate); + + TNodeTemplate correspondingNodeTemplate = unfulfilledRequirements.get(requirement); + + // find matching RelationshipTypes, instantiate RelationshipTemplates and connect the Node Templates + List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(correspondingNodeTemplate, instantiatedNodeTemplate, toscaAnalyzer, requirement); + for (TRelationshipType rt : suitableRTs) { + TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, correspondingNodeTemplate, instantiatedNodeTemplate); + topologyCopy.getNodeTemplateOrRelationshipTemplate().add(relationship); + } + + solutions.add(topologyCopy); + } + if (solutions.size() > 1) { + break; + } + } + return solutions; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/StepByStepCompleter.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/StepByStepCompleter.java new file mode 100644 index 0000000..b8cc745 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/StepByStepCompleter.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.winery.common.ModelUtilities; +import org.eclipse.winery.model.tosca.TEntityTemplate; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TNodeType; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TRelationshipType; +import org.eclipse.winery.model.tosca.TRequirement; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.NodeTemplateConnector; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Utils; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.placeholderhandling.PlaceHolderHandler; + +/** + * This class handles topologies that are completed step by step + */ +public class StepByStepCompleter { + + /** + * the topology to be completed + */ + TTopologyTemplate topology; + + /** + * the Node and RelationshipTemplates chosen by the user in every step + */ + Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> templateChoices; + + /** + * the last inserted place holder to be deleted + */ + private TNodeTemplate placeHolder; + + /** + * The constructor of the class. + * + * @param topology + * the {@link TTopologyTemplate} to be completed + */ + public StepByStepCompleter(TTopologyTemplate topology) { + this.topology = topology; + } + + /** + * This method is called when a topology containing {@link TRequirement}s is completed step by step. + * + * @param unfulfilledRequirements + * a list of unfulfilled requirements + * @param placeHolders + * a list of place holders to be fulfilled + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model + */ + public void completeTopologyStepByStep(Map<TRequirement, TNodeTemplate> unfulfilledRequirements, TOSCAAnalyzer toscaAnalyzer) { + + Set<TRequirement> requirements = unfulfilledRequirements.keySet(); + + TNodeTemplate nodeTemplate = null; + + for (TRequirement requirement : requirements) { + // remove the requirement from the NodeTemplate + TNodeTemplate requirementTemplate = unfulfilledRequirements.get(requirement); + for (TEntityTemplate element : topology.getNodeTemplateOrRelationshipTemplate()) { + if (requirementTemplate.getId().equals(element.getId())) { + ((TNodeTemplate) element).getRequirements().getRequirement().remove(requirement); + } + } + + List<TNodeType> possibleNodeTypes = Utils.matchRequirementAndCapability(requirement, toscaAnalyzer); + + // create a NodeTemplate for each matching node type + List<TNodeTemplate> possibleTemplates = new ArrayList<>(); + for (TNodeType possibleType : possibleNodeTypes) { + nodeTemplate = ModelUtilities.instantiateNodeTemplate(possibleType); + possibleTemplates.add(nodeTemplate); + } + + TNodeTemplate correspondingNodeTemplate = unfulfilledRequirements.get(requirement); + + Map<TNodeTemplate, List<TEntityTemplate>> entityTemplates = new HashMap<>(); + + // add all possible choices to a list and return it to the user + for (TNodeTemplate possibleTemplate : possibleTemplates) { + List<TEntityTemplate> choices = new ArrayList<TEntityTemplate>(); + List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(correspondingNodeTemplate, possibleTemplate, toscaAnalyzer, requirement); + for (TRelationshipType rt : suitableRTs) { + TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, correspondingNodeTemplate, possibleTemplate); + choices.add(relationship); + } + entityTemplates.put(possibleTemplate, choices); + } + + templateChoices = new HashMap<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>>(); + templateChoices.put(correspondingNodeTemplate, entityTemplates); + + // let the user decide which template shall be inserted + break; + } + + } + + /** + * Completes a place holder {@link TTopologyTemplate} step by step. + * + * @param placeHolders + * the place holders of the topology + * @param toscaAnalyzer + * the {@link TOSCAAnalyzer} object to access the data model. + * @return the generic {@link TRelationshipTemplate} which connects to the place holder. + */ + public TRelationshipTemplate completeWildcardTopologyStepByStep(List<TNodeTemplate> placeHolders, TOSCAAnalyzer toscaAnalyzer) { + + // take the first place holder, the order doesn't matter in the step by step approach + TNodeTemplate placeHolder = placeHolders.get(0); + + // get suitable NodeTypes for a placeholder and instantiate NodeTemplates + List<TNodeType> suitableNodeTypes = PlaceHolderHandler.getSuitableNodeTypes(placeHolder, toscaAnalyzer); + List<TNodeTemplate> suitableNodeTemplates = new ArrayList<TNodeTemplate>(); + for (TNodeType suitableNodeType : suitableNodeTypes) { + TNodeTemplate nodeTemplate = ModelUtilities.instantiateNodeTemplate(suitableNodeType); + suitableNodeTemplates.add(nodeTemplate); + } + + /** + * map containing the choices for the user selection + */ + Map<TNodeTemplate, List<TEntityTemplate>> entityTemplates = new HashMap<>(); + + TNodeTemplate sourceTemplate = null; + + // the RelationshipTemplate connecting to the placeholder + TRelationshipTemplate connectingRelationshipTemplate = null; + + for (TEntityTemplate entity : topology.getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TRelationshipTemplate) { + TRelationshipTemplate rt = (TRelationshipTemplate) entity; + if (((TNodeTemplate) rt.getTargetElement().getRef()).getId().equals(placeHolder.getId())) { + connectingRelationshipTemplate = (TRelationshipTemplate) entity; + sourceTemplate = (TNodeTemplate) connectingRelationshipTemplate.getSourceElement().getRef(); + } + } + } + + for (TNodeTemplate nodeTemplate : suitableNodeTemplates) { + + List<TEntityTemplate> choices = new ArrayList<>(); + + // find matching RelationshipTypes to connect the Node Templates + List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(sourceTemplate, nodeTemplate, toscaAnalyzer, null); + for (TRelationshipType rt : suitableRTs) { + TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, sourceTemplate, nodeTemplate); + choices.add(relationship); + } + entityTemplates.put(nodeTemplate, choices); + } + + templateChoices = new HashMap<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>>(); + templateChoices.put(sourceTemplate, entityTemplates); + + this.placeHolder = placeHolder; + + return connectingRelationshipTemplate; + + } + + /** + * Returns a map containing the choices for the user selection when the topology is completed step by step. + * + * @return the field ntChoices + */ + public Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> getTemplateChoices() { + return templateChoices; + } + + /** + * Returns the replaced place holder to remove it from the topology. + * + * @return the place holder + */ + public TNodeTemplate getPlaceHolder() { + return placeHolder; + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/package-info.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/package-info.java new file mode 100644 index 0000000..8a097d5 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/completer/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This package contains classes and methods to actually execute the completion for several use cases. + */ +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer; + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/package-info.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/package-info.java new file mode 100644 index 0000000..bdaf170 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/addons/topologycompleter/topologycompletion/package-info.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This package contains classes and methods to execute and manage the completion. + */ +package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion; + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/resources/TopologyCompletionResource.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/resources/TopologyCompletionResource.java new file mode 100644 index 0000000..efc36e3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/resources/TopologyCompletionResource.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +package org.eclipse.winery.topologymodeler.resources; + +import java.io.StringReader; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.eclipse.winery.model.tosca.Definitions; +import org.eclipse.winery.model.tosca.TNodeTemplate; +import org.eclipse.winery.model.tosca.TRelationshipTemplate; +import org.eclipse.winery.model.tosca.TServiceTemplate; +import org.eclipse.winery.model.tosca.TTopologyTemplate; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.JAXBHelper; +import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.RESTHelper; + +/** + * This class contains resources used for the topology completion. + * + */ +@Path("/") +public class TopologyCompletionResource { + + /** + * Adds selected {@link TNodeTemplate}s and {@link TRelationshipTemplate}s + * to a topology. + * + * @param topology + * the {@link TTopologyTemplate} as XML string + * @param allChoices + * all possible choices as XML + * @param selectedNodeTemplates + * the selected {@link TNodeTemplate}s as JSON array + * @param selectedRelationshipTemplates + * the selected {@link TRelationshipTemplate}s as JSON array + * @return the enhanced {@link TTopologyTemplate} + */ + @Path("selectionhandler/") + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response handleSelection( + @QueryParam(value = "topology") String topology, + @QueryParam(value = "allChoices") String allChoices, + @QueryParam(value = "selectedNodeTemplates") String selectedNodeTemplates, + @QueryParam(value = "selectedRelationshipTemplates") String selectedRelationshipTemplates) { + return Response + .ok() + .entity(JAXBHelper.addTemplatesToTopology(topology, allChoices, + selectedNodeTemplates, selectedRelationshipTemplates)) + .build(); + } + + /** + * This resource is used to save a {@link TTopologyTemplate} to the repository. + * + * @param topology + * the topology to be saved + * @param templateURL + * the URL the {@link TTopologyTemplate} of the topology template + * @param repositoryURL + * the URL of the repository + * @param topologyName + * the name of the saved {@link TTopologyTemplate} + * @param topologyNamespace + * the namespace of the saved {@link TTopologyTemplate} + * @param overwriteTopology + * whether the {@link TTopologyTemplate} should be overwritten or not + * + * @return whether the save operation has been successful or not + */ + @Path("topologysaver/") + @POST + public Response saveTopology(@FormParam("topology") String topology, + @FormParam(value = "templateURL") String templateURL, + @FormParam(value = "repositoryURL") String repositoryURL, + @FormParam(value = "topologyName") String topologyName, + @FormParam(value = "topologyNamespace") String topologyNamespace, + @FormParam(value = "overwriteTopology") String overwriteTopology) { + try { + + boolean overwrite = Boolean.parseBoolean(overwriteTopology); + + // initiate JaxB context + JAXBContext context; + context = JAXBContext.newInstance(Definitions.class); + StringReader reader = new StringReader(topology); + + // unmarshall the topology XML string + Unmarshaller um; + + um = context.createUnmarshaller(); + + Definitions jaxBDefinitions = (Definitions) um.unmarshal(reader); + TServiceTemplate st = (TServiceTemplate) jaxBDefinitions + .getServiceTemplateOrNodeTypeOrNodeTypeImplementation() + .get(0); + TTopologyTemplate toBeSaved = st.getTopologyTemplate(); + + // depending on the selected save method (overwrite or create new) + // the save method is called + if (overwrite) { + RESTHelper.saveCompleteTopology(toBeSaved, templateURL, true, + "", "", repositoryURL); + } else { + RESTHelper.saveCompleteTopology(toBeSaved, templateURL, false, + topologyName, topologyNamespace, repositoryURL); + } + + return Response.ok().build(); + + } catch (JAXBException e) { + e.printStackTrace(); + return Response.serverError().build(); + } + } +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/resources/package-info.java b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/resources/package-info.java new file mode 100644 index 0000000..a06da46 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/java/org/eclipse/winery/topologymodeler/resources/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the resources of the topology modeler + */ +package org.eclipse.winery.topologymodeler.resources;
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/resources/.gitignore b/winery/org.eclipse.winery.topologymodeler/src/main/resources/.gitignore new file mode 100644 index 0000000..17ae84b --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/resources/.gitignore @@ -0,0 +1 @@ +rebel.xml diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.js new file mode 100644 index 0000000..6eccbfe --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.js @@ -0,0 +1,14987 @@ +/*! jQuery UI - v1.10.2 - 2013-03-14 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ +(function( $, undefined ) { + +var uuid = 0, + runiqueId = /^ui-id-\d+$/; + +// $.ui might exist from components with no dependencies, e.g., $.ui.position +$.ui = $.ui || {}; + +$.extend( $.ui, { + version: "1.10.2", + + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 + } +}); + +// plugins +$.fn.extend({ + focus: (function( orig ) { + return function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + orig.apply( this, arguments ); + }; + })( $.fn.focus ), + + scrollParent: function() { + var scrollParent; + if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); + }).eq(0); + } + + return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; + }, + + zIndex: function( zIndex ) { + if ( zIndex !== undefined ) { + return this.css( "zIndex", zIndex ); + } + + if ( this.length ) { + var elem = $( this[ 0 ] ), position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> + value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + }, + + uniqueId: function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + (++uuid); + } + }); + }, + + removeUniqueId: function() { + return this.each(function() { + if ( runiqueId.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + }); + } +}); + +// selectors +function focusable( element, isTabIndexNotNaN ) { + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap=#" + mapName + "]" )[0]; + return !!img && visible( img ); + } + return ( /input|select|textarea|button|object/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible( element ); +} + +function visible( element ) { + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; +} + +$.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + isTabIndexNaN = isNaN( tabIndex ); + return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); + } +}); + +// support: jQuery <1.8 +if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; + }); +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} + + + + + +// deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.support.selectstart = "onselectstart" in document.createElement( "div" ); +$.fn.extend({ + disableSelection: function() { + return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }, + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + } +}); + +$.extend( $.ui, { + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args ) { + var i, + set = instance.plugins[ name ]; + if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } + }, + + // only used by resizable + hasScroll: function( el, a ) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ( $( el ).css( "overflow" ) === "hidden") { + return false; + } + + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", + has = false; + + if ( el[ scroll ] > 0 ) { + return true; + } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[ scroll ] = 1; + has = ( el[ scroll ] > 0 ); + el[ scroll ] = 0; + return has; + } +}); + +})( jQuery ); + +(function( $, undefined ) { + +var uuid = 0, + slice = Array.prototype.slice, + _cleanData = $.cleanData; +$.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); +}; + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); +}; + +$.widget.extend = function( target ) { + var input = slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.widget.extend.apply( null, [ options ].concat(args) ) : + options; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} )._init(); + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "<div>", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( value === undefined ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( value === undefined ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +})( jQuery ); + +(function( $, undefined ) { + +var mouseHandled = false; +$( document ).mouseup( function() { + mouseHandled = false; +}); + +$.widget("ui.mouse", { + version: "1.10.2", + options: { + cancel: "input,textarea,button,select,option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .bind("mousedown."+this.widgetName, function(event) { + return that._mouseDown(event); + }) + .bind("click."+this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); + event.stopImmediatePropagation(); + return false; + } + }); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind("."+this.widgetName); + if ( this._mouseMoveDelegate ) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + } + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + if( mouseHandled ) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = (event.which === 1), + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + that.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return that._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return that._mouseUp(event); + }; + $(document) + .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .bind("mouseup."+this.widgetName, this._mouseUpDelegate); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); + } + + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(/* event */) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } +}); + +})(jQuery); + +(function( $, undefined ) { + +$.widget("ui.draggable", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "drag", + options: { + addClasses: true, + appendTo: "parent", + axis: false, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null + }, + _create: function() { + + if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { + this.element[0].style.position = "relative"; + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } + + this._mouseInit(); + + }, + + _destroy: function() { + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + + var o = this.options; + + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { + return false; + } + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) { + return false; + } + + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>") + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + + return true; + + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + this.helper.addClass("ui-draggable-dragging"); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css("position"); + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.positionAbs = this.element.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this.position = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + //Trigger event + callbacks + if(this._trigger("start", event) === false) { + this._clear(); + return false; + } + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } + + return true; + }, + + _mouseDrag: function(event, noPropagation) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + if(this._trigger("drag", event, ui) === false) { + this._mouseUp({}); + return false; + } + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var element, + that = this, + elementInDom = false, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { + dropped = $.ui.ddmanager.drop(this, event); + } + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + //if the original element is no longer in the DOM don't bother to continue (see #8269) + element = this.element[0]; + while ( element && (element = element.parentNode) ) { + if (element === document ) { + elementInDom = true; + } + } + if ( !elementInDom && this.options.helper === "original" ) { + return false; + } + + if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + if(that._trigger("stop", event) !== false) { + that._clear(); + } + }); + } else { + if(this._trigger("stop", event) !== false) { + this._clear(); + } + } + + return false; + }, + + _mouseUp: function(event) { + //Remove frame helpers + $("div.ui-draggable-iframeFix").each(function() { + this.parentNode.removeChild(this); + }); + + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) + if( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } + + return $.ui.mouse.prototype._mouseUp.call(this, event); + }, + + cancel: function() { + + if(this.helper.is(".ui-draggable-dragging")) { + this._mouseUp({}); + } else { + this._clear(); + } + + return this; + + }, + + _getHandle: function(event) { + return this.options.handle ? + !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : + true; + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); + + if(!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } + + if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { + helper.css("position", "absolute"); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + //This needs to be actually done for all browsers, since pageX/pageY includes this information + //Ugly IE fix + if((this.offsetParent[0] === document.body) || + (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0), + right: (parseInt(this.element.css("marginRight"),10) || 0), + bottom: (parseInt(this.element.css("marginBottom"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var over, c, ce, + o = this.options; + + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + o.containment === "document" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + o.containment === "document" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, + (o.containment === "document" ? 0 : $(window).scrollLeft()) + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + (o.containment === "document" ? 0 : $(window).scrollTop()) + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) { + c = $(o.containment); + ce = c[0]; + + if(!ce) { + return; + } + + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), + (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderRightWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, + (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderBottomWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom + ]; + this.relative_container = c; + + } else if(o.containment.constructor === Array) { + this.containment = o.containment; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var containment, co, top, left, + o = this.options, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName), + pageX = event.pageX, + pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + if(this.containment) { + if (this.relative_container){ + co = this.relative_container.offset(); + containment = [ this.containment[0] + co.left, + this.containment[1] + co.top, + this.containment[2] + co.left, + this.containment[3] + co.top ]; + } + else { + containment = this.containment; + } + + if(event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + //The absolute position has to be recalculated after plugins + if(type === "drag") { + this.positionAbs = this._convertPositionTo("absolute"); + } + return $.Widget.prototype._trigger.call(this, type, event, ui); + }, + + plugins: {}, + + _uiHash: function() { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs + }; + } + +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { + + var inst = $(this).data("ui-draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, "ui-sortable"); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). + sortable._trigger("activate", event, uiSortable); + } + }); + + }, + stop: function(event, ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("ui-draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + + this.instance.isOver = 0; + + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" + if(this.shouldRevert) { + this.instance.options.revert = this.shouldRevert; + } + + //Trigger the stop of the sortable + this.instance._mouseStop(event); + + this.instance.options.helper = this.instance.options._helper; + + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper === "original") { + this.instance.currentItem.css({ top: "auto", left: "auto" }); + } + + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } + + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("ui-draggable"), that = this; + + $.each(inst.sortables, function() { + + var innermostIntersecting = false, + thisSortable = this; + + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + + if(this.instance._intersectsWith(this.instance.containerCache)) { + innermostIntersecting = true; + $.each(inst.sortables, function () { + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + if (this !== thisSortable && + this.instance._intersectsWith(this.instance.containerCache) && + $.contains(thisSortable.instance.element[0], this.instance.element[0]) + ) { + innermostIntersecting = false; + } + return innermostIntersecting; + }); + } + + + if(innermostIntersecting) { + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) { + this.instance._mouseDrag(event); + } + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + + //Prevent reverting on this forced stop + this.instance.options.revert = false; + + // The out event needs to be triggered independently + this.instance._trigger("out", event, this.instance._uiHash(this.instance)); + + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) { + this.instance.placeholder.remove(); + } + + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } + + } + + }); + + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function() { + var t = $("body"), o = $(this).data("ui-draggable").options; + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } + t.css("cursor", o.cursor); + }, + stop: function() { + var o = $(this).data("ui-draggable").options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function() { + var i = $(this).data("ui-draggable"); + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + i.overflowOffset = i.scrollParent.offset(); + } + }, + drag: function( event ) { + + var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; + + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + + if(!o.axis || o.axis !== "x") { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } + } + + if(!o.axis || o.axis !== "y") { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } + } + + } else { + + if(!o.axis || o.axis !== "x") { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + } + + if(!o.axis || o.axis !== "y") { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(i, event); + } + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function() { + + var i = $(this).data("ui-draggable"), + o = i.options; + + i.snapElements = []; + + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if(this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } + }); + + }, + drag: function(event, ui) { + + var ts, bs, ls, rs, l, r, t, b, i, first, + inst = $(this).data("ui-draggable"), + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (i = inst.snapElements.length - 1; i >= 0; i--){ + + l = inst.snapElements[i].left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top; + b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + } + + first = (ts || bs || ls || rs); + + if(o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + } + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function() { + var min, + o = this.data("ui-draggable").options, + group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); + + if (!group.length) { return; } + + min = parseInt($(group[0]).css("zIndex"), 10) || 0; + $(group).each(function(i) { + $(this).css("zIndex", min + i); + }); + this.css("zIndex", (min + group.length)); + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } + } +}); + +})(jQuery); + +(function( $, undefined ) { + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +$.widget("ui.droppable", { + version: "1.10.2", + widgetEventPrefix: "drop", + options: { + accept: "*", + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null + }, + _create: function() { + + var o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; + + this.accept = $.isFunction(accept) ? accept : function(d) { + return d.is(accept); + }; + + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; + $.ui.ddmanager.droppables[o.scope].push(this); + + (o.addClasses && this.element.addClass("ui-droppable")); + + }, + + _destroy: function() { + var i = 0, + drop = $.ui.ddmanager.droppables[this.options.scope]; + + for ( ; i < drop.length; i++ ) { + if ( drop[i] === this ) { + drop.splice(i, 1); + } + } + + this.element.removeClass("ui-droppable ui-droppable-disabled"); + }, + + _setOption: function(key, value) { + + if(key === "accept") { + this.accept = $.isFunction(value) ? value : function(d) { + return d.is(value); + }; + } + $.Widget.prototype._setOption.apply(this, arguments); + }, + + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.addClass(this.options.activeClass); + } + if(draggable){ + this._trigger("activate", event, this.ui(draggable)); + } + }, + + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(draggable){ + this._trigger("deactivate", event, this.ui(draggable)); + } + }, + + _over: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.addClass(this.options.hoverClass); + } + this._trigger("over", event, this.ui(draggable)); + } + + }, + + _out: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("out", event, this.ui(draggable)); + } + + }, + + _drop: function(event,custom) { + + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return false; + } + + this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, "ui-droppable"); + if( + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && + $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + ) { childrenIntersection = true; return false; } + }); + if(childrenIntersection) { + return false; + } + + if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("drop", event, this.ui(draggable)); + return this.element; + } + + return false; + + }, + + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + } + +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) { + return false; + } + + var draggableLeft, draggableTop, + x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; + + switch (toleranceMode) { + case "fit": + return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); + case "intersect": + return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half + x2 - (draggable.helperProportions.width / 2) < r && // Left Half + t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half + y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + case "pointer": + draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); + return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); + case "touch": + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + default: + return false; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { "default": [] }, + prepareOffsets: function(t, event) { + + var i, j, + m = $.ui.ddmanager.droppables[t.options.scope] || [], + type = event ? event.type : null, // workaround for #2317 + list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); + + droppablesLoop: for (i = 0; i < m.length; i++) { + + //No disabled and non-accepted + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { + continue; + } + + // Filter out elements in the current dragged item + for (j=0; j < list.length; j++) { + if(list[j] === m[i].element[0]) { + m[i].proportions.height = 0; + continue droppablesLoop; + } + } + + m[i].visible = m[i].element.css("display") !== "none"; + if(!m[i].visible) { + continue; + } + + //Activate the droppable if used directly from draggables + if(type === "mousedown") { + m[i]._activate.call(m[i], event); + } + + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; + + } + + }, + drop: function(draggable, event) { + + var dropped = false; + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { + + if(!this.options) { + return; + } + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { + dropped = this._drop.call(this, event) || dropped; + } + + if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = true; + this.isover = false; + this._deactivate.call(this, event); + } + + }); + return dropped; + + }, + dragStart: function( draggable, event ) { + //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + }); + }, + drag: function(draggable, event) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) { + $.ui.ddmanager.prepareOffsets(draggable, event); + } + + //Run through all droppables and check their positions based on specific tolerance options + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) { + return; + } + + var parentInstance, scope, parent, + intersects = $.ui.intersect(draggable, this, this.options.tolerance), + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + if(!c) { + return; + } + + if (this.options.greedy) { + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents(":data(ui-droppable)").filter(function () { + return $.data(this, "ui-droppable").options.scope === scope; + }); + + if (parent.length) { + parentInstance = $.data(parent[0], "ui-droppable"); + parentInstance.greedyChild = (c === "isover"); + } + } + + // we just moved into a greedy child + if (parentInstance && c === "isover") { + parentInstance.isover = false; + parentInstance.isout = true; + parentInstance._out.call(parentInstance, event); + } + + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call(this, event); + + // we just moved out of a greedy child + if (parentInstance && c === "isout") { + parentInstance.isout = false; + parentInstance.isover = true; + parentInstance._over.call(parentInstance, event); + } + }); + + }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); + //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } +}; + +})(jQuery); + +(function( $, undefined ) { + +function num(v) { + return parseInt(v, 10) || 0; +} + +function isNumber(value) { + return !isNaN(parseInt(value, 10)); +} + +$.widget("ui.resizable", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "resize", + options: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + containment: false, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + // See #7960 + zIndex: 90, + + // callbacks + resize: null, + start: null, + stop: null + }, + _create: function() { + + var n, i, handle, axis, hname, + that = this, + o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null + }); + + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { + + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ + position: this.element.css("position"), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css("top"), + left: this.element.css("left") + }) + ); + + //Overwrite the original this.element + this.element = this.element.parent().data( + "ui-resizable", this.element.data("ui-resizable") + ); + + this.elementIsWrapper = true; + + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css("resize"); + this.originalElement.css("resize", "none"); + + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); + + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css("margin") }); + + // fix handlers offset + this._proportionallyResize(); + + } + + this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); + if(this.handles.constructor === String) { + + if ( this.handles === "all") { + this.handles = "n,e,s,w,se,sw,ne,nw"; + } + + n = this.handles.split(","); + this.handles = {}; + + for(i = 0; i < n.length; i++) { + + handle = $.trim(n[i]); + hname = "ui-resizable-"+handle; + axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); + + // Apply zIndex to all handles - see #7960 + axis.css({ zIndex: o.zIndex }); + + //TODO : What's going on here? + if ("se" === handle) { + axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); + } + + //Insert into internal handles object and append to element + this.handles[handle] = ".ui-resizable-"+handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + var i, axis, padPos, padWrapper; + + target = target || this.element; + + for(i in this.handles) { + + if(this.handles[i].constructor === String) { + this.handles[i] = $(this.handles[i], this.element).show(); + } + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + axis = $(this.handles[i], this.element); + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + padPos = [ "padding", + /ne|nw|n/.test(i) ? "Top" : + /se|sw|s/.test(i) ? "Bottom" : + /^e$/.test(i) ? "Right" : "Left" ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + + } + + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) { + continue; + } + } + }; + + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = $(".ui-resizable-handle", this.element) + .disableSelection(); + + //Matching axis name + this._handles.mouseover(function() { + if (!that.resizing) { + if (this.className) { + axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + } + //Axis, default = se + that.axis = axis && axis[1] ? axis[1] : "se"; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .mouseenter(function() { + if (o.disabled) { + return; + } + $(this).removeClass("ui-resizable-autohide"); + that._handles.show(); + }) + .mouseleave(function(){ + if (o.disabled) { + return; + } + if (!that.resizing) { + $(this).addClass("ui-resizable-autohide"); + that._handles.hide(); + } + }); + } + + //Initialize the mouse interaction + this._mouseInit(); + + }, + + _destroy: function() { + + this._mouseDestroy(); + + var wrapper, + _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + wrapper = this.element; + this.originalElement.css({ + position: wrapper.css("position"), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css("top"), + left: wrapper.css("left") + }).insertAfter( wrapper ); + wrapper.remove(); + } + + this.originalElement.css("resize", this.originalResizeStyle); + _destroy(this.originalElement); + + return this; + }, + + _mouseCapture: function(event) { + var i, handle, + capture = false; + + for (i in this.handles) { + handle = $(this.handles[i])[0]; + if (handle === event.target || $.contains(handle, event.target)) { + capture = true; + } + } + + return !this.options.disabled && capture; + }, + + _mouseStart: function(event) { + + var curleft, curtop, cursor, + o = this.options, + iniPos = this.element.position(), + el = this.element; + + this.resizing = true; + + // bugfix for http://dev.jquery.com/ticket/1749 + if ( (/absolute/).test( el.css("position") ) ) { + el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); + } else if (el.is(".ui-draggable")) { + el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); + } + + this._renderProxy(); + + curleft = num(this.helper.css("left")); + curtop = num(this.helper.css("top")); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + + cursor = $(".ui-resizable-" + this.axis).css("cursor"); + $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var data, + el = this.helper, props = {}, + smp = this.originalMousePosition, + a = this.axis, + prevTop = this.position.top, + prevLeft = this.position.left, + prevWidth = this.size.width, + prevHeight = this.size.height, + dx = (event.pageX-smp.left)||0, + dy = (event.pageY-smp.top)||0, + trigger = this._change[a]; + + if (!trigger) { + return false; + } + + // Calculate the attrs that will be change + data = trigger.apply(this, [event, dx, dy]); + + // Put this in the mouseDrag handler since the user can start pressing shift while resizing + this._updateVirtualBoundaries(event.shiftKey); + if (this._aspectRatio || event.shiftKey) { + data = this._updateRatio(data, event); + } + + data = this._respectSize(data, event); + + this._updateCache(data); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + if (this.position.top !== prevTop) { + props.top = this.position.top + "px"; + } + if (this.position.left !== prevLeft) { + props.left = this.position.left + "px"; + } + if (this.size.width !== prevWidth) { + props.width = this.size.width + "px"; + } + if (this.size.height !== prevHeight) { + props.height = this.size.height + "px"; + } + el.css(props); + + if (!this._helper && this._proportionallyResizeElements.length) { + this._proportionallyResize(); + } + + // Call the user callback if the element was resized + if ( ! $.isEmptyObject(props) ) { + this._trigger("resize", event, this.ui()); + } + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var pr, ista, soffseth, soffsetw, s, left, top, + o = this.options, that = this; + + if(this._helper) { + + pr = this._proportionallyResizeElements; + ista = pr.length && (/textarea/i).test(pr[0].nodeName); + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; + soffsetw = ista ? 0 : that.sizeDiff.width; + + s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) { + this.element.css($.extend(s, { top: top, left: left })); + } + + that.helper.height(that.size.height); + that.helper.width(that.size.width); + + if (this._helper && !o.animate) { + this._proportionallyResize(); + } + } + + $("body").css("cursor", "auto"); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) { + this.helper.remove(); + } + + return false; + + }, + + _updateVirtualBoundaries: function(forceAspectRatio) { + var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, + o = this.options; + + b = { + minWidth: isNumber(o.minWidth) ? o.minWidth : 0, + maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, + minHeight: isNumber(o.minHeight) ? o.minHeight : 0, + maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity + }; + + if(this._aspectRatio || forceAspectRatio) { + // We want to create an enclosing box whose aspect ration is the requested one + // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension + pMinWidth = b.minHeight * this.aspectRatio; + pMinHeight = b.minWidth / this.aspectRatio; + pMaxWidth = b.maxHeight * this.aspectRatio; + pMaxHeight = b.maxWidth / this.aspectRatio; + + if(pMinWidth > b.minWidth) { + b.minWidth = pMinWidth; + } + if(pMinHeight > b.minHeight) { + b.minHeight = pMinHeight; + } + if(pMaxWidth < b.maxWidth) { + b.maxWidth = pMaxWidth; + } + if(pMaxHeight < b.maxHeight) { + b.maxHeight = pMaxHeight; + } + } + this._vBoundaries = b; + }, + + _updateCache: function(data) { + this.offset = this.helper.offset(); + if (isNumber(data.left)) { + this.position.left = data.left; + } + if (isNumber(data.top)) { + this.position.top = data.top; + } + if (isNumber(data.height)) { + this.size.height = data.height; + } + if (isNumber(data.width)) { + this.size.width = data.width; + } + }, + + _updateRatio: function( data ) { + + var cpos = this.position, + csize = this.size, + a = this.axis; + + if (isNumber(data.height)) { + data.width = (data.height * this.aspectRatio); + } else if (isNumber(data.width)) { + data.height = (data.width / this.aspectRatio); + } + + if (a === "sw") { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a === "nw") { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function( data ) { + + var o = this._vBoundaries, + a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), + dw = this.originalPosition.left + this.originalSize.width, + dh = this.position.top + this.size.height, + cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + if (isminw) { + data.width = o.minWidth; + } + if (isminh) { + data.height = o.minHeight; + } + if (ismaxw) { + data.width = o.maxWidth; + } + if (ismaxh) { + data.height = o.maxHeight; + } + + if (isminw && cw) { + data.left = dw - o.minWidth; + } + if (ismaxw && cw) { + data.left = dw - o.maxWidth; + } + if (isminh && ch) { + data.top = dh - o.minHeight; + } + if (ismaxh && ch) { + data.top = dh - o.maxHeight; + } + + // fixing jump error on top/left - bug #2330 + if (!data.width && !data.height && !data.left && data.top) { + data.top = null; + } else if (!data.width && !data.height && !data.top && data.left) { + data.left = null; + } + + return data; + }, + + _proportionallyResize: function() { + + if (!this._proportionallyResizeElements.length) { + return; + } + + var i, j, borders, paddings, prel, + element = this.helper || this.element; + + for ( i=0; i < this._proportionallyResizeElements.length; i++) { + + prel = this._proportionallyResizeElements[i]; + + if (!this.borderDif) { + this.borderDif = []; + borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; + paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; + + for ( j = 0; j < borders.length; j++ ) { + this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); + } + } + + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); + + } + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(this._helper) { + + this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: "absolute", + left: this.elementOffset.left +"px", + top: this.elementOffset.top +"px", + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx) { + var cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n !== "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "animate", { + + stop: function( event ) { + var that = $(this).data("ui-resizable"), + o = that.options, + pr = that._proportionallyResizeElements, + ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width, + style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + that.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(that.element.css("width"), 10), + height: parseInt(that.element.css("height"), 10), + top: parseInt(that.element.css("top"), 10), + left: parseInt(that.element.css("left"), 10) + }; + + if (pr && pr.length) { + $(pr[0]).css({ width: data.width, height: data.height }); + } + + // propagating resize, and updating values for each animation step + that._updateCache(data); + that._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "containment", { + + start: function() { + var element, p, co, ch, cw, width, height, + that = $(this).data("ui-resizable"), + o = that.options, + el = that.element, + oc = o.containment, + ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + + if (!ce) { + return; + } + + that.containerElement = $(ce); + + if (/document/.test(oc) || oc === document) { + that.containerOffset = { left: 0, top: 0 }; + that.containerPosition = { left: 0, top: 0 }; + + that.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + // i'm a node, so compute top, left, right, bottom + else { + element = $(ce); + p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); + + that.containerOffset = element.offset(); + that.containerPosition = element.position(); + that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + co = that.containerOffset; + ch = that.containerSize.height; + cw = that.containerSize.width; + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); + height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + that.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function( event ) { + var woset, hoset, isParent, isOffsetRelative, + that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, + cop = { top:0, left:0 }, ce = that.containerElement; + + if (ce[0] !== document && (/static/).test(ce.css("position"))) { + cop = co; + } + + if (cp.left < (that._helper ? co.left : 0)) { + that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + that.position.left = o.helper ? co.left : 0; + } + + if (cp.top < (that._helper ? co.top : 0)) { + that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + that.position.top = that._helper ? co.top : 0; + } + + that.offset.left = that.parentData.left+that.position.left; + that.offset.top = that.parentData.top+that.position.top; + + woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); + hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); + + isParent = that.containerElement.get(0) === that.element.parent().get(0); + isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); + + if(isParent && isOffsetRelative) { + woset -= that.parentData.left; + } + + if (woset + that.size.width >= that.parentData.width) { + that.size.width = that.parentData.width - woset; + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + } + + if (hoset + that.size.height >= that.parentData.height) { + that.size.height = that.parentData.height - hoset; + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + } + }, + + stop: function(){ + var that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, + cop = that.containerPosition, + ce = that.containerElement, + helper = $(that.helper), + ho = helper.offset(), + w = helper.outerWidth() - that.sizeDiff.width, + h = helper.outerHeight() - that.sizeDiff.height; + + if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + } +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function () { + var that = $(this).data("ui-resizable"), + o = that.options, + _store = function (exp) { + $(exp).each(function() { + var el = $(this); + el.data("ui-resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) + }); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function (exp) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function (event, ui) { + var that = $(this).data("ui-resizable"), + o = that.options, + os = that.originalSize, + op = that.originalPosition, + delta = { + height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 + }, + + _alsoResize = function (exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, + css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; + + $.each(css, function (i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) { + style[prop] = sum || null; + } + }); + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function () { + $(this).removeData("resizable-alsoresize"); + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function() { + + var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; + + that.ghost = that.originalElement.clone(); + that.ghost + .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass("ui-resizable-ghost") + .addClass(typeof o.ghost === "string" ? o.ghost : ""); + + that.ghost.appendTo(that.helper); + + }, + + resize: function(){ + var that = $(this).data("ui-resizable"); + if (that.ghost) { + that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); + } + }, + + stop: function() { + var that = $(this).data("ui-resizable"); + if (that.ghost && that.helper) { + that.helper.get(0).removeChild(that.ghost.get(0)); + } + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function() { + var that = $(this).data("ui-resizable"), + o = that.options, + cs = that.size, + os = that.originalSize, + op = that.originalPosition, + a = that.axis, + grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, + gridX = (grid[0]||1), + gridY = (grid[1]||1), + ox = Math.round((cs.width - os.width) / gridX) * gridX, + oy = Math.round((cs.height - os.height) / gridY) * gridY, + newWidth = os.width + ox, + newHeight = os.height + oy, + isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), + isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), + isMinWidth = o.minWidth && (o.minWidth > newWidth), + isMinHeight = o.minHeight && (o.minHeight > newHeight); + + o.grid = grid; + + if (isMinWidth) { + newWidth = newWidth + gridX; + } + if (isMinHeight) { + newHeight = newHeight + gridY; + } + if (isMaxWidth) { + newWidth = newWidth - gridX; + } + if (isMaxHeight) { + newHeight = newHeight - gridY; + } + + if (/^(se|s|e)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + } else if (/^(ne)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + } else if (/^(sw)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.left = op.left - ox; + } else { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + that.position.left = op.left - ox; + } + } + +}); + +})(jQuery); + +(function( $, undefined ) { + +$.widget("ui.selectable", $.ui.mouse, { + version: "1.10.2", + options: { + appendTo: "body", + autoRefresh: true, + distance: 0, + filter: "*", + tolerance: "touch", + + // callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null + }, + _create: function() { + var selectees, + that = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + this.refresh = function() { + selectees = $(that.options.filter, that.element[0]); + selectees.addClass("ui-selectee"); + selectees.each(function() { + var $this = $(this), + pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass("ui-selected"), + selecting: $this.hasClass("ui-selecting"), + unselecting: $this.hasClass("ui-unselecting") + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $("<div class='ui-selectable-helper'></div>"); + }, + + _destroy: function() { + this.selectees + .removeClass("ui-selectee") + .removeData("selectable-item"); + this.element + .removeClass("ui-selectable ui-selectable-disabled"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var that = this, + options = this.options; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) { + return; + } + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "left": event.pageX, + "top": event.pageY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter(".ui-selected").each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey && !event.ctrlKey) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().addBack().each(function() { + var doSelect, + selectee = $.data(this, "selectable-item"); + if (selectee) { + doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); + selectee.$element + .removeClass(doSelect ? "ui-unselecting" : "ui-selected") + .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + // selectable (UN)SELECTING callback + if (doSelect) { + that._trigger("selecting", event, { + selecting: selectee.element + }); + } else { + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + return false; + } + }); + + }, + + _mouseDrag: function(event) { + + this.dragged = true; + + if (this.options.disabled) { + return; + } + + var tmp, + that = this, + options = this.options, + x1 = this.opos[0], + y1 = this.opos[1], + x2 = event.pageX, + y2 = event.pageY; + + if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"), + hit = false; + + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element === that.element[0]) { + return; + } + + if (options.tolerance === "touch") { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance === "fit") { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass("ui-selecting"); + selectee.selecting = true; + // selectable SELECTING callback + that._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if ((event.metaKey || event.ctrlKey) && selectee.startselected) { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + selectee.$element.addClass("ui-selected"); + selectee.selected = true; + } else { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var that = this; + + this.dragged = false; + + $(".ui-unselecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $(".ui-selecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +}); + +})(jQuery); + +(function( $, undefined ) { + +/*jshint loopfunc: true */ + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +function isFloating(item) { + return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); +} + +$.widget("ui.sortable", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "sort", + ready: false, + options: { + appendTo: "parent", + axis: false, + connectWith: false, + containment: false, + cursor: "auto", + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: "> *", + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000, + + // callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null + }, + _create: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are being displayed horizontally + this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + //We're ready to go + this.ready = true; + + }, + + _destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) { + this.items[i].item.removeData(this.widgetName + "-item"); + } + + return this; + }, + + _setOption: function(key, value){ + if ( key === "disabled" ) { + this.options[ key ] = value; + + this.widget().toggleClass( "ui-sortable-disabled", !!value ); + } else { + // Don't call widget base _setOption for disable as it adds ui-state-disabled class + $.Widget.prototype._setOption.apply(this, arguments); + } + }, + + _mouseCapture: function(event, overrideHandle) { + var currentItem = null, + validHandle = false, + that = this; + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type === "static") { + return false; + } + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + $(event.target).parents().each(function() { + if($.data(this, that.widgetName + "-item") === that) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, that.widgetName + "-item") === that) { + currentItem = $(event.target); + } + + if(!currentItem) { + return false; + } + if(this.options.handle && !overrideHandle) { + $(this.options.handle, currentItem).find("*").addBack().each(function() { + if(this === event.target) { + validHandle = true; + } + }); + if(!validHandle) { + return false; + } + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var i, body, + o = this.options; + + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] !== this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + if( o.cursor && o.cursor !== "auto" ) { // cursor option + body = this.document.find( "body" ); + + // support: IE + this.storedCursor = body.css( "cursor" ); + body.css( "cursor", o.cursor ); + + this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) { + this._storedOpacity = this.helper.css("opacity"); + } + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) { + this._storedZIndex = this.helper.css("zIndex"); + } + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + this.overflowOffset = this.scrollParent.offset(); + } + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) { + this._cacheHelperProportions(); + } + + + //Post "activate" events to possible containers + if( !noActivation ) { + for ( i = this.containers.length - 1; i >= 0; i-- ) { + this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); + } + } + + //Prepare possible droppables + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + var i, item, itemElement, intersection, + o = this.options, + scrolled = false; + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + + //Rearrange + for (i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } + + // Only put the placeholder inside the current Container, skip all + // items form other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this moving items in "sub-sortables" can cause the placeholder to jitter + // beetween the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } + + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection === 1 ? "down" : "up"; + + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + //Call callbacks + this._trigger("sort", event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) { + return; + } + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) { + $.ui.ddmanager.drop(this, event); + } + + if(this.options.revert) { + var that = this, + cur = this.placeholder.offset(), + axis = this.options.axis, + animation = {}; + + if ( !axis || axis === "x" ) { + animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); + } + if ( !axis || axis === "y" ) { + animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); + } + this.reverting = true; + $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { + that._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + if(this.dragging) { + + this._mouseUp({ target: null }); + + if(this.options.helper === "original") { + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, this._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + if (this.placeholder) { + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { + this.helper.remove(); + } + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); + } + }); + + if(!str.length && o.key) { + str.push(o.key + "="); + } + + return str.join("&"); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height, + l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if ( this.options.tolerance === "pointer" || + this.options.forcePointerForContainers || + (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) && // Right Half + x2 - (this.helperProportions.width / 2) < r && // Left Half + t < y1 + (this.helperProportions.height / 2) && // Bottom Half + y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) { + return false; + } + + return this.floating ? + ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta !== 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta !== 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + return this; + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var i, j, cur, inst, + items = [], + queries = [], + connectWith = this._connectWith(); + + if(connectWith && connected) { + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for ( j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); + } + } + } + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); + + for (i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + } + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); + + this.items = $.grep(this.items, function (item) { + for (var j=0; j < list.length; j++) { + if(list[j] === item.item[0]) { + return false; + } + } + return true; + }); + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + + var i, j, cur, inst, targetData, _queries, item, queriesLength, + items = this.items, + queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], + connectWith = this._connectWith(); + + if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for (j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + } + } + } + + for (i = queries.length - 1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; + + for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); + + item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + } + } + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + var i, item, t, p; + + for (i = this.items.length - 1; i >= 0; i--){ + item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { + continue; + } + + t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + p = t.offset(); + item.left = p.left; + item.top = p.top; + } + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (i = this.containers.length - 1; i >= 0; i--){ + p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + } + } + + return this; + }, + + _createPlaceholder: function(that) { + that = that || this; + var className, + o = that.options; + + if(!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; + o.placeholder = { + element: function() { + + var nodeName = that.currentItem[0].nodeName.toLowerCase(), + element = $( that.document[0].createElement( nodeName ) ) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper"); + + if ( nodeName === "tr" ) { + // Use a high colspan to force the td to expand the full + // width of the table (browsers are smart enough to + // handle this properly) + element.append( "<td colspan='99'> </td>" ); + } else if ( nodeName === "img" ) { + element.attr( "src", that.currentItem.attr( "src" ) ); + } + + if ( !className ) { + element.css( "visibility", "hidden" ); + } + + return element; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) { + return; + } + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } + } + }; + } + + //Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + //Append it after the actual current item + that.currentItem.after(that.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); + + }, + + _contactContainers: function(event) { + var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, + innermostContainer = null, + innermostIndex = null; + + // get innermost container that intersects with item + for (i = this.containers.length - 1; i >= 0; i--) { + + // never consider a container that's located within the item itself + if($.contains(this.currentItem[0], this.containers[i].element[0])) { + continue; + } + + if(this._intersectsWith(this.containers[i].containerCache)) { + + // if we've already found a container and it's more "inner" than this, then continue + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { + continue; + } + + innermostContainer = this.containers[i]; + innermostIndex = i; + + } else { + // container doesn't intersect. trigger "out" event if necessary + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + // if no intersecting containers found, return + if(!innermostContainer) { + return; + } + + // move the item into the container if it's not there already + if(this.containers.length === 1) { + if (!this.containers[innermostIndex].containerCache.over) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + } else { + + //When entering a new container, we will find the item with the least distance and append our item near it + dist = 10000; + itemWithLeastDistance = null; + floating = innermostContainer.floating || isFloating(this.currentItem); + posProperty = floating ? "left" : "top"; + sizeProperty = floating ? "width" : "height"; + base = this.positionAbs[posProperty] + this.offset.click[posProperty]; + for (j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { + continue; + } + if(this.items[j].item[0] === this.currentItem[0]) { + continue; + } + if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { + continue; + } + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; + if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ + nearBottom = true; + cur += this.items[j][sizeProperty]; + } + + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + this.direction = nearBottom ? "up": "down"; + } + } + + //Check if dropOnEmpty is enabled + if(!itemWithLeastDistance && !this.options.dropOnEmpty) { + return; + } + + if(this.currentContainer === this.containers[innermostIndex]) { + return; + } + + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); + this.currentContainer = this.containers[innermostIndex]; + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + + + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); + + //Add the helper to the DOM if that didn't happen already + if(!helper.parents("body").length) { + $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + } + + if(helper[0] === this.currentItem[0]) { + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + } + + if(!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if(!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + // This needs to be actually done for all browsers, since pageX/pageY includes this information + // with an ugly IE fix + if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var ce, co, over, + o = this.options; + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment)) { + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var top, left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) { + pageX = this.containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < this.containment[1]) { + pageY = this.containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > this.containment[2]) { + pageX = this.containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > this.containment[3]) { + pageY = this.containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if(counter === this.counter) { + this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + } + }); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var i, + delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } + this._noFinalSort = null; + + if(this.helper[0] === this.currentItem[0]) { + for(i in this._storedCSS) { + if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { + this._storedCSS[i] = ""; + } + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + } + if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + } + + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if(!noPropagation) { + delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + } + } + + + //Post events to containers + for (i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + } + if(this.containers[i].containerCache.over) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if ( this.storedCursor ) { + this.document.find( "body" ).css( "cursor", this.storedCursor ); + this.storedStylesheet.remove(); + } + if(this._storedOpacity) { + this.helper.css("opacity", this._storedOpacity); + } + if(this._storedZIndex) { + this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); + } + + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return false; + } + + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] !== this.currentItem[0]) { + this.helper.remove(); + } + this.helper = null; + + if(!noPropagation) { + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return true; + + }, + + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null + }; + } + +}); + +})(jQuery); + +(function($, undefined) { + +var dataSpace = "ui-effects-"; + +$.effects = { + effect: {} +}; + +/*! + * jQuery Color Animations v2.1.2 + * https://github.com/jquery/jquery-color + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * Date: Wed Jan 16 08:47:09 2013 -0600 + */ +(function( jQuery, undefined ) { + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + // a set of RE's that can match strings and generate color tuples. + stringParsers = [{ + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ) + ]; + } + }, { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + }], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, + + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + support = color.support = {}, + + // element for support tests + supportElem = jQuery( "<p>" )[ 0 ], + + // colors = jQuery.Color.names + colors, + + // local aliases of functions called often + each = jQuery.each; + +// determine rgba support immediately +supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; +support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; + +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +}); + +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + + if ( value == null ) { + return (allowEmpty || !prop.def) ? null : prop.def; + } + + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); + + // IE will pass in empty strings as value for alpha, + // which will hit this case + if ( isNaN( value ) ) { + return prop.def; + } + + if ( type.mod ) { + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return (value + type.mod) % type.mod; + } + + // for now all property types without mod have min and max + return 0 > value ? 0 : type.max < value ? type.max : value; +} + +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; + + string = string.toLowerCase(); + + each( stringParsers, function( i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; + } + }); + + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } + + // named colors + return colors[ string ]; +} + +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } + + var inst = this, + type = jQuery.type( red ), + rgba = this._rgba = []; + + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; + } + + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } + + if ( type === "array" ) { + each( spaces.rgba.props, function( key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + }); + return this; + } + + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + }); + } else { + each( spaces, function( spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { + + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + }); + + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + // use the default of 1 + inst[ cache ][ 3 ] = 1; + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + }); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if (isCache) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + }); + } + return same; + }); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + }); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + }); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } + + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; + + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + })); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + return v == null ? ( i > 2 ? 1 : 0 ) : v; + }); + + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + + return prefix + rgba.join() + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } + + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + }); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join() + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); + + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } + + return "#" + jQuery.map( rgba, function( v ) { + + // default to 0 when nulls exist + v = ( v || 0 ).toString( 16 ); + return v.length === 1 ? "0" + v : v; + }).join(""); + }, + toString: function() { + return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); + } +}); +color.fn.parse.prototype = color.fn; + +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 + +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + (q - p) * h * 6; + } + if ( h * 2 < 1) { + return q; + } + if ( h * 3 < 2 ) { + return p + (q - p) * ((2/3) - h) * 6; + } + return p; +} + +spaces.hsla.to = function ( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } + + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; +}; + +spaces.hsla.from = function ( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; + + +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } + + var ret, + type = jQuery.type( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + }); + + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; + + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var vtype = jQuery.type( value ), + fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), + local = this[ fn ](), + cur = local[ prop.idx ], + match; + + if ( vtype === "undefined" ) { + return cur; + } + + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = jQuery.type( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + }); +}); + +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + + if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + (backgroundColor === "" || backgroundColor === "transparent") && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } + } + + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); + } + + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch( e ) { + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + } + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + }); + +}; + +color.hook( stepHooks ); + +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; + + each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { + expanded[ "border" + part + "Color" ] = value; + }); + return expanded; + } +}; + +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" +}; + +})( jQuery ); + + +/******************************************************************************/ +/****************************** CLASS ANIMATIONS ******************************/ +/******************************************************************************/ +(function() { + +var classAnimationActions = [ "add", "remove", "toggle" ], + shorthandStyles = { + border: 1, + borderBottom: 1, + borderColor: 1, + borderLeft: 1, + borderRight: 1, + borderTop: 1, + borderWidth: 1, + margin: 1, + padding: 1 + }; + +$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { + $.fx.step[ prop ] = function( fx ) { + if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { + jQuery.style( fx.elem, prop, fx.end ); + fx.setAttr = true; + } + }; +}); + +function getElementStyles( elem ) { + var key, len, + style = elem.ownerDocument.defaultView ? + elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : + elem.currentStyle, + styles = {}; + + if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { + len = style.length; + while ( len-- ) { + key = style[ len ]; + if ( typeof style[ key ] === "string" ) { + styles[ $.camelCase( key ) ] = style[ key ]; + } + } + // support: Opera, IE <9 + } else { + for ( key in style ) { + if ( typeof style[ key ] === "string" ) { + styles[ key ] = style[ key ]; + } + } + } + + return styles; +} + + +function styleDifference( oldStyle, newStyle ) { + var diff = {}, + name, value; + + for ( name in newStyle ) { + value = newStyle[ name ]; + if ( oldStyle[ name ] !== value ) { + if ( !shorthandStyles[ name ] ) { + if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { + diff[ name ] = value; + } + } + } + } + + return diff; +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +$.effects.animateClass = function( value, duration, easing, callback ) { + var o = $.speed( duration, easing, callback ); + + return this.queue( function() { + var animated = $( this ), + baseClass = animated.attr( "class" ) || "", + applyClassChange, + allAnimations = o.children ? animated.find( "*" ).addBack() : animated; + + // map the animated objects to store the original styles. + allAnimations = allAnimations.map(function() { + var el = $( this ); + return { + el: el, + start: getElementStyles( this ) + }; + }); + + // apply class change + applyClassChange = function() { + $.each( classAnimationActions, function(i, action) { + if ( value[ action ] ) { + animated[ action + "Class" ]( value[ action ] ); + } + }); + }; + applyClassChange(); + + // map all animated objects again - calculate new styles and diff + allAnimations = allAnimations.map(function() { + this.end = getElementStyles( this.el[ 0 ] ); + this.diff = styleDifference( this.start, this.end ); + return this; + }); + + // apply original class + animated.attr( "class", baseClass ); + + // map all animated objects again - this time collecting a promise + allAnimations = allAnimations.map(function() { + var styleInfo = this, + dfd = $.Deferred(), + opts = $.extend({}, o, { + queue: false, + complete: function() { + dfd.resolve( styleInfo ); + } + }); + + this.el.animate( this.diff, opts ); + return dfd.promise(); + }); + + // once all animations have completed: + $.when.apply( $, allAnimations.get() ).done(function() { + + // set the final class + applyClassChange(); + + // for each animated element, + // clear all css properties that were animated + $.each( arguments, function() { + var el = this.el; + $.each( this.diff, function(key) { + el.css( key, "" ); + }); + }); + + // this is guarnteed to be there if you use jQuery.speed() + // it also handles dequeuing the next anim... + o.complete.call( animated[ 0 ] ); + }); + }); +}; + +$.fn.extend({ + addClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.addClass ), + + removeClass: (function( orig ) { + return function( classNames, speed, easing, callback ) { + return arguments.length > 1 ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + })( $.fn.removeClass ), + + toggleClass: (function( orig ) { + return function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { + if ( !speed ) { + // without speed parameter + return orig.apply( this, arguments ); + } else { + return $.effects.animateClass.call( this, + (force ? { add: classNames } : { remove: classNames }), + speed, easing, callback ); + } + } else { + // without force parameter + return $.effects.animateClass.call( this, + { toggle: classNames }, force, speed, easing ); + } + }; + })( $.fn.toggleClass ), + + switchClass: function( remove, add, speed, easing, callback) { + return $.effects.animateClass.call( this, { + add: add, + remove: remove + }, speed, easing, callback ); + } +}); + +})(); + +/******************************************************************************/ +/*********************************** EFFECTS **********************************/ +/******************************************************************************/ + +(function() { + +$.extend( $.effects, { + version: "1.10.2", + + // Saves a set of properties in a data storage + save: function( element, set ) { + for( var i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); + } + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function( element, set ) { + var val, i; + for( i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + val = element.data( dataSpace + set[ i ] ); + // support: jQuery 1.6.2 + // http://bugs.jquery.com/ticket/9917 + // jQuery 1.6.2 incorrectly returns undefined for any falsy value. + // We can't differentiate between "" and 0 here, so we just assume + // empty string since it's likely to be a more common value... + if ( val === undefined ) { + val = ""; + } + element.css( set[ i ], val ); + } + } + }, + + setMode: function( el, mode ) { + if (mode === "toggle") { + mode = el.is( ":hidden" ) ? "show" : "hide"; + } + return mode; + }, + + // Translates a [top,left] array into a baseline value + // this should be a little more flexible in the future to handle a string & hash + getBaseline: function( origin, original ) { + var y, x; + switch ( origin[ 0 ] ) { + case "top": y = 0; break; + case "middle": y = 0.5; break; + case "bottom": y = 1; break; + default: y = origin[ 0 ] / original.height; + } + switch ( origin[ 1 ] ) { + case "left": x = 0; break; + case "center": x = 0.5; break; + case "right": x = 1; break; + default: x = origin[ 1 ] / original.width; + } + return { + x: x, + y: y + }; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function( element ) { + + // if the element is already wrapped, return it + if ( element.parent().is( ".ui-effects-wrapper" )) { + return element.parent(); + } + + // wrap the element + var props = { + width: element.outerWidth(true), + height: element.outerHeight(true), + "float": element.css( "float" ) + }, + wrapper = $( "<div></div>" ) + .addClass( "ui-effects-wrapper" ) + .css({ + fontSize: "100%", + background: "transparent", + border: "none", + margin: 0, + padding: 0 + }), + // Store the size in case width/height are defined in % - Fixes #5245 + size = { + width: element.width(), + height: element.height() + }, + active = document.activeElement; + + // support: Firefox + // Firefox incorrectly exposes anonymous content + // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 + try { + active.id; + } catch( e ) { + active = document.body; + } + + element.wrap( wrapper ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + + wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element + + // transfer positioning properties to the wrapper + if ( element.css( "position" ) === "static" ) { + wrapper.css({ position: "relative" }); + element.css({ position: "relative" }); + } else { + $.extend( props, { + position: element.css( "position" ), + zIndex: element.css( "z-index" ) + }); + $.each([ "top", "left", "bottom", "right" ], function(i, pos) { + props[ pos ] = element.css( pos ); + if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { + props[ pos ] = "auto"; + } + }); + element.css({ + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto" + }); + } + element.css(size); + + return wrapper.css( props ).show(); + }, + + removeWrapper: function( element ) { + var active = document.activeElement; + + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + element.parent().replaceWith( element ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + } + + + return element; + }, + + setTransition: function( element, list, factor, value ) { + value = value || {}; + $.each( list, function( i, x ) { + var unit = element.cssUnit( x ); + if ( unit[ 0 ] > 0 ) { + value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; + } + }); + return value; + } +}); + +// return an effect options object for the given parameters: +function _normalizeArguments( effect, options, speed, callback ) { + + // allow passing all options as the first parameter + if ( $.isPlainObject( effect ) ) { + options = effect; + effect = effect.effect; + } + + // convert to an object + effect = { effect: effect }; + + // catch (effect, null, ...) + if ( options == null ) { + options = {}; + } + + // catch (effect, callback) + if ( $.isFunction( options ) ) { + callback = options; + speed = null; + options = {}; + } + + // catch (effect, speed, ?) + if ( typeof options === "number" || $.fx.speeds[ options ] ) { + callback = speed; + speed = options; + options = {}; + } + + // catch (effect, options, callback) + if ( $.isFunction( speed ) ) { + callback = speed; + speed = null; + } + + // add options to effect + if ( options ) { + $.extend( effect, options ); + } + + speed = speed || options.duration; + effect.duration = $.fx.off ? 0 : + typeof speed === "number" ? speed : + speed in $.fx.speeds ? $.fx.speeds[ speed ] : + $.fx.speeds._default; + + effect.complete = callback || options.complete; + + return effect; +} + +function standardAnimationOption( option ) { + // Valid standard speeds (nothing, number, named speed) + if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { + return true; + } + + // Invalid strings - treat as "normal" speed + if ( typeof option === "string" && !$.effects.effect[ option ] ) { + return true; + } + + // Complete callback + if ( $.isFunction( option ) ) { + return true; + } + + // Options hash (but not naming an effect) + if ( typeof option === "object" && !option.effect ) { + return true; + } + + // Didn't match any standard API + return false; +} + +$.fn.extend({ + effect: function( /* effect, options, speed, callback */ ) { + var args = _normalizeArguments.apply( this, arguments ), + mode = args.mode, + queue = args.queue, + effectMethod = $.effects.effect[ args.effect ]; + + if ( $.fx.off || !effectMethod ) { + // delegate to the original method (e.g., .show()) if possible + if ( mode ) { + return this[ mode ]( args.duration, args.complete ); + } else { + return this.each( function() { + if ( args.complete ) { + args.complete.call( this ); + } + }); + } + } + + function run( next ) { + var elem = $( this ), + complete = args.complete, + mode = args.mode; + + function done() { + if ( $.isFunction( complete ) ) { + complete.call( elem[0] ); + } + if ( $.isFunction( next ) ) { + next(); + } + } + + // If the element already has the correct final state, delegate to + // the core methods so the internal tracking of "olddisplay" works. + if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + elem[ mode ](); + done(); + } else { + effectMethod.call( elem[0], args, done ); + } + } + + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); + }, + + show: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "show"; + return this.effect.call( this, args ); + } + }; + })( $.fn.show ), + + hide: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "hide"; + return this.effect.call( this, args ); + } + }; + })( $.fn.hide ), + + toggle: (function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) || typeof option === "boolean" ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "toggle"; + return this.effect.call( this, args ); + } + }; + })( $.fn.toggle ), + + // helper functions + cssUnit: function(key) { + var style = this.css( key ), + val = []; + + $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { + if ( style.indexOf( unit ) > 0 ) { + val = [ parseFloat( style ), unit ]; + } + }); + return val; + } +}); + +})(); + +/******************************************************************************/ +/*********************************** EASING ***********************************/ +/******************************************************************************/ + +(function() { + +// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) + +var baseEasings = {}; + +$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { + baseEasings[ name ] = function( p ) { + return Math.pow( p, i + 2 ); + }; +}); + +$.extend( baseEasings, { + Sine: function ( p ) { + return 1 - Math.cos( p * Math.PI / 2 ); + }, + Circ: function ( p ) { + return 1 - Math.sqrt( 1 - p * p ); + }, + Elastic: function( p ) { + return p === 0 || p === 1 ? p : + -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); + }, + Back: function( p ) { + return p * p * ( 3 * p - 2 ); + }, + Bounce: function ( p ) { + var pow2, + bounce = 4; + + while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} + return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); + } +}); + +$.each( baseEasings, function( name, easeIn ) { + $.easing[ "easeIn" + name ] = easeIn; + $.easing[ "easeOut" + name ] = function( p ) { + return 1 - easeIn( 1 - p ); + }; + $.easing[ "easeInOut" + name ] = function( p ) { + return p < 0.5 ? + easeIn( p * 2 ) / 2 : + 1 - easeIn( p * -2 + 2 ) / 2; + }; +}); + +})(); + +})(jQuery); + +(function( $, undefined ) { + +var uid = 0, + hideProps = {}, + showProps = {}; + +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; + +$.widget( "ui.accordion", { + version: "1.10.2", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + _create: function() { + var options = this.options; + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + + this._processPanels(); + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next(), + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "<span>" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter(":not(.ui-accordion-content-active)") + .hide(); + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(), + accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) + .removeClass( "ui-corner-all" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } + + this._trigger( "activate", null, data ); + } +}); + +})( jQuery ); + +(function( $, undefined ) { + +// used to prevent race conditions with remote data sources +var requestIndex = 0; + +$.widget( "ui.autocomplete", { + version: "1.10.2", + defaultElement: "<input>", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + pending: 0, + + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[0].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + this.isMultiLine = + // Textareas are always multi-line + isTextarea ? true : + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + isInput ? false : + // All other element types are determined by whether or not they're contentEditable + this.element.prop( "isContentEditable" ); + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + case keyCode.NUMPAD_ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + this._value( this.term ); + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + event.preventDefault(); + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + }); + + this._initSource(); + this.menu = $( "<ul>" ) + .addClass( "ui-autocomplete ui-front" ) + .appendTo( this._appendTo() ) + .menu({ + // custom key handling for now + input: $(), + // disable ARIA support, the live region takes care of that + role: null + }) + .hide() + .data( "ui-menu" ); + + this._on( this.menu.element, { + mousedown: function( event ) { + // prevent moving focus out of the text field + event.preventDefault(); + + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + }); + + // clicking on the scrollbar causes focus to shift to the body + // but we can't detect a mouseup or a click immediately afterward + // so we have to track the next mousedown and close the menu if + // the user clicks somewhere outside of the autocomplete + var menuElement = this.menu.element[ 0 ]; + if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { + this._delay(function() { + var that = this; + this.document.one( "mousedown", function( event ) { + if ( event.target !== that.element[ 0 ] && + event.target !== menuElement && + !$.contains( menuElement, event.target ) ) { + that.close(); + } + }); + }); + } + }, + menufocus: function( event, ui ) { + // support: Firefox + // Prevent accidental activation of menu items in Firefox (#7024 #9118) + if ( this.isNewMenu ) { + this.isNewMenu = false; + if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { + this.menu.blur(); + + this.document.one( "mousemove", function() { + $( event.target ).trigger( event.originalEvent ); + }); + + return; + } + } + + var item = ui.item.data( "ui-autocomplete-item" ); + if ( false !== this._trigger( "focus", event, { item: item } ) ) { + // use value to match what will end up in the input, if it was a key event + if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { + this._value( item.value ); + } + } else { + // Normally the input is populated with the item's value as the + // menu is navigated, causing screen readers to notice a change and + // announce the item. Since the focus event was canceled, this doesn't + // happen, so we update the live region so that screen readers can + // still notice the change and announce it. + this.liveRegion.text( item.value ); + } + }, + menuselect: function( event, ui ) { + var item = ui.item.data( "ui-autocomplete-item" ), + previous = this.previous; + + // only trigger when focus was lost (click on menu) + if ( this.element[0] !== this.document[0].activeElement ) { + this.element.focus(); + this.previous = previous; + // #6109 - IE triggers two focus events and the second + // is asynchronous, so we need to reset the previous + // term synchronously and asynchronously :-( + this._delay(function() { + this.previous = previous; + this.selectedItem = item; + }); + } + + if ( false !== this._trigger( "select", event, { item: item } ) ) { + this._value( item.value ); + } + // reset the term after the select event + // this allows custom select handling to work properly + this.term = this._value(); + + this.close( event ); + this.selectedItem = item; + } + }); + + this.liveRegion = $( "<span>", { + role: "status", + "aria-live": "polite" + }) + .addClass( "ui-helper-hidden-accessible" ) + .insertAfter( this.element ); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _destroy: function() { + clearTimeout( this.searching ); + this.element + .removeClass( "ui-autocomplete-input" ) + .removeAttr( "autocomplete" ); + this.menu.element.remove(); + this.liveRegion.remove(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "source" ) { + this._initSource(); + } + if ( key === "appendTo" ) { + this.menu.element.appendTo( this._appendTo() ); + } + if ( key === "disabled" && value && this.xhr ) { + this.xhr.abort(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); + } + + if ( !element ) { + element = this.element.closest( ".ui-front" ); + } + + if ( !element.length ) { + element = this.document[0].body; + } + + return element; + }, + + _initSource: function() { + var array, url, + that = this; + if ( $.isArray(this.options.source) ) { + array = this.options.source; + this.source = function( request, response ) { + response( $.ui.autocomplete.filter( array, request.term ) ); + }; + } else if ( typeof this.options.source === "string" ) { + url = this.options.source; + this.source = function( request, response ) { + if ( that.xhr ) { + that.xhr.abort(); + } + that.xhr = $.ajax({ + url: url, + data: request, + dataType: "json", + success: function( data ) { + response( data ); + }, + error: function() { + response( [] ); + } + }); + }; + } else { + this.source = this.options.source; + } + }, + + _searchTimeout: function( event ) { + clearTimeout( this.searching ); + this.searching = this._delay(function() { + // only search if the value has changed + if ( this.term !== this._value() ) { + this.selectedItem = null; + this.search( null, event ); + } + }, this.options.delay ); + }, + + search: function( value, event ) { + value = value != null ? value : this._value(); + + // always save the actual value, not the one passed as an argument + this.term = this._value(); + + if ( value.length < this.options.minLength ) { + return this.close( event ); + } + + if ( this._trigger( "search", event ) === false ) { + return; + } + + return this._search( value ); + }, + + _search: function( value ) { + this.pending++; + this.element.addClass( "ui-autocomplete-loading" ); + this.cancelSearch = false; + + this.source( { term: value }, this._response() ); + }, + + _response: function() { + var that = this, + index = ++requestIndex; + + return function( content ) { + if ( index === requestIndex ) { + that.__response( content ); + } + + that.pending--; + if ( !that.pending ) { + that.element.removeClass( "ui-autocomplete-loading" ); + } + }; + }, + + __response: function( content ) { + if ( content ) { + content = this._normalize( content ); + } + this._trigger( "response", null, { content: content } ); + if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { + this._suggest( content ); + this._trigger( "open" ); + } else { + // use ._close() instead of .close() so we don't cancel future searches + this._close(); + } + }, + + close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, + + _close: function( event ) { + if ( this.menu.element.is( ":visible" ) ) { + this.menu.element.hide(); + this.menu.blur(); + this.isNewMenu = true; + this._trigger( "close", event ); + } + }, + + _change: function( event ) { + if ( this.previous !== this._value() ) { + this._trigger( "change", event, { item: this.selectedItem } ); + } + }, + + _normalize: function( items ) { + // assume all items have the right format when the first item is complete + if ( items.length && items[0].label && items[0].value ) { + return items; + } + return $.map( items, function( item ) { + if ( typeof item === "string" ) { + return { + label: item, + value: item + }; + } + return $.extend({ + label: item.label || item.value, + value: item.value || item.label + }, item ); + }); + }, + + _suggest: function( items ) { + var ul = this.menu.element.empty(); + this._renderMenu( ul, items ); + this.isNewMenu = true; + this.menu.refresh(); + + // size and position menu + ul.show(); + this._resizeMenu(); + ul.position( $.extend({ + of: this.element + }, this.options.position )); + + if ( this.options.autoFocus ) { + this.menu.next(); + } + }, + + _resizeMenu: function() { + var ul = this.menu.element; + ul.outerWidth( Math.max( + // Firefox wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping (#7513) + ul.width( "" ).outerWidth() + 1, + this.element.outerWidth() + ) ); + }, + + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ); + }); + }, + + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); + }, + + _renderItem: function( ul, item ) { + return $( "<li>" ) + .append( $( "<a>" ).text( item.label ) ) + .appendTo( ul ); + }, + + _move: function( direction, event ) { + if ( !this.menu.element.is( ":visible" ) ) { + this.search( null, event ); + return; + } + if ( this.menu.isFirstItem() && /^previous/.test( direction ) || + this.menu.isLastItem() && /^next/.test( direction ) ) { + this._value( this.term ); + this.menu.blur(); + return; + } + this.menu[ direction ]( event ); + }, + + widget: function() { + return this.menu.element; + }, + + _value: function() { + return this.valueMethod.apply( this.element, arguments ); + }, + + _keyEvent: function( keyEvent, event ) { + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + this._move( keyEvent, event ); + + // prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); + } + } +}); + +$.extend( $.ui.autocomplete, { + escapeRegex: function( value ) { + return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); + }, + filter: function(array, term) { + var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); + return $.grep( array, function(value) { + return matcher.test( value.label || value.value || value ); + }); + } +}); + + +// live region extension, adding a `messages` option +// NOTE: This is an experimental API. We are still investigating +// a full solution for string manipulation and internationalization. +$.widget( "ui.autocomplete", $.ui.autocomplete, { + options: { + messages: { + noResults: "No search results.", + results: function( amount ) { + return amount + ( amount > 1 ? " results are" : " result is" ) + + " available, use up and down arrow keys to navigate."; + } + } + }, + + __response: function( content ) { + var message; + this._superApply( arguments ); + if ( this.options.disabled || this.cancelSearch ) { + return; + } + if ( content && content.length ) { + message = this.options.messages.results( content.length ); + } else { + message = this.options.messages.noResults; + } + this.liveRegion.text( message ); + } +}); + +}( jQuery )); + +(function( $, undefined ) { + +var lastActive, startXPos, startYPos, clickDragged, + baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", + stateClasses = "ui-state-hover ui-state-active ", + typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", + formResetHandler = function() { + var buttons = $( this ).find( ":ui-button" ); + setTimeout(function() { + buttons.button( "refresh" ); + }, 1 ); + }, + radioGroup = function( radio ) { + var name = radio.name, + form = radio.form, + radios = $( [] ); + if ( name ) { + name = name.replace( /'/g, "\\'" ); + if ( form ) { + radios = $( form ).find( "[name='" + name + "']" ); + } else { + radios = $( "[name='" + name + "']", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } + } + return radios; + }; + +$.widget( "ui.button", { + version: "1.10.2", + defaultElement: "<button>", + options: { + disabled: null, + text: true, + label: null, + icons: { + primary: null, + secondary: null + } + }, + _create: function() { + this.element.closest( "form" ) + .unbind( "reset" + this.eventNamespace ) + .bind( "reset" + this.eventNamespace, formResetHandler ); + + if ( typeof this.options.disabled !== "boolean" ) { + this.options.disabled = !!this.element.prop( "disabled" ); + } else { + this.element.prop( "disabled", this.options.disabled ); + } + + this._determineButtonType(); + this.hasTitle = !!this.buttonElement.attr( "title" ); + + var that = this, + options = this.options, + toggleButton = this.type === "checkbox" || this.type === "radio", + activeClass = !toggleButton ? "ui-state-active" : "", + focusClass = "ui-state-focus"; + + if ( options.label === null ) { + options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); + } + + this._hoverable( this.buttonElement ); + + this.buttonElement + .addClass( baseClasses ) + .attr( "role", "button" ) + .bind( "mouseenter" + this.eventNamespace, function() { + if ( options.disabled ) { + return; + } + if ( this === lastActive ) { + $( this ).addClass( "ui-state-active" ); + } + }) + .bind( "mouseleave" + this.eventNamespace, function() { + if ( options.disabled ) { + return; + } + $( this ).removeClass( activeClass ); + }) + .bind( "click" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + }); + + this.element + .bind( "focus" + this.eventNamespace, function() { + // no need to check disabled, focus won't be triggered anyway + that.buttonElement.addClass( focusClass ); + }) + .bind( "blur" + this.eventNamespace, function() { + that.buttonElement.removeClass( focusClass ); + }); + + if ( toggleButton ) { + this.element.bind( "change" + this.eventNamespace, function() { + if ( clickDragged ) { + return; + } + that.refresh(); + }); + // if mouse moves between mousedown and mouseup (drag) set clickDragged flag + // prevents issue where button state changes but checkbox/radio checked state + // does not in Firefox (see ticket #6970) + this.buttonElement + .bind( "mousedown" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + return; + } + clickDragged = false; + startXPos = event.pageX; + startYPos = event.pageY; + }) + .bind( "mouseup" + this.eventNamespace, function( event ) { + if ( options.disabled ) { + return; + } + if ( startXPos !== event.pageX || startYPos !== event.pageY ) { + clickDragged = true; + } + }); + } + + if ( this.type === "checkbox" ) { + this.buttonElement.bind( "click" + this.eventNamespace, function() { + if ( options.disabled || clickDragged ) { + return false; + } + }); + } else if ( this.type === "radio" ) { + this.buttonElement.bind( "click" + this.eventNamespace, function() { + if ( options.disabled || clickDragged ) { + return false; + } + $( this ).addClass( "ui-state-active" ); + that.buttonElement.attr( "aria-pressed", "true" ); + + var radio = that.element[ 0 ]; + radioGroup( radio ) + .not( radio ) + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + }); + } else { + this.buttonElement + .bind( "mousedown" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).addClass( "ui-state-active" ); + lastActive = this; + that.document.one( "mouseup", function() { + lastActive = null; + }); + }) + .bind( "mouseup" + this.eventNamespace, function() { + if ( options.disabled ) { + return false; + } + $( this ).removeClass( "ui-state-active" ); + }) + .bind( "keydown" + this.eventNamespace, function(event) { + if ( options.disabled ) { + return false; + } + if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { + $( this ).addClass( "ui-state-active" ); + } + }) + // see #8559, we bind to blur here in case the button element loses + // focus between keydown and keyup, it would be left in an "active" state + .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { + $( this ).removeClass( "ui-state-active" ); + }); + + if ( this.buttonElement.is("a") ) { + this.buttonElement.keyup(function(event) { + if ( event.keyCode === $.ui.keyCode.SPACE ) { + // TODO pass through original event correctly (just as 2nd argument doesn't work) + $( this ).click(); + } + }); + } + } + + // TODO: pull out $.Widget's handling for the disabled option into + // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can + // be overridden by individual plugins + this._setOption( "disabled", options.disabled ); + this._resetButton(); + }, + + _determineButtonType: function() { + var ancestor, labelSelector, checked; + + if ( this.element.is("[type=checkbox]") ) { + this.type = "checkbox"; + } else if ( this.element.is("[type=radio]") ) { + this.type = "radio"; + } else if ( this.element.is("input") ) { + this.type = "input"; + } else { + this.type = "button"; + } + + if ( this.type === "checkbox" || this.type === "radio" ) { + // we don't search against the document in case the element + // is disconnected from the DOM + ancestor = this.element.parents().last(); + labelSelector = "label[for='" + this.element.attr("id") + "']"; + this.buttonElement = ancestor.find( labelSelector ); + if ( !this.buttonElement.length ) { + ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); + this.buttonElement = ancestor.filter( labelSelector ); + if ( !this.buttonElement.length ) { + this.buttonElement = ancestor.find( labelSelector ); + } + } + this.element.addClass( "ui-helper-hidden-accessible" ); + + checked = this.element.is( ":checked" ); + if ( checked ) { + this.buttonElement.addClass( "ui-state-active" ); + } + this.buttonElement.prop( "aria-pressed", checked ); + } else { + this.buttonElement = this.element; + } + }, + + widget: function() { + return this.buttonElement; + }, + + _destroy: function() { + this.element + .removeClass( "ui-helper-hidden-accessible" ); + this.buttonElement + .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) + .removeAttr( "role" ) + .removeAttr( "aria-pressed" ) + .html( this.buttonElement.find(".ui-button-text").html() ); + + if ( !this.hasTitle ) { + this.buttonElement.removeAttr( "title" ); + } + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "disabled" ) { + if ( value ) { + this.element.prop( "disabled", true ); + } else { + this.element.prop( "disabled", false ); + } + return; + } + this._resetButton(); + }, + + refresh: function() { + //See #8237 & #8828 + var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); + + if ( isDisabled !== this.options.disabled ) { + this._setOption( "disabled", isDisabled ); + } + if ( this.type === "radio" ) { + radioGroup( this.element[0] ).each(function() { + if ( $( this ).is( ":checked" ) ) { + $( this ).button( "widget" ) + .addClass( "ui-state-active" ) + .attr( "aria-pressed", "true" ); + } else { + $( this ).button( "widget" ) + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + } + }); + } else if ( this.type === "checkbox" ) { + if ( this.element.is( ":checked" ) ) { + this.buttonElement + .addClass( "ui-state-active" ) + .attr( "aria-pressed", "true" ); + } else { + this.buttonElement + .removeClass( "ui-state-active" ) + .attr( "aria-pressed", "false" ); + } + } + }, + + _resetButton: function() { + if ( this.type === "input" ) { + if ( this.options.label ) { + this.element.val( this.options.label ); + } + return; + } + var buttonElement = this.buttonElement.removeClass( typeClasses ), + buttonText = $( "<span></span>", this.document[0] ) + .addClass( "ui-button-text" ) + .html( this.options.label ) + .appendTo( buttonElement.empty() ) + .text(), + icons = this.options.icons, + multipleIcons = icons.primary && icons.secondary, + buttonClasses = []; + + if ( icons.primary || icons.secondary ) { + if ( this.options.text ) { + buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); + } + + if ( icons.primary ) { + buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); + } + + if ( icons.secondary ) { + buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); + } + + if ( !this.options.text ) { + buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); + + if ( !this.hasTitle ) { + buttonElement.attr( "title", $.trim( buttonText ) ); + } + } + } else { + buttonClasses.push( "ui-button-text-only" ); + } + buttonElement.addClass( buttonClasses.join( " " ) ); + } +}); + +$.widget( "ui.buttonset", { + version: "1.10.2", + options: { + items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" + }, + + _create: function() { + this.element.addClass( "ui-buttonset" ); + }, + + _init: function() { + this.refresh(); + }, + + _setOption: function( key, value ) { + if ( key === "disabled" ) { + this.buttons.button( "option", key, value ); + } + + this._super( key, value ); + }, + + refresh: function() { + var rtl = this.element.css( "direction" ) === "rtl"; + + this.buttons = this.element.find( this.options.items ) + .filter( ":ui-button" ) + .button( "refresh" ) + .end() + .not( ":ui-button" ) + .button() + .end() + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) + .filter( ":first" ) + .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) + .end() + .filter( ":last" ) + .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) + .end() + .end(); + }, + + _destroy: function() { + this.element.removeClass( "ui-buttonset" ); + this.buttons + .map(function() { + return $( this ).button( "widget" )[ 0 ]; + }) + .removeClass( "ui-corner-left ui-corner-right" ) + .end() + .button( "destroy" ); + } +}); + +}( jQuery ) ); + +(function( $, undefined ) { + +$.extend($.ui, { datepicker: { version: "1.10.2" } }); + +var PROP_NAME = "datepicker", + dpuuid = new Date().getTime(), + instActive; + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division + this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class + this._appendClass = "ui-datepicker-append"; // The name of the append marker class + this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class + this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class + this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class + this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class + this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class + this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[""] = { // Default regional settings + closeText: "Done", // Display text for close link + prevText: "Prev", // Display text for previous month link + nextText: "Next", // Display text for next month link + currentText: "Today", // Display text for current month link + monthNames: ["January","February","March","April","May","June", + "July","August","September","October","November","December"], // Names of months for drop-down and formatting + monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting + dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday + weekHeader: "Wk", // Column header for week of the year + dateFormat: "mm/dd/yy", // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false, // True if right-to-left language, false if left-to-right + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearSuffix: "" // Additional text to append to the year in the month headers + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: "focus", // "focus" for popup on focus, + // "button" for trigger button, or "both" for either + showAnim: "fadeIn", // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: "", // Display text following the input box, e.g. showing the format + buttonText: "...", // Text for trigger button + buttonImage: "", // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + yearRange: "c-10:c+10", // Range of years to display in drop-down, + // either relative to today's year (-nn:+nn), relative to currently displayed year + // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) + showOtherMonths: false, // True to show dates in other months, false to leave blank + selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable + showWeek: false, // True to show week of the year, false to not show it + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: "+10", // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with "+" for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: "fast", // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: "", // Selector for an alternate field to store selected dates into + altFormat: "", // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false, // True to show button panel, false to not show it + autoSize: false, // True to size the input for the date format, false to leave as is + disabled: false // The initial disabled state + }; + $.extend(this._defaults, this.regional[""]); + this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: "hasDatepicker", + + //Keep track of the maximum number of rows displayed (see #7043) + maxRows: 4, + + // TODO rename to "widget" when switching to widget factory + _widgetDatepicker: function() { + return this.dpDiv; + }, + + /* Override the default settings for all instances of the date picker. + * @param settings object - the new settings to use as defaults (anonymous object) + * @return the manager object + */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + * @param target element - the target input field or division or span + * @param settings object - the new settings to use for this date picker instance (anonymous) + */ + _attachDatepicker: function(target, settings) { + var nodeName, inline, inst; + nodeName = target.nodeName.toLowerCase(); + inline = (nodeName === "div" || nodeName === "span"); + if (!target.id) { + this.uuid += 1; + target.id = "dp" + this.uuid; + } + inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}); + if (nodeName === "input") { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) { + return; + } + this._attachments(input, inst); + input.addClass(this.markerClassName).keydown(this._doKeyDown). + keypress(this._doKeyPress).keyup(this._doKeyUp); + this._autoSize(inst); + $.data(target, PROP_NAME, inst); + //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + }, + + /* Make attachments based on settings. */ + _attachments: function(input, inst) { + var showOn, buttonText, buttonImage, + appendText = this._get(inst, "appendText"), + isRTL = this._get(inst, "isRTL"); + + if (inst.append) { + inst.append.remove(); + } + if (appendText) { + inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); + input[isRTL ? "before" : "after"](inst.append); + } + + input.unbind("focus", this._showDatepicker); + + if (inst.trigger) { + inst.trigger.remove(); + } + + showOn = this._get(inst, "showOn"); + if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + } + if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked + buttonText = this._get(inst, "buttonText"); + buttonImage = this._get(inst, "buttonImage"); + inst.trigger = $(this._get(inst, "buttonImageOnly") ? + $("<img/>").addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $("<button type='button'></button>").addClass(this._triggerClass). + html(!buttonImage ? buttonText : $("<img/>").attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? "before" : "after"](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { + $.datepicker._hideDatepicker(); + } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { + $.datepicker._hideDatepicker(); + $.datepicker._showDatepicker(input[0]); + } else { + $.datepicker._showDatepicker(input[0]); + } + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, "autoSize") && !inst.inline) { + var findMax, max, maxI, i, + date = new Date(2009, 12 - 1, 20), // Ensure double digits + dateFormat = this._get(inst, "dateFormat"); + + if (dateFormat.match(/[DM]/)) { + findMax = function(names) { + max = 0; + maxI = 0; + for (i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + "monthNames" : "monthNamesShort")))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); + } + inst.input.attr("size", this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) { + return; + } + divSpan.addClass(this.markerClassName).append(inst.dpDiv); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + //If disabled option is true, disable the datepicker before showing it (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements + // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height + inst.dpDiv.css( "display", "block" ); + }, + + /* Pop-up the date picker in a "dialog" box. + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var id, browserWidth, browserHeight, scrollX, scrollY, + inst = this._dialogInst; // internal instance + + if (!inst) { + this.uuid += 1; + id = "dp" + this.uuid; + this._dialogInput = $("<input type='text' id='" + id + + "' style='position: absolute; top: -100px; width: 0px;'/>"); + this._dialogInput.keydown(this._doKeyDown); + $("body").append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + browserWidth = document.documentElement.clientWidth; + browserHeight = document.documentElement.clientHeight; + scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) { + $.blockUI(this.dpDiv); + } + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + * @param target element - the target input field or division or span + */ + _destroyDatepicker: function(target) { + var nodeName, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName === "input") { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind("focus", this._showDatepicker). + unbind("keydown", this._doKeyDown). + unbind("keypress", this._doKeyPress). + unbind("keyup", this._doKeyUp); + } else if (nodeName === "div" || nodeName === "span") { + $target.removeClass(this.markerClassName).empty(); + } + }, + + /* Enable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _enableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img").css({opacity: "1.0", cursor: ""}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().removeClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", false); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _disableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img").css({opacity: "0.5", cursor: "default"}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().addClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", true); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] === target) { + return true; + } + } + return false; + }, + + /* Retrieve the instance data for the target control. + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw "Missing instance data for this datepicker"; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also "all" for all instance settings or + * "defaults" for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ + _optionDatepicker: function(target, name, value) { + var settings, date, minDate, maxDate, + inst = this._getInst(target); + + if (arguments.length === 2 && typeof name === "string") { + return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : + (inst ? (name === "all" ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + + settings = name || {}; + if (typeof name === "string") { + settings = {}; + settings[name] = value; + } + + if (inst) { + if (this._curInst === inst) { + this._hideDatepicker(); + } + + date = this._getDateDatepicker(target, true); + minDate = this._getMinMaxDate(inst, "min"); + maxDate = this._getMinMaxDate(inst, "max"); + extendRemove(inst.settings, settings); + // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { + inst.settings.minDate = this._formatDate(inst, minDate); + } + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { + inst.settings.maxDate = this._formatDate(inst, maxDate); + } + if ( "disabled" in settings ) { + if ( settings.disabled ) { + this._disableDatepicker(target); + } else { + this._enableDatepicker(target); + } + } + this._attachments($(target), inst); + this._autoSize(inst); + this._setDate(inst, date); + this._updateAlternate(inst); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + * @param target element - the target input field or division or span + */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + * @param target element - the target input field or division or span + * @param date Date - the new date + */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) { + this._setDateFromField(inst, noDefault); + } + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var onSelect, dateStr, sel, + inst = $.datepicker._getInst(event.target), + handled = true, + isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); + + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) { + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + + $.datepicker._currentClass + ")", inst.dpDiv); + if (sel[0]) { + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + } + + onSelect = $.datepicker._get(inst, "onSelect"); + if (onSelect) { + dateStr = $.datepicker._formatDate(inst); + + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } else { + $.datepicker._hideDatepicker(); + } + + return false; // don't submit the form + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) { + $.datepicker._clearDate(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) { + $.datepicker._gotoToday(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, -7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, +7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + } else { + handled = false; + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var chars, chr, + inst = $.datepicker._getInst(event.target); + + if ($.datepicker._get(inst, "constrainInput")) { + chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); + chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var date, + inst = $.datepicker._getInst(event.target); + + if (inst.input.val() !== inst.lastVal) { + try { + date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (err) { + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger + input = $("input", input.parentNode)[0]; + } + + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here + return; + } + + var inst, beforeShow, beforeShowSettings, isFixed, + offset, showAnim, duration; + + inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst !== inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + if ( inst && $.datepicker._datepickerShowing ) { + $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); + } + } + + beforeShow = $.datepicker._get(inst, "beforeShow"); + beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + if(beforeShowSettings === false){ + return; + } + extendRemove(inst.settings, beforeShowSettings); + + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + + if ($.datepicker._inDialog) { // hide cursor + input.value = ""; + } + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + + isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css("position") === "fixed"; + return !isFixed; + }); + + offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + //to avoid flashes on Firefox + inst.dpDiv.empty(); + // determine sizing offscreen + inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + "static" : (isFixed ? "fixed" : "absolute")), display: "none", + left: offset.left + "px", top: offset.top + "px"}); + + if (!inst.inline) { + showAnim = $.datepicker._get(inst, "showAnim"); + duration = $.datepicker._get(inst, "duration"); + inst.dpDiv.zIndex($(input).zIndex()+1); + $.datepicker._datepickerShowing = true; + + if ( $.effects && $.effects.effect[ showAnim ] ) { + inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); + } else { + inst.dpDiv[showAnim || "show"](showAnim ? duration : null); + } + + if (inst.input.is(":visible") && !inst.input.is(":disabled")) { + inst.input.focus(); + } + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) + instActive = inst; // for delegate hover events + inst.dpDiv.empty().append(this._generateHTML(inst)); + this._attachHandlers(inst); + inst.dpDiv.find("." + this._dayOverClass + " a").mouseover(); + + var origyearshtml, + numMonths = this._getNumberOfMonths(inst), + cols = numMonths[1], + width = 17; + + inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); + if (cols > 1) { + inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); + } + inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + + "Class"]("ui-datepicker-multi"); + inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + + "Class"]("ui-datepicker-rtl"); + + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && + inst.input.is(":visible") && !inst.input.is(":disabled") && inst.input[0] !== document.activeElement) { + inst.input.focus(); + } + + // deffered render of the years select (to avoid flashes on Firefox) + if( inst.yearshtml ){ + origyearshtml = inst.yearshtml; + setTimeout(function(){ + //assure that inst.yearshtml didn't change. + if( origyearshtml === inst.yearshtml && inst.yearshtml ){ + inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); + } + origyearshtml = inst.yearshtml = null; + }, 0); + } + }, + + /* Retrieve the size of left and top borders for an element. + * @param elem (jQuery object) the element of interest + * @return (number[2]) the left and top borders + */ + _getBorders: function(elem) { + var convert = function(value) { + return {thin: 1, medium: 2, thick: 3}[value] || value; + }; + return [parseFloat(convert(elem.css("border-left-width"))), + parseFloat(convert(elem.css("border-top-width")))]; + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(), + dpHeight = inst.dpDiv.outerHeight(), + inputWidth = inst.input ? inst.input.outerWidth() : 0, + inputHeight = inst.input ? inst.input.outerHeight() : 0, + viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), + viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); + + offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var position, + inst = this._getInst(obj), + isRTL = this._get(inst, "isRTL"); + + while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? "previousSibling" : "nextSibling"]; + } + + position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + * @param input element - the input field attached to the date picker + */ + _hideDatepicker: function(input) { + var showAnim, duration, postProcess, onClose, + inst = this._curInst; + + if (!inst || (input && inst !== $.data(input, PROP_NAME))) { + return; + } + + if (this._datepickerShowing) { + showAnim = this._get(inst, "showAnim"); + duration = this._get(inst, "duration"); + postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); + } else { + inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : + (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); + } + + if (!showAnim) { + postProcess(); + } + this._datepickerShowing = false; + + onClose = this._get(inst, "onClose"); + if (onClose) { + onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); + } + + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); + if ($.blockUI) { + $.unblockUI(); + $("body").append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) { + return; + } + + var $target = $(event.target), + inst = $.datepicker._getInst($target[0]); + + if ( ( ( $target[0].id !== $.datepicker._mainDivId && + $target.parents("#" + $.datepicker._mainDivId).length === 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.closest("." + $.datepicker._triggerClass).length && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { + $.datepicker._hideDatepicker(); + } + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id), + inst = this._getInst(target[0]); + + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var date, + target = $(id), + inst = this._getInst(target[0]); + + if (this._get(inst, "gotoCurrent") && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } else { + date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id), + inst = this._getInst(target[0]); + + inst["selected" + (period === "M" ? "Month" : "Year")] = + inst["draw" + (period === "M" ? "Month" : "Year")] = + parseInt(select.options[select.selectedIndex].value,10); + + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var inst, + target = $(id); + + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + + inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $("a", td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + this._selectDate(target, ""); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var onSelect, + target = $(id), + inst = this._getInst(target[0]); + + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) { + inst.input.val(dateStr); + } + this._updateAlternate(inst); + + onSelect = this._get(inst, "onSelect"); + if (onSelect) { + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + } else if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + + if (inst.inline){ + this._updateDatepicker(inst); + } else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) !== "object") { + inst.input.focus(); // restore focus + } + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altFormat, date, dateStr, + altField = this._get(inst, "altField"); + + if (altField) { // update alternate field too + altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); + date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), ""]; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ + iso8601Week: function(date) { + var time, + checkDate = new Date(date.getTime()); + + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + + time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ + parseDate: function (format, value, settings) { + if (format == null || value == null) { + throw "Invalid arguments"; + } + + value = (typeof value === "object" ? value.toString() : value + ""); + if (value === "") { + return null; + } + + var iFormat, dim, extra, + iValue = 0, + shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, + shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : + new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Extract a number from the string value + getNumber = function(match) { + var isDoubled = lookAhead(match), + size = (match === "@" ? 14 : (match === "!" ? 20 : + (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), + digits = new RegExp("^\\d{1," + size + "}"), + num = value.substring(iValue).match(digits); + if (!num) { + throw "Missing number at position " + iValue; + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + // Extract a name from the string value and convert to an index + getName = function(match, shortNames, longNames) { + var index = -1, + names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index !== -1) { + return index + 1; + } else { + throw "Unknown name at position " + iValue; + } + }, + // Confirm that a literal character matches the string value + checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw "Unexpected literal at position " + iValue; + } + iValue++; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + checkLiteral(); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + day = getNumber("d"); + break; + case "D": + getName("D", dayNamesShort, dayNames); + break; + case "o": + doy = getNumber("o"); + break; + case "m": + month = getNumber("m"); + break; + case "M": + month = getName("M", monthNamesShort, monthNames); + break; + case "y": + year = getNumber("y"); + break; + case "@": + date = new Date(getNumber("@")); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "!": + date = new Date((getNumber("!") - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")){ + checkLiteral(); + } else { + literal = true; + } + break; + default: + checkLiteral(); + } + } + } + + if (iValue < value.length){ + extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw "Extra/unparsed characters found in date: " + extra; + } + } + + if (year === -1) { + year = new Date().getFullYear(); + } else if (year < 100) { + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + } + + if (doy > -1) { + month = 1; + day = doy; + do { + dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) { + break; + } + month++; + day -= dim; + } while (true); + } + + date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw "Invalid date"; // E.g. 31/02/00 + } + return date; + }, + + /* Standard date formats. */ + ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) + COOKIE: "D, dd M yy", + ISO_8601: "yy-mm-dd", + RFC_822: "D, d M y", + RFC_850: "DD, dd-M-y", + RFC_1036: "D, d M y", + RFC_1123: "D, d M yy", + RFC_2822: "D, d M yy", + RSS: "D, d M y", // RFC 822 + TICKS: "!", + TIMESTAMP: "@", + W3C: "yy-mm-dd", // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * "..." - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ + formatDate: function (format, date, settings) { + if (!date) { + return ""; + } + + var iFormat, + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Format a number, with leading zero if necessary + formatNumber = function(match, value, len) { + var num = "" + value; + if (lookAhead(match)) { + while (num.length < len) { + num = "0" + num; + } + } + return num; + }, + // Format a name, short or long as requested + formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }, + output = "", + literal = false; + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + output += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + output += formatNumber("d", date.getDate(), 2); + break; + case "D": + output += formatName("D", date.getDay(), dayNamesShort, dayNames); + break; + case "o": + output += formatNumber("o", + Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case "m": + output += formatNumber("m", date.getMonth() + 1, 2); + break; + case "M": + output += formatName("M", date.getMonth(), monthNamesShort, monthNames); + break; + case "y": + output += (lookAhead("y") ? date.getFullYear() : + (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); + break; + case "@": + output += date.getTime(); + break; + case "!": + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) { + output += "'"; + } else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); + } + } + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var iFormat, + chars = "", + literal = false, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + chars += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": case "m": case "y": case "@": + chars += "0123456789"; + break; + case "D": case "M": + return null; // Accept anything + case "'": + if (lookAhead("'")) { + chars += "'"; + } else { + literal = true; + } + break; + default: + chars += format.charAt(iFormat); + } + } + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() === inst.lastVal) { + return; + } + + var dateFormat = this._get(inst, "dateFormat"), + dates = inst.lastVal = inst.input ? inst.input.val() : null, + defaultDate = this._getDefaultDate(inst), + date = defaultDate, + settings = this._getFormatConfig(inst); + + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + dates = (noDefault ? "" : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }, + offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(), + year = date.getFullYear(), + month = date.getMonth(), + day = date.getDate(), + pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, + matches = pattern.exec(offset); + + while (matches) { + switch (matches[2] || "d") { + case "d" : case "D" : + day += parseInt(matches[1],10); break; + case "w" : case "W" : + day += parseInt(matches[1],10) * 7; break; + case "m" : case "M" : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case "y": case "Y" : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }, + newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : + (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + + newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); + if (newDate) { + newDate.setHours(0); + newDate.setMinutes(0); + newDate.setSeconds(0); + newDate.setMilliseconds(0); + } + return this._daylightSavingAdjust(newDate); + }, + + /* Handle switch to/from daylight saving. + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ + _daylightSavingAdjust: function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !date, + origMonth = inst.selectedMonth, + origYear = inst.selectedYear, + newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + + inst.selectedDay = inst.currentDay = newDate.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); + if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { + this._notifyChange(inst); + } + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? "" : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Attach the onxxx handlers. These are declared statically so + * they work with static code transformers like Caja. + */ + _attachHandlers: function(inst) { + var stepMonths = this._get(inst, "stepMonths"), + id = "#" + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find("[data-handler]").map(function () { + var handler = { + prev: function () { + window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, -stepMonths, "M"); + }, + next: function () { + window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, +stepMonths, "M"); + }, + hide: function () { + window["DP_jQuery_" + dpuuid].datepicker._hideDatepicker(); + }, + today: function () { + window["DP_jQuery_" + dpuuid].datepicker._gotoToday(id); + }, + selectDay: function () { + window["DP_jQuery_" + dpuuid].datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); + return false; + }, + selectMonth: function () { + window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "M"); + return false; + }, + selectYear: function () { + window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "Y"); + return false; + } + }; + $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); + }); + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, + controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, + monthNames, monthNamesShort, beforeShowDay, showOtherMonths, + selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, + cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, + printDate, dRow, tbody, daySettings, otherMonth, unselectable, + tempDate = new Date(), + today = this._daylightSavingAdjust( + new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time + isRTL = this._get(inst, "isRTL"), + showButtonPanel = this._get(inst, "showButtonPanel"), + hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), + navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), + numMonths = this._getNumberOfMonths(inst), + showCurrentAtPos = this._get(inst, "showCurrentAtPos"), + stepMonths = this._get(inst, "stepMonths"), + isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), + currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + drawMonth = inst.drawMonth - showCurrentAtPos, + drawYear = inst.drawYear; + + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + + prevText = this._get(inst, "prevText"); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + + prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + + " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>")); + + nextText = this._get(inst, "nextText"); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + + next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + + " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" : + (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>")); + + currentText = this._get(inst, "currentText"); + gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + + controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + + this._get(inst, "closeText") + "</button>" : ""); + + buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") + + (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + + ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : ""; + + firstDay = parseInt(this._get(inst, "firstDay"),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + + showWeek = this._get(inst, "showWeek"); + dayNames = this._get(inst, "dayNames"); + dayNamesMin = this._get(inst, "dayNamesMin"); + monthNames = this._get(inst, "monthNames"); + monthNamesShort = this._get(inst, "monthNamesShort"); + beforeShowDay = this._get(inst, "beforeShowDay"); + showOtherMonths = this._get(inst, "showOtherMonths"); + selectOtherMonths = this._get(inst, "selectOtherMonths"); + defaultDate = this._getDefaultDate(inst); + html = ""; + dow; + for (row = 0; row < numMonths[0]; row++) { + group = ""; + this.maxRows = 4; + for (col = 0; col < numMonths[1]; col++) { + selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + cornerClass = " ui-corner-all"; + calender = ""; + if (isMultiMonth) { + calender += "<div class='ui-datepicker-group"; + if (numMonths[1] > 1) { + switch (col) { + case 0: calender += " ui-datepicker-group-first"; + cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break; + case numMonths[1]-1: calender += " ui-datepicker-group-last"; + cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break; + default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; + } + } + calender += "'>"; + } + calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + "</div><table class='ui-datepicker-calendar'><thead>" + + "<tr>"; + thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>"; + } + calender += thead + "</tr></thead><tbody>"; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += "<tr>"; + tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" + + this._get(inst, "calculateWeek")(printDate) + "</td>"); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += "<td class='" + + ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends + (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months + ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key + (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ? + // or defaultDate is current printedDate and defaultDate is selectedDate + " " + this._dayOverClass : "") + // highlight selected day + (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days + (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates + (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day + (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different) + ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title + (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + + (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") + + (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day + (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months + "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + "</tr>"; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += "</tbody></table>" + (isMultiMonth ? "</div>" + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : ""); + group += calender; + } + html += group; + } + html += buttonPanel; + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "<div class='ui-datepicker-title'>", + monthHtml = ""; + + // month selection + if (secondary || !changeMonth) { + monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>"; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; + for ( month = 0; month < 12; month++) { + if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) { + monthHtml += "<option value='" + month + "'" + + (month === drawMonth ? " selected='selected'" : "") + + ">" + monthNamesShort[month] + "</option>"; + } + } + monthHtml += "</select>"; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; + } else { + // determine range of years to display + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; + for (; year <= endYear; year++) { + inst.yearshtml += "<option value='" + year + "'" + + (year === drawYear ? " selected='selected'" : "") + + ">" + year + "</option>"; + } + inst.yearshtml += "</select>"; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "</div>"; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period === "M" || period === "Y") { + this._notifyChange(inst); + } + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + } + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + + if (offset < 0) { + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10); + maxYear = parseInt(yearSplit[1], 10); + if ( yearSplit[0].match(/[+\-].*/) ) { + minYear += currentYear; + } + if ( yearSplit[1].match(/[+\-].*/) ) { + maxYear += currentYear; + } + } + + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day === "object" ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function bindHover(dpDiv) { + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } + }) + .delegate(selector, "mouseover", function(){ + if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } + } + }); +} + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) { + if (props[name] == null) { + target[name] = props[name]; + } + } + return target; +} + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + return this.each(function() { + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.10.2"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window["DP_jQuery_" + dpuuid] = $; + +})(jQuery); + +(function( $, undefined ) { + +var sizeRelatedOptions = { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + resizableRelatedOptions = { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }; + +$.widget( "ui.dialog", { + version: "1.10.2", + options: { + appendTo: "body", + autoOpen: true, + buttons: [], + closeOnEscape: true, + closeText: "close", + dialogClass: "", + draggable: true, + hide: null, + height: "auto", + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + // Ensure the titlebar is always visible + using: function( pos ) { + var topOffset = $( this ).css( pos ).offset().top; + if ( topOffset < 0 ) { + $( this ).css( "top", pos.top - topOffset ); + } + } + }, + resizable: true, + show: null, + title: null, + width: 300, + + // callbacks + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + }, + + _create: function() { + this.originalCss = { + display: this.element[0].style.display, + width: this.element[0].style.width, + minHeight: this.element[0].style.minHeight, + maxHeight: this.element[0].style.maxHeight, + height: this.element[0].style.height + }; + this.originalPosition = { + parent: this.element.parent(), + index: this.element.parent().children().index( this.element ) + }; + this.originalTitle = this.element.attr("title"); + this.options.title = this.options.title || this.originalTitle; + + this._createWrapper(); + + this.element + .show() + .removeAttr("title") + .addClass("ui-dialog-content ui-widget-content") + .appendTo( this.uiDialog ); + + this._createTitlebar(); + this._createButtonPane(); + + if ( this.options.draggable && $.fn.draggable ) { + this._makeDraggable(); + } + if ( this.options.resizable && $.fn.resizable ) { + this._makeResizable(); + } + + this._isOpen = false; + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + if ( element && (element.jquery || element.nodeType) ) { + return $( element ); + } + return this.document.find( element || "body" ).eq( 0 ); + }, + + _destroy: function() { + var next, + originalPosition = this.originalPosition; + + this._destroyOverlay(); + + this.element + .removeUniqueId() + .removeClass("ui-dialog-content ui-widget-content") + .css( this.originalCss ) + // Without detaching first, the following becomes really slow + .detach(); + + this.uiDialog.stop( true, true ).remove(); + + if ( this.originalTitle ) { + this.element.attr( "title", this.originalTitle ); + } + + next = originalPosition.parent.children().eq( originalPosition.index ); + // Don't try to place the dialog next to itself (#8613) + if ( next.length && next[0] !== this.element[0] ) { + next.before( this.element ); + } else { + originalPosition.parent.append( this.element ); + } + }, + + widget: function() { + return this.uiDialog; + }, + + disable: $.noop, + enable: $.noop, + + close: function( event ) { + var that = this; + + if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { + return; + } + + this._isOpen = false; + this._destroyOverlay(); + + if ( !this.opener.filter(":focusable").focus().length ) { + // Hiding a focused element doesn't trigger blur in WebKit + // so in case we have nothing to focus on, explicitly blur the active element + // https://bugs.webkit.org/show_bug.cgi?id=47182 + $( this.document[0].activeElement ).blur(); + } + + this._hide( this.uiDialog, this.options.hide, function() { + that._trigger( "close", event ); + }); + }, + + isOpen: function() { + return this._isOpen; + }, + + moveToTop: function() { + this._moveToTop(); + }, + + _moveToTop: function( event, silent ) { + var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length; + if ( moved && !silent ) { + this._trigger( "focus", event ); + } + return moved; + }, + + open: function() { + var that = this; + if ( this._isOpen ) { + if ( this._moveToTop() ) { + this._focusTabbable(); + } + return; + } + + this._isOpen = true; + this.opener = $( this.document[0].activeElement ); + + this._size(); + this._position(); + this._createOverlay(); + this._moveToTop( null, true ); + this._show( this.uiDialog, this.options.show, function() { + that._focusTabbable(); + that._trigger("focus"); + }); + + this._trigger("open"); + }, + + _focusTabbable: function() { + // Set focus to the first match: + // 1. First element inside the dialog matching [autofocus] + // 2. Tabbable element inside the content element + // 3. Tabbable element inside the buttonpane + // 4. The close button + // 5. The dialog itself + var hasFocus = this.element.find("[autofocus]"); + if ( !hasFocus.length ) { + hasFocus = this.element.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogButtonPane.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogTitlebarClose.filter(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialog; + } + hasFocus.eq( 0 ).focus(); + }, + + _keepFocus: function( event ) { + function checkFocus() { + var activeElement = this.document[0].activeElement, + isActive = this.uiDialog[0] === activeElement || + $.contains( this.uiDialog[0], activeElement ); + if ( !isActive ) { + this._focusTabbable(); + } + } + event.preventDefault(); + checkFocus.call( this ); + // support: IE + // IE <= 8 doesn't prevent moving focus even with event.preventDefault() + // so we check again later + this._delay( checkFocus ); + }, + + _createWrapper: function() { + this.uiDialog = $("<div>") + .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + + this.options.dialogClass ) + .hide() + .attr({ + // Setting tabIndex makes the div focusable + tabIndex: -1, + role: "dialog" + }) + .appendTo( this._appendTo() ); + + this._on( this.uiDialog, { + keydown: function( event ) { + if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + event.preventDefault(); + this.close( event ); + return; + } + + // prevent tabbing out of dialogs + if ( event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + var tabbables = this.uiDialog.find(":tabbable"), + first = tabbables.filter(":first"), + last = tabbables.filter(":last"); + + if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { + first.focus( 1 ); + event.preventDefault(); + } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { + last.focus( 1 ); + event.preventDefault(); + } + }, + mousedown: function( event ) { + if ( this._moveToTop( event ) ) { + this._focusTabbable(); + } + } + }); + + // We assume that any existing aria-describedby attribute means + // that the dialog content is marked up properly + // otherwise we brute force the content as the description + if ( !this.element.find("[aria-describedby]").length ) { + this.uiDialog.attr({ + "aria-describedby": this.element.uniqueId().attr("id") + }); + } + }, + + _createTitlebar: function() { + var uiDialogTitle; + + this.uiDialogTitlebar = $("<div>") + .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix") + .prependTo( this.uiDialog ); + this._on( this.uiDialogTitlebar, { + mousedown: function( event ) { + // Don't prevent click on close button (#8838) + // Focusing a dialog that is partially scrolled out of view + // causes the browser to scroll it into view, preventing the click event + if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) { + // Dialog isn't getting focus when dragging (#8063) + this.uiDialog.focus(); + } + } + }); + + this.uiDialogTitlebarClose = $("<button></button>") + .button({ + label: this.options.closeText, + icons: { + primary: "ui-icon-closethick" + }, + text: false + }) + .addClass("ui-dialog-titlebar-close") + .appendTo( this.uiDialogTitlebar ); + this._on( this.uiDialogTitlebarClose, { + click: function( event ) { + event.preventDefault(); + this.close( event ); + } + }); + + uiDialogTitle = $("<span>") + .uniqueId() + .addClass("ui-dialog-title") + .prependTo( this.uiDialogTitlebar ); + this._title( uiDialogTitle ); + + this.uiDialog.attr({ + "aria-labelledby": uiDialogTitle.attr("id") + }); + }, + + _title: function( title ) { + if ( !this.options.title ) { + title.html(" "); + } + title.text( this.options.title ); + }, + + _createButtonPane: function() { + this.uiDialogButtonPane = $("<div>") + .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"); + + this.uiButtonSet = $("<div>") + .addClass("ui-dialog-buttonset") + .appendTo( this.uiDialogButtonPane ); + + this._createButtons(); + }, + + _createButtons: function() { + var that = this, + buttons = this.options.buttons; + + // if we already have a button pane, remove it + this.uiDialogButtonPane.remove(); + this.uiButtonSet.empty(); + + if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { + this.uiDialog.removeClass("ui-dialog-buttons"); + return; + } + + $.each( buttons, function( name, props ) { + var click, buttonOptions; + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + // Change the context for the click callback to be the main element + click = props.click; + props.click = function() { + click.apply( that.element[0], arguments ); + }; + buttonOptions = { + icons: props.icons, + text: props.showText + }; + delete props.icons; + delete props.showText; + $( "<button></button>", props ) + .button( buttonOptions ) + .appendTo( that.uiButtonSet ); + }); + this.uiDialog.addClass("ui-dialog-buttons"); + this.uiDialogButtonPane.appendTo( this.uiDialog ); + }, + + _makeDraggable: function() { + var that = this, + options = this.options; + + function filteredUi( ui ) { + return { + position: ui.position, + offset: ui.offset + }; + } + + this.uiDialog.draggable({ + cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", + handle: ".ui-dialog-titlebar", + containment: "document", + start: function( event, ui ) { + $( this ).addClass("ui-dialog-dragging"); + that._blockFrames(); + that._trigger( "dragStart", event, filteredUi( ui ) ); + }, + drag: function( event, ui ) { + that._trigger( "drag", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.position = [ + ui.position.left - that.document.scrollLeft(), + ui.position.top - that.document.scrollTop() + ]; + $( this ).removeClass("ui-dialog-dragging"); + that._unblockFrames(); + that._trigger( "dragStop", event, filteredUi( ui ) ); + } + }); + }, + + _makeResizable: function() { + var that = this, + options = this.options, + handles = options.resizable, + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = this.uiDialog.css("position"), + resizeHandles = typeof handles === "string" ? + handles : + "n,e,s,w,se,sw,ne,nw"; + + function filteredUi( ui ) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + this.uiDialog.resizable({ + cancel: ".ui-dialog-content", + containment: "document", + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: this._minHeight(), + handles: resizeHandles, + start: function( event, ui ) { + $( this ).addClass("ui-dialog-resizing"); + that._blockFrames(); + that._trigger( "resizeStart", event, filteredUi( ui ) ); + }, + resize: function( event, ui ) { + that._trigger( "resize", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.height = $( this ).height(); + options.width = $( this ).width(); + $( this ).removeClass("ui-dialog-resizing"); + that._unblockFrames(); + that._trigger( "resizeStop", event, filteredUi( ui ) ); + } + }) + .css( "position", position ); + }, + + _minHeight: function() { + var options = this.options; + + return options.height === "auto" ? + options.minHeight : + Math.min( options.minHeight, options.height ); + }, + + _position: function() { + // Need to show the dialog to get the actual offset in the position plugin + var isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( this.options.position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var that = this, + resize = false, + resizableOptions = {}; + + $.each( options, function( key, value ) { + that._setOption( key, value ); + + if ( key in sizeRelatedOptions ) { + resize = true; + } + if ( key in resizableRelatedOptions ) { + resizableOptions[ key ] = value; + } + }); + + if ( resize ) { + this._size(); + this._position(); + } + if ( this.uiDialog.is(":data(ui-resizable)") ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function( key, value ) { + /*jshint maxcomplexity:15*/ + var isDraggable, isResizable, + uiDialog = this.uiDialog; + + if ( key === "dialogClass" ) { + uiDialog + .removeClass( this.options.dialogClass ) + .addClass( value ); + } + + if ( key === "disabled" ) { + return; + } + + this._super( key, value ); + + if ( key === "appendTo" ) { + this.uiDialog.appendTo( this._appendTo() ); + } + + if ( key === "buttons" ) { + this._createButtons(); + } + + if ( key === "closeText" ) { + this.uiDialogTitlebarClose.button({ + // Ensure that we always pass a string + label: "" + value + }); + } + + if ( key === "draggable" ) { + isDraggable = uiDialog.is(":data(ui-draggable)"); + if ( isDraggable && !value ) { + uiDialog.draggable("destroy"); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + } + + if ( key === "position" ) { + this._position(); + } + + if ( key === "resizable" ) { + // currently resizable, becoming non-resizable + isResizable = uiDialog.is(":data(ui-resizable)"); + if ( isResizable && !value ) { + uiDialog.resizable("destroy"); + } + + // currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable(); + } + } + + if ( key === "title" ) { + this._title( this.uiDialogTitlebar.find(".ui-dialog-title") ); + } + }, + + _size: function() { + // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + // divs will both have width and height set, so we need to reset them + var nonContentHeight, minContentHeight, maxContentHeight, + options = this.options; + + // Reset content sizing + this.element.show().css({ + width: "auto", + minHeight: 0, + maxHeight: "none", + height: 0 + }); + + if ( options.minWidth > options.width ) { + options.width = options.minWidth; + } + + // reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css({ + height: "auto", + width: options.width + }) + .outerHeight(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + maxContentHeight = typeof options.maxHeight === "number" ? + Math.max( 0, options.maxHeight - nonContentHeight ) : + "none"; + + if ( options.height === "auto" ) { + this.element.css({ + minHeight: minContentHeight, + maxHeight: maxContentHeight, + height: "auto" + }); + } else { + this.element.height( Math.max( 0, options.height - nonContentHeight ) ); + } + + if (this.uiDialog.is(":data(ui-resizable)") ) { + this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); + } + }, + + _blockFrames: function() { + this.iframeBlocks = this.document.find( "iframe" ).map(function() { + var iframe = $( this ); + + return $( "<div>" ) + .css({ + position: "absolute", + width: iframe.outerWidth(), + height: iframe.outerHeight() + }) + .appendTo( iframe.parent() ) + .offset( iframe.offset() )[0]; + }); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; + } + }, + + _allowInteraction: function( event ) { + if ( $( event.target ).closest(".ui-dialog").length ) { + return true; + } + + // TODO: Remove hack when datepicker implements + // the .ui-front logic (#8989) + return !!$( event.target ).closest(".ui-datepicker").length; + }, + + _createOverlay: function() { + if ( !this.options.modal ) { + return; + } + + var that = this, + widgetFullName = this.widgetFullName; + if ( !$.ui.dialog.overlayInstances ) { + // Prevent use of anchors and inputs. + // We use a delay in case the overlay is created from an + // event that we're going to be cancelling. (#2804) + this._delay(function() { + // Handle .dialog().dialog("close") (#4065) + if ( $.ui.dialog.overlayInstances ) { + this.document.bind( "focusin.dialog", function( event ) { + if ( !that._allowInteraction( event ) ) { + event.preventDefault(); + $(".ui-dialog:visible:last .ui-dialog-content") + .data( widgetFullName )._focusTabbable(); + } + }); + } + }); + } + + this.overlay = $("<div>") + .addClass("ui-widget-overlay ui-front") + .appendTo( this._appendTo() ); + this._on( this.overlay, { + mousedown: "_keepFocus" + }); + $.ui.dialog.overlayInstances++; + }, + + _destroyOverlay: function() { + if ( !this.options.modal ) { + return; + } + + if ( this.overlay ) { + $.ui.dialog.overlayInstances--; + + if ( !$.ui.dialog.overlayInstances ) { + this.document.unbind( "focusin.dialog" ); + } + this.overlay.remove(); + this.overlay = null; + } + } +}); + +$.ui.dialog.overlayInstances = 0; + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // position option with array notation + // just override with old implementation + $.widget( "ui.dialog", $.ui.dialog, { + _position: function() { + var position = this.options.position, + myAt = [], + offset = [ 0, 0 ], + isVisible; + + if ( position ) { + if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { + myAt = position.split ? position.split(" ") : [ position[0], position[1] ]; + if ( myAt.length === 1 ) { + myAt[1] = myAt[0]; + } + + $.each( [ "left", "top" ], function( i, offsetPosition ) { + if ( +myAt[ i ] === myAt[ i ] ) { + offset[ i ] = myAt[ i ]; + myAt[ i ] = offsetPosition; + } + }); + + position = { + my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + + myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), + at: myAt.join(" ") + }; + } + + position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); + } else { + position = $.ui.dialog.prototype.options.position; + } + + // need to show the dialog to get the actual offset in the position plugin + isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + } + }); +} + +}( jQuery ) ); + +(function( $, undefined ) { + +var rvertical = /up|down|vertical/, + rpositivemotion = /up|left|vertical|horizontal/; + +$.effects.effect.blind = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + direction = o.direction || "up", + vertical = rvertical.test( direction ), + ref = vertical ? "height" : "width", + ref2 = vertical ? "top" : "left", + motion = rpositivemotion.test( direction ), + animation = {}, + show = mode === "show", + wrapper, distance, margin; + + // if already wrapped, the wrapper's properties are my property. #6245 + if ( el.parent().is( ".ui-effects-wrapper" ) ) { + $.effects.save( el.parent(), props ); + } else { + $.effects.save( el, props ); + } + el.show(); + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + distance = wrapper[ ref ](); + margin = parseFloat( wrapper.css( ref2 ) ) || 0; + + animation[ ref ] = show ? distance : 0; + if ( !motion ) { + el + .css( vertical ? "bottom" : "right", 0 ) + .css( vertical ? "top" : "left", "auto" ) + .css({ position: "absolute" }); + + animation[ ref2 ] = show ? margin : distance + margin; + } + + // start at 0 if we are showing + if ( show ) { + wrapper.css( ref, 0 ); + if ( ! motion ) { + wrapper.css( ref2, margin + distance ); + } + } + + // Animate + wrapper.animate( animation, { + duration: o.duration, + easing: o.easing, + queue: false, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.bounce = function( o, done ) { + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + + // defaults: + mode = $.effects.setMode( el, o.mode || "effect" ), + hide = mode === "hide", + show = mode === "show", + direction = o.direction || "up", + distance = o.distance, + times = o.times || 5, + + // number of internal animations + anims = times * 2 + ( show || hide ? 1 : 0 ), + speed = o.duration / anims, + easing = o.easing, + + // utility: + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ), + i, + upAnim, + downAnim, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + // Avoid touching opacity to prevent clearType and PNG issues in IE + if ( show || hide ) { + props.push( "opacity" ); + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); // Create Wrapper + + // default distance for the BIGGEST bounce is the outer Distance / 3 + if ( !distance ) { + distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; + } + + if ( show ) { + downAnim = { opacity: 1 }; + downAnim[ ref ] = 0; + + // if we are showing, force opacity 0 and set the initial position + // then do the "first" animation + el.css( "opacity", 0 ) + .css( ref, motion ? -distance * 2 : distance * 2 ) + .animate( downAnim, speed, easing ); + } + + // start at the smallest distance if we are hiding + if ( hide ) { + distance = distance / Math.pow( 2, times - 1 ); + } + + downAnim = {}; + downAnim[ ref ] = 0; + // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here + for ( i = 0; i < times; i++ ) { + upAnim = {}; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ) + .animate( downAnim, speed, easing ); + + distance = hide ? distance * 2 : distance / 2; + } + + // Last Bounce when Hiding + if ( hide ) { + upAnim = { opacity: 0 }; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + el.animate( upAnim, speed, easing ); + } + + el.queue(function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.clip = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "vertical", + vert = direction === "vertical", + size = vert ? "height" : "width", + position = vert ? "top" : "left", + animation = {}, + wrapper, animate, distance; + + // Save & Show + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + animate = ( el[0].tagName === "IMG" ) ? wrapper : el; + distance = animate[ size ](); + + // Shift + if ( show ) { + animate.css( size, 0 ); + animate.css( position, distance / 2 ); + } + + // Create Animation Object: + animation[ size ] = show ? distance : 0; + animation[ position ] = show ? 0 : distance / 2; + + // Animate + animate.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( !show ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.drop = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + direction = o.direction || "left", + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", + animation = { + opacity: show ? 1 : 0 + }, + distance; + + // Adjust + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2; + + if ( show ) { + el + .css( "opacity", 0 ) + .css( ref, motion === "pos" ? -distance : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( motion === "pos" ? "+=" : "-=" ) : + ( motion === "pos" ? "-=" : "+=" ) ) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.explode = function( o, done ) { + + var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, + cells = rows, + el = $( this ), + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + + // show and then visibility:hidden the element before calculating offset + offset = el.show().css( "visibility", "hidden" ).offset(), + + // width and height of a piece + width = Math.ceil( el.outerWidth() / cells ), + height = Math.ceil( el.outerHeight() / rows ), + pieces = [], + + // loop + i, j, left, top, mx, my; + + // children animate complete: + function childComplete() { + pieces.push( this ); + if ( pieces.length === rows * cells ) { + animComplete(); + } + } + + // clone the element for each row and cell. + for( i = 0; i < rows ; i++ ) { // ===> + top = offset.top + i * height; + my = i - ( rows - 1 ) / 2 ; + + for( j = 0; j < cells ; j++ ) { // ||| + left = offset.left + j * width; + mx = j - ( cells - 1 ) / 2 ; + + // Create a clone of the now hidden main element that will be absolute positioned + // within a wrapper div off the -left and -top equal to size of our pieces + el + .clone() + .appendTo( "body" ) + .wrap( "<div></div>" ) + .css({ + position: "absolute", + visibility: "visible", + left: -j * width, + top: -i * height + }) + + // select the wrapper - make it overflow: hidden and absolute positioned based on + // where the original was located +left and +top equal to the size of pieces + .parent() + .addClass( "ui-effects-explode" ) + .css({ + position: "absolute", + overflow: "hidden", + width: width, + height: height, + left: left + ( show ? mx * width : 0 ), + top: top + ( show ? my * height : 0 ), + opacity: show ? 0 : 1 + }).animate({ + left: left + ( show ? 0 : mx * width ), + top: top + ( show ? 0 : my * height ), + opacity: show ? 1 : 0 + }, o.duration || 500, o.easing, childComplete ); + } + } + + function animComplete() { + el.css({ + visibility: "visible" + }); + $( pieces ).remove(); + if ( !show ) { + el.hide(); + } + done(); + } +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.fade = function( o, done ) { + var el = $( this ), + mode = $.effects.setMode( el, o.mode || "toggle" ); + + el.animate({ + opacity: mode + }, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: done + }); +}; + +})( jQuery ); + +(function( $, undefined ) { + +$.effects.effect.fold = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "hide" ), + show = mode === "show", + hide = mode === "hide", + size = o.size || 15, + percent = /([0-9]+)%/.exec( size ), + horizFirst = !!o.horizFirst, + widthFirst = show !== horizFirst, + ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], + duration = o.duration / 2, + wrapper, distance, + animation1 = {}, + animation2 = {}; + + $.effects.save( el, props ); + el.show(); + + // Create Wrapper + wrapper = $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + distance = widthFirst ? + [ wrapper.width(), wrapper.height() ] : + [ wrapper.height(), wrapper.width() ]; + + if ( percent ) { + size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; + } + if ( show ) { + wrapper.css( horizFirst ? { + height: 0, + width: size + } : { + height: size, + width: 0 + }); + } + + // Animation + animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; + animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; + + // Animate + wrapper + .animate( animation1, duration, o.easing ) + .animate( animation2, duration, o.easing, function() { + if ( hide ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.highlight = function( o, done ) { + var elem = $( this ), + props = [ "backgroundImage", "backgroundColor", "opacity" ], + mode = $.effects.setMode( elem, o.mode || "show" ), + animation = { + backgroundColor: elem.css( "backgroundColor" ) + }; + + if (mode === "hide") { + animation.opacity = 0; + } + + $.effects.save( elem, props ); + + elem + .show() + .css({ + backgroundImage: "none", + backgroundColor: o.color || "#ffff99" + }) + .animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + elem.hide(); + } + $.effects.restore( elem, props ); + done(); + } + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.pulsate = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "show" ), + show = mode === "show", + hide = mode === "hide", + showhide = ( show || mode === "hide" ), + + // showing or hiding leaves of the "last" animation + anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), + duration = o.duration / anims, + animateTo = 0, + queue = elem.queue(), + queuelen = queue.length, + i; + + if ( show || !elem.is(":visible")) { + elem.css( "opacity", 0 ).show(); + animateTo = 1; + } + + // anims - 1 opacity "toggles" + for ( i = 1; i < anims; i++ ) { + elem.animate({ + opacity: animateTo + }, duration, o.easing ); + animateTo = 1 - animateTo; + } + + elem.animate({ + opacity: animateTo + }, duration, o.easing); + + elem.queue(function() { + if ( hide ) { + elem.hide(); + } + done(); + }); + + // We just queued up "anims" animations, we need to put them next in the queue + if ( queuelen > 1 ) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + elem.dequeue(); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.puff = function( o, done ) { + var elem = $( this ), + mode = $.effects.setMode( elem, o.mode || "hide" ), + hide = mode === "hide", + percent = parseInt( o.percent, 10 ) || 150, + factor = percent / 100, + original = { + height: elem.height(), + width: elem.width(), + outerHeight: elem.outerHeight(), + outerWidth: elem.outerWidth() + }; + + $.extend( o, { + effect: "scale", + queue: false, + fade: true, + mode: mode, + complete: done, + percent: hide ? percent : 100, + from: hide ? + original : + { + height: original.height * factor, + width: original.width * factor, + outerHeight: original.outerHeight * factor, + outerWidth: original.outerWidth * factor + } + }); + + elem.effect( o ); +}; + +$.effects.effect.scale = function( o, done ) { + + // Create element + var el = $( this ), + options = $.extend( true, {}, o ), + mode = $.effects.setMode( el, o.mode || "effect" ), + percent = parseInt( o.percent, 10 ) || + ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), + direction = o.direction || "both", + origin = o.origin, + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }, + factor = { + y: direction !== "horizontal" ? (percent / 100) : 1, + x: direction !== "vertical" ? (percent / 100) : 1 + }; + + // We are going to pass this effect to the size effect: + options.effect = "size"; + options.queue = false; + options.complete = done; + + // Set default origin and restore for show/hide + if ( mode !== "effect" ) { + options.origin = origin || ["middle","center"]; + options.restore = true; + } + + options.from = o.from || ( mode === "show" ? { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + } : original ); + options.to = { + height: original.height * factor.y, + width: original.width * factor.x, + outerHeight: original.outerHeight * factor.y, + outerWidth: original.outerWidth * factor.x + }; + + // Fade option to support puff + if ( options.fade ) { + if ( mode === "show" ) { + options.from.opacity = 0; + options.to.opacity = 1; + } + if ( mode === "hide" ) { + options.from.opacity = 1; + options.to.opacity = 0; + } + } + + // Animate + el.effect( options ); + +}; + +$.effects.effect.size = function( o, done ) { + + // Create element + var original, baseline, factor, + el = $( this ), + props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], + + // Always restore + props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], + + // Copy for children + props2 = [ "width", "height", "overflow" ], + cProps = [ "fontSize" ], + vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], + hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], + + // Set options + mode = $.effects.setMode( el, o.mode || "effect" ), + restore = o.restore || mode !== "effect", + scale = o.scale || "both", + origin = o.origin || [ "middle", "center" ], + position = el.css( "position" ), + props = restore ? props0 : props1, + zero = { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + }; + + if ( mode === "show" ) { + el.show(); + } + original = { + height: el.height(), + width: el.width(), + outerHeight: el.outerHeight(), + outerWidth: el.outerWidth() + }; + + if ( o.mode === "toggle" && mode === "show" ) { + el.from = o.to || zero; + el.to = o.from || original; + } else { + el.from = o.from || ( mode === "show" ? zero : original ); + el.to = o.to || ( mode === "hide" ? zero : original ); + } + + // Set scaling factor + factor = { + from: { + y: el.from.height / original.height, + x: el.from.width / original.width + }, + to: { + y: el.to.height / original.height, + x: el.to.width / original.width + } + }; + + // Scale the css box + if ( scale === "box" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( vProps ); + el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + props = props.concat( hProps ); + el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); + el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); + } + } + + // Scale the content + if ( scale === "content" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + props = props.concat( cProps ).concat( props2 ); + el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); + el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); + } + } + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + el.css( "overflow", "hidden" ).css( el.from ); + + // Adjust + if (origin) { // Calculate baseline shifts + baseline = $.effects.getBaseline( origin, original ); + el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; + el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; + el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; + el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; + } + el.css( el.from ); // set top & left + + // Animate + if ( scale === "content" || scale === "both" ) { // Scale the children + + // Add margins/font-size + vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); + hProps = hProps.concat([ "marginLeft", "marginRight" ]); + props2 = props0.concat(vProps).concat(hProps); + + el.find( "*[width]" ).each( function(){ + var child = $( this ), + c_original = { + height: child.height(), + width: child.width(), + outerHeight: child.outerHeight(), + outerWidth: child.outerWidth() + }; + if (restore) { + $.effects.save(child, props2); + } + + child.from = { + height: c_original.height * factor.from.y, + width: c_original.width * factor.from.x, + outerHeight: c_original.outerHeight * factor.from.y, + outerWidth: c_original.outerWidth * factor.from.x + }; + child.to = { + height: c_original.height * factor.to.y, + width: c_original.width * factor.to.x, + outerHeight: c_original.height * factor.to.y, + outerWidth: c_original.width * factor.to.x + }; + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); + child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); + child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); + } + + // Animate children + child.css( child.from ); + child.animate( child.to, o.duration, o.easing, function() { + + // Restore children + if ( restore ) { + $.effects.restore( child, props2 ); + } + }); + }); + } + + // Animate + el.animate( el.to, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( el.to.opacity === 0 ) { + el.css( "opacity", el.from.opacity ); + } + if( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + if ( !restore ) { + + // we need to calculate our new positioning based on the scaling + if ( position === "static" ) { + el.css({ + position: "relative", + top: el.to.top, + left: el.to.left + }); + } else { + $.each([ "top", "left" ], function( idx, pos ) { + el.css( pos, function( _, str ) { + var val = parseInt( str, 10 ), + toRef = idx ? el.to.left : el.to.top; + + // if original was "auto", recalculate the new value from wrapper + if ( str === "auto" ) { + return toRef + "px"; + } + + return val + toRef + "px"; + }); + }); + } + } + + $.effects.removeWrapper( el ); + done(); + } + }); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.shake = function( o, done ) { + + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.effects.setMode( el, o.mode || "effect" ), + direction = o.direction || "left", + distance = o.distance || 20, + times = o.times || 3, + anims = times * 2 + 1, + speed = Math.round(o.duration/anims), + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + animation = {}, + animation1 = {}, + animation2 = {}, + i, + + // we will need to re-assemble the queue to stack our animations in place + queue = el.queue(), + queuelen = queue.length; + + $.effects.save( el, props ); + el.show(); + $.effects.createWrapper( el ); + + // Animation + animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; + animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; + animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; + + // Animate + el.animate( animation, speed, o.easing ); + + // Shakes + for ( i = 1; i < times; i++ ) { + el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); + } + el + .animate( animation1, speed, o.easing ) + .animate( animation, speed / 2, o.easing ) + .queue(function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + }); + + // inject all the animations we just queued to be first in line (after "inprogress") + if ( queuelen > 1) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); + } + el.dequeue(); + +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.slide = function( o, done ) { + + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "width", "height" ], + mode = $.effects.setMode( el, o.mode || "show" ), + show = mode === "show", + direction = o.direction || "left", + ref = (direction === "up" || direction === "down") ? "top" : "left", + positiveMotion = (direction === "up" || direction === "left"), + distance, + animation = {}; + + // Adjust + $.effects.save( el, props ); + el.show(); + distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); + + $.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + if ( show ) { + el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); + } + + // Animation + animation[ ref ] = ( show ? + ( positiveMotion ? "+=" : "-=") : + ( positiveMotion ? "-=" : "+=")) + + distance; + + // Animate + el.animate( animation, { + queue: false, + duration: o.duration, + easing: o.easing, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.effects.restore( el, props ); + $.effects.removeWrapper( el ); + done(); + } + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.effects.effect.transfer = function( o, done ) { + var elem = $( this ), + target = $( o.to ), + targetFixed = target.css( "position" ) === "fixed", + body = $("body"), + fixTop = targetFixed ? body.scrollTop() : 0, + fixLeft = targetFixed ? body.scrollLeft() : 0, + endPosition = target.offset(), + animation = { + top: endPosition.top - fixTop , + left: endPosition.left - fixLeft , + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = elem.offset(), + transfer = $( "<div class='ui-effects-transfer'></div>" ) + .appendTo( document.body ) + .addClass( o.className ) + .css({ + top: startPosition.top - fixTop , + left: startPosition.left - fixLeft , + height: elem.innerHeight(), + width: elem.innerWidth(), + position: targetFixed ? "fixed" : "absolute" + }) + .animate( animation, o.duration, o.easing, function() { + transfer.remove(); + done(); + }); +}; + +})(jQuery); + +(function( $, undefined ) { + +$.widget( "ui.menu", { + version: "1.10.2", + defaultElement: "<ul>", + delay: 300, + options: { + icons: { + submenu: "ui-icon-carat-1-e" + }, + menus: "ul", + position: { + my: "left top", + at: "right top" + }, + role: "menu", + + // callbacks + blur: null, + focus: null, + select: null + }, + + _create: function() { + this.activeMenu = this.element; + // flag used to prevent firing of the click handler + // as the event bubbles up through nested menus + this.mouseHandled = false; + this.element + .uniqueId() + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) + .attr({ + role: this.options.role, + tabIndex: 0 + }) + // need to catch all clicks on disabled menu + // not possible through _on + .bind( "click" + this.eventNamespace, $.proxy(function( event ) { + if ( this.options.disabled ) { + event.preventDefault(); + } + }, this )); + + if ( this.options.disabled ) { + this.element + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } + + this._on({ + // Prevent focus from sticking to links inside menu after clicking + // them (focus should always stay on UL during navigation). + "mousedown .ui-menu-item > a": function( event ) { + event.preventDefault(); + }, + "click .ui-state-disabled > a": function( event ) { + event.preventDefault(); + }, + "click .ui-menu-item:has(a)": function( event ) { + var target = $( event.target ).closest( ".ui-menu-item" ); + if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { + this.mouseHandled = true; + + this.select( event ); + // Open submenu on click + if ( target.has( ".ui-menu" ).length ) { + this.expand( event ); + } else if ( !this.element.is( ":focus" ) ) { + // Redirect focus to the menu + this.element.trigger( "focus", [ true ] ); + + // If the active item is on the top level, let it stay active. + // Otherwise, blur the active item since it is no longer visible. + if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { + clearTimeout( this.timer ); + } + } + } + }, + "mouseenter .ui-menu-item": function( event ) { + var target = $( event.currentTarget ); + // Remove ui-state-active class from siblings of the newly focused menu item + // to avoid a jump caused by adjacent elements both having a class with a border + target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); + this.focus( event, target ); + }, + mouseleave: "collapseAll", + "mouseleave .ui-menu": "collapseAll", + focus: function( event, keepActiveItem ) { + // If there's already an active item, keep it active + // If not, activate the first item + var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 ); + + if ( !keepActiveItem ) { + this.focus( event, item ); + } + }, + blur: function( event ) { + this._delay(function() { + if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { + this.collapseAll( event ); + } + }); + }, + keydown: "_keydown" + }); + + this.refresh(); + + // Clicks outside of a menu collapse any open menus + this._on( this.document, { + click: function( event ) { + if ( !$( event.target ).closest( ".ui-menu" ).length ) { + this.collapseAll( event ); + } + + // Reset the mouseHandled flag + this.mouseHandled = false; + } + }); + }, + + _destroy: function() { + // Destroy (sub)menus + this.element + .removeAttr( "aria-activedescendant" ) + .find( ".ui-menu" ).addBack() + .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-disabled" ) + .removeUniqueId() + .show(); + + // Destroy menu items + this.element.find( ".ui-menu-item" ) + .removeClass( "ui-menu-item" ) + .removeAttr( "role" ) + .removeAttr( "aria-disabled" ) + .children( "a" ) + .removeUniqueId() + .removeClass( "ui-corner-all ui-state-hover" ) + .removeAttr( "tabIndex" ) + .removeAttr( "role" ) + .removeAttr( "aria-haspopup" ) + .children().each( function() { + var elem = $( this ); + if ( elem.data( "ui-menu-submenu-carat" ) ) { + elem.remove(); + } + }); + + // Destroy menu dividers + this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); + }, + + _keydown: function( event ) { + /*jshint maxcomplexity:20*/ + var match, prev, character, skip, regex, + preventDefault = true; + + function escape( value ) { + return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + this.previousPage( event ); + break; + case $.ui.keyCode.PAGE_DOWN: + this.nextPage( event ); + break; + case $.ui.keyCode.HOME: + this._move( "first", "first", event ); + break; + case $.ui.keyCode.END: + this._move( "last", "last", event ); + break; + case $.ui.keyCode.UP: + this.previous( event ); + break; + case $.ui.keyCode.DOWN: + this.next( event ); + break; + case $.ui.keyCode.LEFT: + this.collapse( event ); + break; + case $.ui.keyCode.RIGHT: + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + this.expand( event ); + } + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate( event ); + break; + case $.ui.keyCode.ESCAPE: + this.collapse( event ); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + character = String.fromCharCode( event.keyCode ); + skip = false; + + clearTimeout( this.filterTimer ); + + if ( character === prev ) { + skip = true; + } else { + character = prev + character; + } + + regex = new RegExp( "^" + escape( character ), "i" ); + match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { + return regex.test( $( this ).children( "a" ).text() ); + }); + match = skip && match.index( this.active.next() ) !== -1 ? + this.active.nextAll( ".ui-menu-item" ) : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if ( !match.length ) { + character = String.fromCharCode( event.keyCode ); + regex = new RegExp( "^" + escape( character ), "i" ); + match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { + return regex.test( $( this ).children( "a" ).text() ); + }); + } + + if ( match.length ) { + this.focus( event, match ); + if ( match.length > 1 ) { + this.previousFilter = character; + this.filterTimer = this._delay(function() { + delete this.previousFilter; + }, 1000 ); + } else { + delete this.previousFilter; + } + } else { + delete this.previousFilter; + } + } + + if ( preventDefault ) { + event.preventDefault(); + } + }, + + _activate: function( event ) { + if ( !this.active.is( ".ui-state-disabled" ) ) { + if ( this.active.children( "a[aria-haspopup='true']" ).length ) { + this.expand( event ); + } else { + this.select( event ); + } + } + }, + + refresh: function() { + var menus, + icon = this.options.icons.submenu, + submenus = this.element.find( this.options.menus ); + + // Initialize nested menus + submenus.filter( ":not(.ui-menu)" ) + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .hide() + .attr({ + role: this.options.role, + "aria-hidden": "true", + "aria-expanded": "false" + }) + .each(function() { + var menu = $( this ), + item = menu.prev( "a" ), + submenuCarat = $( "<span>" ) + .addClass( "ui-menu-icon ui-icon " + icon ) + .data( "ui-menu-submenu-carat", true ); + + item + .attr( "aria-haspopup", "true" ) + .prepend( submenuCarat ); + menu.attr( "aria-labelledby", item.attr( "id" ) ); + }); + + menus = submenus.add( this.element ); + + // Don't refresh list items that are already adapted + menus.children( ":not(.ui-menu-item):has(a)" ) + .addClass( "ui-menu-item" ) + .attr( "role", "presentation" ) + .children( "a" ) + .uniqueId() + .addClass( "ui-corner-all" ) + .attr({ + tabIndex: -1, + role: this._itemRole() + }); + + // Initialize unlinked menu-items containing spaces and/or dashes only as dividers + menus.children( ":not(.ui-menu-item)" ).each(function() { + var item = $( this ); + // hyphen, em dash, en dash + if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) { + item.addClass( "ui-widget-content ui-menu-divider" ); + } + }); + + // Add aria-disabled attribute to any disabled menu item + menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); + + // If the active item has been removed, blur the menu + if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + this.blur(); + } + }, + + _itemRole: function() { + return { + menu: "menuitem", + listbox: "option" + }[ this.options.role ]; + }, + + _setOption: function( key, value ) { + if ( key === "icons" ) { + this.element.find( ".ui-menu-icon" ) + .removeClass( this.options.icons.submenu ) + .addClass( value.submenu ); + } + this._super( key, value ); + }, + + focus: function( event, item ) { + var nested, focused; + this.blur( event, event && event.type === "focus" ); + + this._scrollIntoView( item ); + + this.active = item.first(); + focused = this.active.children( "a" ).addClass( "ui-state-focus" ); + // Only update aria-activedescendant if there's a role + // otherwise we assume focus is managed elsewhere + if ( this.options.role ) { + this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); + } + + // Highlight active parent menu item, if any + this.active + .parent() + .closest( ".ui-menu-item" ) + .children( "a:first" ) + .addClass( "ui-state-active" ); + + if ( event && event.type === "keydown" ) { + this._close(); + } else { + this.timer = this._delay(function() { + this._close(); + }, this.delay ); + } + + nested = item.children( ".ui-menu" ); + if ( nested.length && ( /^mouse/.test( event.type ) ) ) { + this._startOpening(nested); + } + this.activeMenu = item.parent(); + + this._trigger( "focus", event, { item: item } ); + }, + + _scrollIntoView: function( item ) { + var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; + if ( this._hasScroll() ) { + borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; + paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; + offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; + scroll = this.activeMenu.scrollTop(); + elementHeight = this.activeMenu.height(); + itemHeight = item.height(); + + if ( offset < 0 ) { + this.activeMenu.scrollTop( scroll + offset ); + } else if ( offset + itemHeight > elementHeight ) { + this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); + } + } + }, + + blur: function( event, fromFocus ) { + if ( !fromFocus ) { + clearTimeout( this.timer ); + } + + if ( !this.active ) { + return; + } + + this.active.children( "a" ).removeClass( "ui-state-focus" ); + this.active = null; + + this._trigger( "blur", event, { item: this.active } ); + }, + + _startOpening: function( submenu ) { + clearTimeout( this.timer ); + + // Don't open if already open fixes a Firefox bug that caused a .5 pixel + // shift in the submenu position when mousing over the carat icon + if ( submenu.attr( "aria-hidden" ) !== "true" ) { + return; + } + + this.timer = this._delay(function() { + this._close(); + this._open( submenu ); + }, this.delay ); + }, + + _open: function( submenu ) { + var position = $.extend({ + of: this.active + }, this.options.position ); + + clearTimeout( this.timer ); + this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) + .hide() + .attr( "aria-hidden", "true" ); + + submenu + .show() + .removeAttr( "aria-hidden" ) + .attr( "aria-expanded", "true" ) + .position( position ); + }, + + collapseAll: function( event, all ) { + clearTimeout( this.timer ); + this.timer = this._delay(function() { + // If we were passed an event, look for the submenu that contains the event + var currentMenu = all ? this.element : + $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); + + // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway + if ( !currentMenu.length ) { + currentMenu = this.element; + } + + this._close( currentMenu ); + + this.blur( event ); + this.activeMenu = currentMenu; + }, this.delay ); + }, + + // With no arguments, closes the currently active menu - if nothing is active + // it closes all menus. If passed an argument, it will search for menus BELOW + _close: function( startMenu ) { + if ( !startMenu ) { + startMenu = this.active ? this.active.parent() : this.element; + } + + startMenu + .find( ".ui-menu" ) + .hide() + .attr( "aria-hidden", "true" ) + .attr( "aria-expanded", "false" ) + .end() + .find( "a.ui-state-active" ) + .removeClass( "ui-state-active" ); + }, + + collapse: function( event ) { + var newItem = this.active && + this.active.parent().closest( ".ui-menu-item", this.element ); + if ( newItem && newItem.length ) { + this._close(); + this.focus( event, newItem ); + } + }, + + expand: function( event ) { + var newItem = this.active && + this.active + .children( ".ui-menu " ) + .children( ".ui-menu-item" ) + .first(); + + if ( newItem && newItem.length ) { + this._open( newItem.parent() ); + + // Delay so Firefox will not hide activedescendant change in expanding submenu from AT + this._delay(function() { + this.focus( event, newItem ); + }); + } + }, + + next: function( event ) { + this._move( "next", "first", event ); + }, + + previous: function( event ) { + this._move( "prev", "last", event ); + }, + + isFirstItem: function() { + return this.active && !this.active.prevAll( ".ui-menu-item" ).length; + }, + + isLastItem: function() { + return this.active && !this.active.nextAll( ".ui-menu-item" ).length; + }, + + _move: function( direction, filter, event ) { + var next; + if ( this.active ) { + if ( direction === "first" || direction === "last" ) { + next = this.active + [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) + .eq( -1 ); + } else { + next = this.active + [ direction + "All" ]( ".ui-menu-item" ) + .eq( 0 ); + } + } + if ( !next || !next.length || !this.active ) { + next = this.activeMenu.children( ".ui-menu-item" )[ filter ](); + } + + this.focus( event, next ); + }, + + nextPage: function( event ) { + var item, base, height; + + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isLastItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.nextAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base - height < 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.children( ".ui-menu-item" ) + [ !this.active ? "first" : "last" ]() ); + } + }, + + previousPage: function( event ) { + var item, base, height; + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isFirstItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.height(); + this.active.prevAll( ".ui-menu-item" ).each(function() { + item = $( this ); + return item.offset().top - base + height > 0; + }); + + this.focus( event, item ); + } else { + this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); + } + }, + + _hasScroll: function() { + return this.element.outerHeight() < this.element.prop( "scrollHeight" ); + }, + + select: function( event ) { + // TODO: It should never be possible to not have an active item at this + // point, but the tests don't trigger mouseenter before click. + this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); + var ui = { item: this.active }; + if ( !this.active.has( ".ui-menu" ).length ) { + this.collapseAll( event, true ); + } + this._trigger( "select", event, ui ); + } +}); + +}( jQuery )); + +(function( $, undefined ) { + +$.ui = $.ui || {}; + +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), + overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ); + return { + element: withinElement, + isWindow: isWindow, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: isWindow ? withinElement.width() : withinElement.outerWidth(), + height: isWindow ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !$.support.offsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem : elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } + else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { + position.top += myOffset + atOffset + offset; + } + } + else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function () { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +}( jQuery ) ); + +(function( $, undefined ) { + +$.widget( "ui.progressbar", { + version: "1.10.2", + options: { + max: 100, + value: 0, + + change: null, + complete: null + }, + + min: 0, + + _create: function() { + // Constrain initial value + this.oldValue = this.options.value = this._constrainedValue(); + + this.element + .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .attr({ + // Only set static values, aria-valuenow and aria-valuemax are + // set inside _refreshValue() + role: "progressbar", + "aria-valuemin": this.min + }); + + this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) + .appendTo( this.element ); + + this._refreshValue(); + }, + + _destroy: function() { + this.element + .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + + this.valueDiv.remove(); + }, + + value: function( newValue ) { + if ( newValue === undefined ) { + return this.options.value; + } + + this.options.value = this._constrainedValue( newValue ); + this._refreshValue(); + }, + + _constrainedValue: function( newValue ) { + if ( newValue === undefined ) { + newValue = this.options.value; + } + + this.indeterminate = newValue === false; + + // sanitize value + if ( typeof newValue !== "number" ) { + newValue = 0; + } + + return this.indeterminate ? false : + Math.min( this.options.max, Math.max( this.min, newValue ) ); + }, + + _setOptions: function( options ) { + // Ensure "value" option is set after other values (like max) + var value = options.value; + delete options.value; + + this._super( options ); + + this.options.value = this._constrainedValue( value ); + this._refreshValue(); + }, + + _setOption: function( key, value ) { + if ( key === "max" ) { + // Don't allow a max less than min + value = Math.max( this.min, value ); + } + + this._super( key, value ); + }, + + _percentage: function() { + return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); + }, + + _refreshValue: function() { + var value = this.options.value, + percentage = this._percentage(); + + this.valueDiv + .toggle( this.indeterminate || value > this.min ) + .toggleClass( "ui-corner-right", value === this.options.max ) + .width( percentage.toFixed(0) + "%" ); + + this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); + + if ( this.indeterminate ) { + this.element.removeAttr( "aria-valuenow" ); + if ( !this.overlayDiv ) { + this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv ); + } + } else { + this.element.attr({ + "aria-valuemax": this.options.max, + "aria-valuenow": value + }); + if ( this.overlayDiv ) { + this.overlayDiv.remove(); + this.overlayDiv = null; + } + } + + if ( this.oldValue !== value ) { + this.oldValue = value; + this._trigger( "change" ); + } + if ( value === this.options.max ) { + this._trigger( "complete" ); + } + } +}); + +})( jQuery ); + +(function( $, undefined ) { + +// number of pages in a slider +// (how many times can you page up/down to go through the whole range) +var numPages = 5; + +$.widget( "ui.slider", $.ui.mouse, { + version: "1.10.2", + widgetEventPrefix: "slide", + + options: { + animate: false, + distance: 0, + max: 100, + min: 0, + orientation: "horizontal", + range: false, + step: 1, + value: 0, + values: null, + + // callbacks + change: null, + slide: null, + start: null, + stop: null + }, + + _create: function() { + this._keySliding = false; + this._mouseSliding = false; + this._animateOff = true; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + + this.element + .addClass( "ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all"); + + this._refresh(); + this._setOption( "disabled", this.options.disabled ); + + this._animateOff = false; + }, + + _refresh: function() { + this._createRange(); + this._createHandles(); + this._setupEvents(); + this._refreshValue(); + }, + + _createHandles: function() { + var i, handleCount, + options = this.options, + existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), + handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", + handles = []; + + handleCount = ( options.values && options.values.length ) || 1; + + if ( existingHandles.length > handleCount ) { + existingHandles.slice( handleCount ).remove(); + existingHandles = existingHandles.slice( 0, handleCount ); + } + + for ( i = existingHandles.length; i < handleCount; i++ ) { + handles.push( handle ); + } + + this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); + + this.handle = this.handles.eq( 0 ); + + this.handles.each(function( i ) { + $( this ).data( "ui-slider-handle-index", i ); + }); + }, + + _createRange: function() { + var options = this.options, + classes = ""; + + if ( options.range ) { + if ( options.range === true ) { + if ( !options.values ) { + options.values = [ this._valueMin(), this._valueMin() ]; + } else if ( options.values.length && options.values.length !== 2 ) { + options.values = [ options.values[0], options.values[0] ]; + } else if ( $.isArray( options.values ) ) { + options.values = options.values.slice(0); + } + } + + if ( !this.range || !this.range.length ) { + this.range = $( "<div></div>" ) + .appendTo( this.element ); + + classes = "ui-slider-range" + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + " ui-widget-header ui-corner-all"; + } else { + this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) + // Handle range switching from true to min/max + .css({ + "left": "", + "bottom": "" + }); + } + + this.range.addClass( classes + + ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); + } else { + this.range = $([]); + } + }, + + _setupEvents: function() { + var elements = this.handles.add( this.range ).filter( "a" ); + this._off( elements ); + this._on( elements, this._handleEvents ); + this._hoverable( elements ); + this._focusable( elements ); + }, + + _destroy: function() { + this.handles.remove(); + this.range.remove(); + + this.element + .removeClass( "ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all" ); + + this._mouseDestroy(); + }, + + _mouseCapture: function( event ) { + var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, + that = this, + o = this.options; + + if ( o.disabled ) { + return false; + } + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + position = { x: event.pageX, y: event.pageY }; + normValue = this._normValueFromMouse( position ); + distance = this._valueMax() - this._valueMin() + 1; + this.handles.each(function( i ) { + var thisDistance = Math.abs( normValue - that.values(i) ); + if (( distance > thisDistance ) || + ( distance === thisDistance && + (i === that._lastChangedValue || that.values(i) === o.min ))) { + distance = thisDistance; + closestHandle = $( this ); + index = i; + } + }); + + allowed = this._start( event, index ); + if ( allowed === false ) { + return false; + } + this._mouseSliding = true; + + this._handleIndex = index; + + closestHandle + .addClass( "ui-state-active" ) + .focus(); + + offset = closestHandle.offset(); + mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - ( closestHandle.width() / 2 ), + top: event.pageY - offset.top - + ( closestHandle.height() / 2 ) - + ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - + ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + + ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) + }; + + if ( !this.handles.hasClass( "ui-state-hover" ) ) { + this._slide( event, index, normValue ); + } + this._animateOff = true; + return true; + }, + + _mouseStart: function() { + return true; + }, + + _mouseDrag: function( event ) { + var position = { x: event.pageX, y: event.pageY }, + normValue = this._normValueFromMouse( position ); + + this._slide( event, this._handleIndex, normValue ); + + return false; + }, + + _mouseStop: function( event ) { + this.handles.removeClass( "ui-state-active" ); + this._mouseSliding = false; + + this._stop( event, this._handleIndex ); + this._change( event, this._handleIndex ); + + this._handleIndex = null; + this._clickOffset = null; + this._animateOff = false; + + return false; + }, + + _detectOrientation: function() { + this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; + }, + + _normValueFromMouse: function( position ) { + var pixelTotal, + pixelMouse, + percentMouse, + valueTotal, + valueMouse; + + if ( this.orientation === "horizontal" ) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); + } + + percentMouse = ( pixelMouse / pixelTotal ); + if ( percentMouse > 1 ) { + percentMouse = 1; + } + if ( percentMouse < 0 ) { + percentMouse = 0; + } + if ( this.orientation === "vertical" ) { + percentMouse = 1 - percentMouse; + } + + valueTotal = this._valueMax() - this._valueMin(); + valueMouse = this._valueMin() + percentMouse * valueTotal; + + return this._trimAlignValue( valueMouse ); + }, + + _start: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + return this._trigger( "start", event, uiHash ); + }, + + _slide: function( event, index, newVal ) { + var otherVal, + newValues, + allowed; + + if ( this.options.values && this.options.values.length ) { + otherVal = this.values( index ? 0 : 1 ); + + if ( ( this.options.values.length === 2 && this.options.range === true ) && + ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) + ) { + newVal = otherVal; + } + + if ( newVal !== this.values( index ) ) { + newValues = this.values(); + newValues[ index ] = newVal; + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal, + values: newValues + } ); + otherVal = this.values( index ? 0 : 1 ); + if ( allowed !== false ) { + this.values( index, newVal, true ); + } + } + } else { + if ( newVal !== this.value() ) { + // A slide can be canceled by returning false from the slide callback + allowed = this._trigger( "slide", event, { + handle: this.handles[ index ], + value: newVal + } ); + if ( allowed !== false ) { + this.value( newVal ); + } + } + } + }, + + _stop: function( event, index ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + this._trigger( "stop", event, uiHash ); + }, + + _change: function( event, index ) { + if ( !this._keySliding && !this._mouseSliding ) { + var uiHash = { + handle: this.handles[ index ], + value: this.value() + }; + if ( this.options.values && this.options.values.length ) { + uiHash.value = this.values( index ); + uiHash.values = this.values(); + } + + //store the last changed value index for reference when handles overlap + this._lastChangedValue = index; + + this._trigger( "change", event, uiHash ); + } + }, + + value: function( newValue ) { + if ( arguments.length ) { + this.options.value = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, 0 ); + return; + } + + return this._value(); + }, + + values: function( index, newValue ) { + var vals, + newValues, + i; + + if ( arguments.length > 1 ) { + this.options.values[ index ] = this._trimAlignValue( newValue ); + this._refreshValue(); + this._change( null, index ); + return; + } + + if ( arguments.length ) { + if ( $.isArray( arguments[ 0 ] ) ) { + vals = this.options.values; + newValues = arguments[ 0 ]; + for ( i = 0; i < vals.length; i += 1 ) { + vals[ i ] = this._trimAlignValue( newValues[ i ] ); + this._change( null, i ); + } + this._refreshValue(); + } else { + if ( this.options.values && this.options.values.length ) { + return this._values( index ); + } else { + return this.value(); + } + } + } else { + return this._values(); + } + }, + + _setOption: function( key, value ) { + var i, + valsLength = 0; + + if ( key === "range" && this.options.range === true ) { + if ( value === "min" ) { + this.options.value = this._values( 0 ); + this.options.values = null; + } else if ( value === "max" ) { + this.options.value = this._values( this.options.values.length-1 ); + this.options.values = null; + } + } + + if ( $.isArray( this.options.values ) ) { + valsLength = this.options.values.length; + } + + $.Widget.prototype._setOption.apply( this, arguments ); + + switch ( key ) { + case "orientation": + this._detectOrientation(); + this.element + .removeClass( "ui-slider-horizontal ui-slider-vertical" ) + .addClass( "ui-slider-" + this.orientation ); + this._refreshValue(); + break; + case "value": + this._animateOff = true; + this._refreshValue(); + this._change( null, 0 ); + this._animateOff = false; + break; + case "values": + this._animateOff = true; + this._refreshValue(); + for ( i = 0; i < valsLength; i += 1 ) { + this._change( null, i ); + } + this._animateOff = false; + break; + case "min": + case "max": + this._animateOff = true; + this._refreshValue(); + this._animateOff = false; + break; + case "range": + this._animateOff = true; + this._refresh(); + this._animateOff = false; + break; + } + }, + + //internal value getter + // _value() returns value trimmed by min and max, aligned by step + _value: function() { + var val = this.options.value; + val = this._trimAlignValue( val ); + + return val; + }, + + //internal values getter + // _values() returns array of values trimmed by min and max, aligned by step + // _values( index ) returns single value trimmed by min and max, aligned by step + _values: function( index ) { + var val, + vals, + i; + + if ( arguments.length ) { + val = this.options.values[ index ]; + val = this._trimAlignValue( val ); + + return val; + } else if ( this.options.values && this.options.values.length ) { + // .slice() creates a copy of the array + // this copy gets trimmed by min and max and then returned + vals = this.options.values.slice(); + for ( i = 0; i < vals.length; i+= 1) { + vals[ i ] = this._trimAlignValue( vals[ i ] ); + } + + return vals; + } else { + return []; + } + }, + + // returns the step-aligned value that val is closest to, between (inclusive) min and max + _trimAlignValue: function( val ) { + if ( val <= this._valueMin() ) { + return this._valueMin(); + } + if ( val >= this._valueMax() ) { + return this._valueMax(); + } + var step = ( this.options.step > 0 ) ? this.options.step : 1, + valModStep = (val - this._valueMin()) % step, + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat( alignValue.toFixed(5) ); + }, + + _valueMin: function() { + return this.options.min; + }, + + _valueMax: function() { + return this.options.max; + }, + + _refreshValue: function() { + var lastValPercent, valPercent, value, valueMin, valueMax, + oRange = this.options.range, + o = this.options, + that = this, + animate = ( !this._animateOff ) ? o.animate : false, + _set = {}; + + if ( this.options.values && this.options.values.length ) { + this.handles.each(function( i ) { + valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; + _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + if ( that.options.range === true ) { + if ( that.orientation === "horizontal" ) { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } else { + if ( i === 0 ) { + that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); + } + if ( i === 1 ) { + that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + } + lastValPercent = valPercent; + }); + } else { + value = this.value(); + valueMin = this._valueMin(); + valueMax = this._valueMax(); + valPercent = ( valueMax !== valueMin ) ? + ( value - valueMin ) / ( valueMax - valueMin ) * 100 : + 0; + _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; + this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); + + if ( oRange === "min" && this.orientation === "horizontal" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "horizontal" ) { + this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + if ( oRange === "min" && this.orientation === "vertical" ) { + this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); + } + if ( oRange === "max" && this.orientation === "vertical" ) { + this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); + } + } + }, + + _handleEvents: { + keydown: function( event ) { + /*jshint maxcomplexity:25*/ + var allowed, curVal, newVal, step, + index = $( event.target ).data( "ui-slider-handle-index" ); + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.PAGE_UP: + case $.ui.keyCode.PAGE_DOWN: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + event.preventDefault(); + if ( !this._keySliding ) { + this._keySliding = true; + $( event.target ).addClass( "ui-state-active" ); + allowed = this._start( event, index ); + if ( allowed === false ) { + return; + } + } + break; + } + + step = this.options.step; + if ( this.options.values && this.options.values.length ) { + curVal = newVal = this.values( index ); + } else { + curVal = newVal = this.value(); + } + + switch ( event.keyCode ) { + case $.ui.keyCode.HOME: + newVal = this._valueMin(); + break; + case $.ui.keyCode.END: + newVal = this._valueMax(); + break; + case $.ui.keyCode.PAGE_UP: + newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.PAGE_DOWN: + newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if ( curVal === this._valueMax() ) { + return; + } + newVal = this._trimAlignValue( curVal + step ); + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if ( curVal === this._valueMin() ) { + return; + } + newVal = this._trimAlignValue( curVal - step ); + break; + } + + this._slide( event, index, newVal ); + }, + click: function( event ) { + event.preventDefault(); + }, + keyup: function( event ) { + var index = $( event.target ).data( "ui-slider-handle-index" ); + + if ( this._keySliding ) { + this._keySliding = false; + this._stop( event, index ); + this._change( event, index ); + $( event.target ).removeClass( "ui-state-active" ); + } + } + } + +}); + +}(jQuery)); + +(function( $ ) { + +function modifier( fn ) { + return function() { + var previous = this.element.val(); + fn.apply( this, arguments ); + this._refresh(); + if ( previous !== this.element.val() ) { + this._trigger( "change" ); + } + }; +} + +$.widget( "ui.spinner", { + version: "1.10.2", + defaultElement: "<input>", + widgetEventPrefix: "spin", + options: { + culture: null, + icons: { + down: "ui-icon-triangle-1-s", + up: "ui-icon-triangle-1-n" + }, + incremental: true, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + + change: null, + spin: null, + start: null, + stop: null + }, + + _create: function() { + // handle string values that need to be parsed + this._setOption( "max", this.options.max ); + this._setOption( "min", this.options.min ); + this._setOption( "step", this.options.step ); + + // format the value, but don't constrain + this._value( this.element.val(), true ); + + this._draw(); + this._on( this._events ); + this._refresh(); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _getCreateOptions: function() { + var options = {}, + element = this.element; + + $.each( [ "min", "max", "step" ], function( i, option ) { + var value = element.attr( option ); + if ( value !== undefined && value.length ) { + options[ option ] = value; + } + }); + + return options; + }, + + _events: { + keydown: function( event ) { + if ( this._start( event ) && this._keydown( event ) ) { + event.preventDefault(); + } + }, + keyup: "_stop", + focus: function() { + this.previous = this.element.val(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + this._stop(); + this._refresh(); + if ( this.previous !== this.element.val() ) { + this._trigger( "change", event ); + } + }, + mousewheel: function( event, delta ) { + if ( !delta ) { + return; + } + if ( !this.spinning && !this._start( event ) ) { + return false; + } + + this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); + clearTimeout( this.mousewheelTimer ); + this.mousewheelTimer = this._delay(function() { + if ( this.spinning ) { + this._stop( event ); + } + }, 100 ); + event.preventDefault(); + }, + "mousedown .ui-spinner-button": function( event ) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[0] === this.document[0].activeElement ? + this.previous : this.element.val(); + function checkFocus() { + var isActive = this.element[0] === this.document[0].activeElement; + if ( !isActive ) { + this.element.focus(); + this.previous = previous; + // support: IE + // IE sets focus asynchronously, so we need to check if focus + // moved off of the input because the user clicked on the button. + this._delay(function() { + this.previous = previous; + }); + } + } + + // ensure focus is on (or stays on) the text field + event.preventDefault(); + checkFocus.call( this ); + + // support: IE + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + // and check (again) if focus moved off of the input. + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + checkFocus.call( this ); + }); + + if ( this._start( event ) === false ) { + return; + } + + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + "mouseup .ui-spinner-button": "_stop", + "mouseenter .ui-spinner-button": function( event ) { + // button will add ui-state-active if mouse was down while mouseleave and kept down + if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { + return; + } + + if ( this._start( event ) === false ) { + return false; + } + this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + // TODO: do we really want to consider this a stop? + // shouldn't we just stop the repeater and wait until mouseup before + // we trigger the stop event? + "mouseleave .ui-spinner-button": "_stop" + }, + + _draw: function() { + var uiSpinner = this.uiSpinner = this.element + .addClass( "ui-spinner-input" ) + .attr( "autocomplete", "off" ) + .wrap( this._uiSpinnerHtml() ) + .parent() + // add buttons + .append( this._buttonHtml() ); + + this.element.attr( "role", "spinbutton" ); + + // button bindings + this.buttons = uiSpinner.find( ".ui-spinner-button" ) + .attr( "tabIndex", -1 ) + .button() + .removeClass( "ui-corner-all" ); + + // IE 6 doesn't understand height: 50% for the buttons + // unless the wrapper has an explicit height + if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && + uiSpinner.height() > 0 ) { + uiSpinner.height( uiSpinner.height() ); + } + + // disable spinner if element was already disabled + if ( this.options.disabled ) { + this.disable(); + } + }, + + _keydown: function( event ) { + var options = this.options, + keyCode = $.ui.keyCode; + + switch ( event.keyCode ) { + case keyCode.UP: + this._repeat( null, 1, event ); + return true; + case keyCode.DOWN: + this._repeat( null, -1, event ); + return true; + case keyCode.PAGE_UP: + this._repeat( null, options.page, event ); + return true; + case keyCode.PAGE_DOWN: + this._repeat( null, -options.page, event ); + return true; + } + + return false; + }, + + _uiSpinnerHtml: function() { + return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"; + }, + + _buttonHtml: function() { + return "" + + "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" + + "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" + + "</a>" + + "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" + + "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" + + "</a>"; + }, + + _start: function( event ) { + if ( !this.spinning && this._trigger( "start", event ) === false ) { + return false; + } + + if ( !this.counter ) { + this.counter = 1; + } + this.spinning = true; + return true; + }, + + _repeat: function( i, steps, event ) { + i = i || 500; + + clearTimeout( this.timer ); + this.timer = this._delay(function() { + this._repeat( 40, steps, event ); + }, i ); + + this._spin( steps * this.options.step, event ); + }, + + _spin: function( step, event ) { + var value = this.value() || 0; + + if ( !this.counter ) { + this.counter = 1; + } + + value = this._adjustValue( value + step * this._increment( this.counter ) ); + + if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { + this._value( value ); + this.counter++; + } + }, + + _increment: function( i ) { + var incremental = this.options.incremental; + + if ( incremental ) { + return $.isFunction( incremental ) ? + incremental( i ) : + Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 ); + } + + return 1; + }, + + _precision: function() { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); + } + return precision; + }, + + _precisionOf: function( num ) { + var str = num.toString(), + decimal = str.indexOf( "." ); + return decimal === -1 ? 0 : str.length - decimal - 1; + }, + + _adjustValue: function( value ) { + var base, aboveMin, + options = this.options; + + // make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value - base; + // - round to the nearest step + aboveMin = Math.round(aboveMin / options.step) * options.step; + // - rounding is based on 0, so adjust back to our base + value = base + aboveMin; + + // fix precision from bad JS floating point math + value = parseFloat( value.toFixed( this._precision() ) ); + + // clamp the value + if ( options.max !== null && value > options.max) { + return options.max; + } + if ( options.min !== null && value < options.min ) { + return options.min; + } + + return value; + }, + + _stop: function( event ) { + if ( !this.spinning ) { + return; + } + + clearTimeout( this.timer ); + clearTimeout( this.mousewheelTimer ); + this.counter = 0; + this.spinning = false; + this._trigger( "stop", event ); + }, + + _setOption: function( key, value ) { + if ( key === "culture" || key === "numberFormat" ) { + var prevValue = this._parse( this.element.val() ); + this.options[ key ] = value; + this.element.val( this._format( prevValue ) ); + return; + } + + if ( key === "max" || key === "min" || key === "step" ) { + if ( typeof value === "string" ) { + value = this._parse( value ); + } + } + if ( key === "icons" ) { + this.buttons.first().find( ".ui-icon" ) + .removeClass( this.options.icons.up ) + .addClass( value.up ); + this.buttons.last().find( ".ui-icon" ) + .removeClass( this.options.icons.down ) + .addClass( value.down ); + } + + this._super( key, value ); + + if ( key === "disabled" ) { + if ( value ) { + this.element.prop( "disabled", true ); + this.buttons.button( "disable" ); + } else { + this.element.prop( "disabled", false ); + this.buttons.button( "enable" ); + } + } + }, + + _setOptions: modifier(function( options ) { + this._super( options ); + this._value( this.element.val() ); + }), + + _parse: function( val ) { + if ( typeof val === "string" && val !== "" ) { + val = window.Globalize && this.options.numberFormat ? + Globalize.parseFloat( val, 10, this.options.culture ) : +val; + } + return val === "" || isNaN( val ) ? null : val; + }, + + _format: function( value ) { + if ( value === "" ) { + return ""; + } + return window.Globalize && this.options.numberFormat ? + Globalize.format( value, this.options.numberFormat, this.options.culture ) : + value; + }, + + _refresh: function() { + this.element.attr({ + "aria-valuemin": this.options.min, + "aria-valuemax": this.options.max, + // TODO: what should we do with values that can't be parsed? + "aria-valuenow": this._parse( this.element.val() ) + }); + }, + + // update the value without triggering change + _value: function( value, allowAny ) { + var parsed; + if ( value !== "" ) { + parsed = this._parse( value ); + if ( parsed !== null ) { + if ( !allowAny ) { + parsed = this._adjustValue( parsed ); + } + value = this._format( parsed ); + } + } + this.element.val( value ); + this._refresh(); + }, + + _destroy: function() { + this.element + .removeClass( "ui-spinner-input" ) + .prop( "disabled", false ) + .removeAttr( "autocomplete" ) + .removeAttr( "role" ) + .removeAttr( "aria-valuemin" ) + .removeAttr( "aria-valuemax" ) + .removeAttr( "aria-valuenow" ); + this.uiSpinner.replaceWith( this.element ); + }, + + stepUp: modifier(function( steps ) { + this._stepUp( steps ); + }), + _stepUp: function( steps ) { + if ( this._start() ) { + this._spin( (steps || 1) * this.options.step ); + this._stop(); + } + }, + + stepDown: modifier(function( steps ) { + this._stepDown( steps ); + }), + _stepDown: function( steps ) { + if ( this._start() ) { + this._spin( (steps || 1) * -this.options.step ); + this._stop(); + } + }, + + pageUp: modifier(function( pages ) { + this._stepUp( (pages || 1) * this.options.page ); + }), + + pageDown: modifier(function( pages ) { + this._stepDown( (pages || 1) * this.options.page ); + }), + + value: function( newVal ) { + if ( !arguments.length ) { + return this._parse( this.element.val() ); + } + modifier( this._value ).call( this, newVal ); + }, + + widget: function() { + return this.uiSpinner; + } +}); + +}( jQuery ) ); + +(function( $, undefined ) { + +var tabId = 0, + rhash = /#.*$/; + +function getNextTabId() { + return ++tabId; +} + +function isLocal( anchor ) { + return anchor.hash.length > 1 && + decodeURIComponent( anchor.href.replace( rhash, "" ) ) === + decodeURIComponent( location.href.replace( rhash, "" ) ); +} + +$.widget( "ui.tabs", { + version: "1.10.2", + delay: 300, + options: { + active: null, + collapsible: false, + event: "click", + heightStyle: "content", + hide: null, + show: null, + + // callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null + }, + + _create: function() { + var that = this, + options = this.options; + + this.running = false; + + this.element + .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) + .toggleClass( "ui-tabs-collapsible", options.collapsible ) + // Prevent users from focusing disabled tabs via click + .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) { + if ( $( this ).is( ".ui-state-disabled" ) ) { + event.preventDefault(); + } + }) + // support: IE <9 + // Preventing the default action in mousedown doesn't prevent IE + // from focusing the element, so if the anchor gets focused, blur. + // We don't have to worry about focusing the previously focused + // element since clicking on a non-focusable element should focus + // the body anyway. + .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { + if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { + this.blur(); + } + }); + + this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( $.isArray( options.disabled ) ) { + options.disabled = $.unique( options.disabled.concat( + $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { + return that.tabs.index( li ); + }) + ) ).sort(); + } + + // check for length avoids error when initializing empty list + if ( this.options.active !== false && this.anchors.length ) { + this.active = this._findActive( options.active ); + } else { + this.active = $(); + } + + this._refresh(); + + if ( this.active.length ) { + this.load( options.active ); + } + }, + + _initialActive: function() { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHash = location.hash.substring( 1 ); + + if ( active === null ) { + // check the fragment identifier in the URL + if ( locationHash ) { + this.tabs.each(function( i, tab ) { + if ( $( tab ).attr( "aria-controls" ) === locationHash ) { + active = i; + return false; + } + }); + } + + // check for a tab marked active via a class + if ( active === null ) { + active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); + } + + // no active tab, set to false + if ( active === null || active === -1 ) { + active = this.tabs.length ? 0 : false; + } + } + + // handle numbers: negative, out of range + if ( active !== false ) { + active = this.tabs.index( this.tabs.eq( active ) ); + if ( active === -1 ) { + active = collapsible ? false : 0; + } + } + + // don't allow collapsible: false and active: false + if ( !collapsible && active === false && this.anchors.length ) { + active = 0; + } + + return active; + }, + + _getCreateEventData: function() { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab( this.active ) + }; + }, + + _tabKeydown: function( event ) { + /*jshint maxcomplexity:15*/ + var focusedTab = $( this.document[0].activeElement ).closest( "li" ), + selectedIndex = this.tabs.index( focusedTab ), + goingForward = true; + + if ( this._handlePageNav( event ) ) { + return; + } + + switch ( event.keyCode ) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length - 1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + // Activate only, no collapsing + event.preventDefault(); + clearTimeout( this.activating ); + this._activate( selectedIndex ); + return; + case $.ui.keyCode.ENTER: + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout( this.activating ); + // Determine if we should collapse or activate + this._activate( selectedIndex === this.options.active ? false : selectedIndex ); + return; + default: + return; + } + + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout( this.activating ); + selectedIndex = this._focusNextTab( selectedIndex, goingForward ); + + // Navigating with control key will prevent automatic activation + if ( !event.ctrlKey ) { + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr( "aria-selected", "false" ); + this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); + + this.activating = this._delay(function() { + this.option( "active", selectedIndex ); + }, this.delay ); + } + }, + + _panelKeydown: function( event ) { + if ( this._handlePageNav( event ) ) { + return; + } + + // Ctrl+up moves focus to the current tab + if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { + event.preventDefault(); + this.active.focus(); + } + }, + + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function( event ) { + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { + this._activate( this._focusNextTab( this.options.active - 1, false ) ); + return true; + } + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { + this._activate( this._focusNextTab( this.options.active + 1, true ) ); + return true; + } + }, + + _findNextTab: function( index, goingForward ) { + var lastTabIndex = this.tabs.length - 1; + + function constrain() { + if ( index > lastTabIndex ) { + index = 0; + } + if ( index < 0 ) { + index = lastTabIndex; + } + return index; + } + + while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { + index = goingForward ? index + 1 : index - 1; + } + + return index; + }, + + _focusNextTab: function( index, goingForward ) { + index = this._findNextTab( index, goingForward ); + this.tabs.eq( index ).focus(); + return index; + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "disabled" ) { + // don't use the widget factory's disabled handling + this._setupDisabled( value ); + return; + } + + this._super( key, value); + + if ( key === "collapsible" ) { + this.element.toggleClass( "ui-tabs-collapsible", value ); + // Setting collapsible: false while collapsed; open first panel + if ( !value && this.options.active === false ) { + this._activate( 0 ); + } + } + + if ( key === "event" ) { + this._setupEvents( value ); + } + + if ( key === "heightStyle" ) { + this._setupHeightStyle( value ); + } + }, + + _tabId: function( tab ) { + return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId(); + }, + + _sanitizeSelector: function( hash ) { + return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; + }, + + refresh: function() { + var options = this.options, + lis = this.tablist.children( ":has(a[href])" ); + + // get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { + return lis.index( tab ); + }); + + this._processTabs(); + + // was collapsed or no tabs + if ( options.active === false || !this.anchors.length ) { + options.active = false; + this.active = $(); + // was active, but active tab is gone + } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { + // all remaining tabs are disabled + if ( this.tabs.length === options.disabled.length ) { + options.active = false; + this.active = $(); + // activate previous tab + } else { + this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); + } + // was active, active tab still exists + } else { + // make sure active index is correct + options.active = this.tabs.index( this.active ); + } + + this._refresh(); + }, + + _refresh: function() { + this._setupDisabled( this.options.disabled ); + this._setupEvents( this.options.event ); + this._setupHeightStyle( this.options.heightStyle ); + + this.tabs.not( this.active ).attr({ + "aria-selected": "false", + tabIndex: -1 + }); + this.panels.not( this._getPanelForTab( this.active ) ) + .hide() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + + // Make sure one tab is in the tab order + if ( !this.active.length ) { + this.tabs.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active + .addClass( "ui-tabs-active ui-state-active" ) + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + this._getPanelForTab( this.active ) + .show() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + }, + + _processTabs: function() { + var that = this; + + this.tablist = this._getList() + .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .attr( "role", "tablist" ); + + this.tabs = this.tablist.find( "> li:has(a[href])" ) + .addClass( "ui-state-default ui-corner-top" ) + .attr({ + role: "tab", + tabIndex: -1 + }); + + this.anchors = this.tabs.map(function() { + return $( "a", this )[ 0 ]; + }) + .addClass( "ui-tabs-anchor" ) + .attr({ + role: "presentation", + tabIndex: -1 + }); + + this.panels = $(); + + this.anchors.each(function( i, anchor ) { + var selector, panel, panelId, + anchorId = $( anchor ).uniqueId().attr( "id" ), + tab = $( anchor ).closest( "li" ), + originalAriaControls = tab.attr( "aria-controls" ); + + // inline tab + if ( isLocal( anchor ) ) { + selector = anchor.hash; + panel = that.element.find( that._sanitizeSelector( selector ) ); + // remote tab + } else { + panelId = that._tabId( tab ); + selector = "#" + panelId; + panel = that.element.find( selector ); + if ( !panel.length ) { + panel = that._createPanel( panelId ); + panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); + } + panel.attr( "aria-live", "polite" ); + } + + if ( panel.length) { + that.panels = that.panels.add( panel ); + } + if ( originalAriaControls ) { + tab.data( "ui-tabs-aria-controls", originalAriaControls ); + } + tab.attr({ + "aria-controls": selector.substring( 1 ), + "aria-labelledby": anchorId + }); + panel.attr( "aria-labelledby", anchorId ); + }); + + this.panels + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .attr( "role", "tabpanel" ); + }, + + // allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function() { + return this.element.find( "ol,ul" ).eq( 0 ); + }, + + _createPanel: function( id ) { + return $( "<div>" ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "ui-tabs-destroy", true ); + }, + + _setupDisabled: function( disabled ) { + if ( $.isArray( disabled ) ) { + if ( !disabled.length ) { + disabled = false; + } else if ( disabled.length === this.anchors.length ) { + disabled = true; + } + } + + // disable tabs + for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { + if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { + $( li ) + .addClass( "ui-state-disabled" ) + .attr( "aria-disabled", "true" ); + } else { + $( li ) + .removeClass( "ui-state-disabled" ) + .removeAttr( "aria-disabled" ); + } + } + + this.options.disabled = disabled; + }, + + _setupEvents: function( event ) { + var events = { + click: function( event ) { + event.preventDefault(); + } + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.anchors.add( this.tabs ).add( this.panels ) ); + this._on( this.anchors, events ); + this._on( this.tabs, { keydown: "_tabKeydown" } ); + this._on( this.panels, { keydown: "_panelKeydown" } ); + + this._focusable( this.tabs ); + this._hoverable( this.tabs ); + }, + + _setupHeightStyle: function( heightStyle ) { + var maxHeight, + parent = this.element.parent(); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + maxHeight -= this.element.outerHeight() - this.element.height(); + + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.element.children().not( this.panels ).each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.panels.each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.panels.each(function() { + maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); + }).height( maxHeight ); + } + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + anchor = $( event.currentTarget ), + tab = anchor.closest( "li" ), + clickedIsActive = tab[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab( tab ), + toHide = !active.length ? $() : this._getPanelForTab( active ), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow + }; + + event.preventDefault(); + + if ( tab.hasClass( "ui-state-disabled" ) || + // tab is already loading + tab.hasClass( "ui-tabs-loading" ) || + // can't switch durning an animation + this.running || + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.tabs.index( tab ); + + this.active = clickedIsActive ? $() : tab; + if ( this.xhr ) { + this.xhr.abort(); + } + + if ( !toHide.length && !toShow.length ) { + $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); + } + + if ( toShow.length ) { + this.load( this.tabs.index( tab ), event ); + } + this._toggle( event, eventData ); + }, + + // handles show/hide for selecting tabs + _toggle: function( event, eventData ) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; + + this.running = true; + + function complete() { + that.running = false; + that._trigger( "activate", event, eventData ); + } + + function show() { + eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); + + if ( toShow.length && that.options.show ) { + that._show( toShow, that.options.show, complete ); + } else { + toShow.show(); + complete(); + } + } + + // start out by hiding, then showing, then completing + if ( toHide.length && this.options.hide ) { + this._hide( toHide, this.options.hide, function() { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + show(); + }); + } else { + eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); + toHide.hide(); + show(); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + eventData.oldTab.attr( "aria-selected", "false" ); + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if ( toShow.length && toHide.length ) { + eventData.oldTab.attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.tabs.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow.attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + eventData.newTab.attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _activate: function( index ) { + var anchor, + active = this._findActive( index ); + + // trying to activate the already active panel + if ( active[ 0 ] === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the current active header + if ( !active.length ) { + active = this.active; + } + + anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; + this._eventHandler({ + target: anchor, + currentTarget: anchor, + preventDefault: $.noop + }); + }, + + _findActive: function( index ) { + return index === false ? $() : this.tabs.eq( index ); + }, + + _getIndex: function( index ) { + // meta-function to give users option to provide a href string instead of a numerical index. + if ( typeof index === "string" ) { + index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); + } + + return index; + }, + + _destroy: function() { + if ( this.xhr ) { + this.xhr.abort(); + } + + this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); + + this.tablist + .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) + .removeAttr( "role" ); + + this.anchors + .removeClass( "ui-tabs-anchor" ) + .removeAttr( "role" ) + .removeAttr( "tabIndex" ) + .removeUniqueId(); + + this.tabs.add( this.panels ).each(function() { + if ( $.data( this, "ui-tabs-destroy" ) ) { + $( this ).remove(); + } else { + $( this ) + .removeClass( "ui-state-default ui-state-active ui-state-disabled " + + "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) + .removeAttr( "tabIndex" ) + .removeAttr( "aria-live" ) + .removeAttr( "aria-busy" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-labelledby" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "role" ); + } + }); + + this.tabs.each(function() { + var li = $( this ), + prev = li.data( "ui-tabs-aria-controls" ); + if ( prev ) { + li + .attr( "aria-controls", prev ) + .removeData( "ui-tabs-aria-controls" ); + } else { + li.removeAttr( "aria-controls" ); + } + }); + + this.panels.show(); + + if ( this.options.heightStyle !== "content" ) { + this.panels.css( "height", "" ); + } + }, + + enable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === false ) { + return; + } + + if ( index === undefined ) { + disabled = false; + } else { + index = this._getIndex( index ); + if ( $.isArray( disabled ) ) { + disabled = $.map( disabled, function( num ) { + return num !== index ? num : null; + }); + } else { + disabled = $.map( this.tabs, function( li, num ) { + return num !== index ? num : null; + }); + } + } + this._setupDisabled( disabled ); + }, + + disable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === true ) { + return; + } + + if ( index === undefined ) { + disabled = true; + } else { + index = this._getIndex( index ); + if ( $.inArray( index, disabled ) !== -1 ) { + return; + } + if ( $.isArray( disabled ) ) { + disabled = $.merge( [ index ], disabled ).sort(); + } else { + disabled = [ index ]; + } + } + this._setupDisabled( disabled ); + }, + + load: function( index, event ) { + index = this._getIndex( index ); + var that = this, + tab = this.tabs.eq( index ), + anchor = tab.find( ".ui-tabs-anchor" ), + panel = this._getPanelForTab( tab ), + eventData = { + tab: tab, + panel: panel + }; + + // not remote + if ( isLocal( anchor[ 0 ] ) ) { + return; + } + + this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); + + // support: jQuery <1.8 + // jQuery <1.8 returns false if the request is canceled in beforeSend, + // but as of 1.8, $.ajax() always returns a jqXHR object. + if ( this.xhr && this.xhr.statusText !== "canceled" ) { + tab.addClass( "ui-tabs-loading" ); + panel.attr( "aria-busy", "true" ); + + this.xhr + .success(function( response ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + panel.html( response ); + that._trigger( "load", event, eventData ); + }, 1 ); + }) + .complete(function( jqXHR, status ) { + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function() { + if ( status === "abort" ) { + that.panels.stop( false, true ); + } + + tab.removeClass( "ui-tabs-loading" ); + panel.removeAttr( "aria-busy" ); + + if ( jqXHR === that.xhr ) { + delete that.xhr; + } + }, 1 ); + }); + } + }, + + _ajaxSettings: function( anchor, event, eventData ) { + var that = this; + return { + url: anchor.attr( "href" ), + beforeSend: function( jqXHR, settings ) { + return that._trigger( "beforeLoad", event, + $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) ); + } + }; + }, + + _getPanelForTab: function( tab ) { + var id = $( tab ).attr( "aria-controls" ); + return this.element.find( this._sanitizeSelector( "#" + id ) ); + } +}); + +})( jQuery ); + +(function( $ ) { + +var increments = 0; + +function addDescribedBy( elem, id ) { + var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); + describedby.push( id ); + elem + .data( "ui-tooltip-id", id ) + .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); +} + +function removeDescribedBy( elem ) { + var id = elem.data( "ui-tooltip-id" ), + describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), + index = $.inArray( id, describedby ); + if ( index !== -1 ) { + describedby.splice( index, 1 ); + } + + elem.removeData( "ui-tooltip-id" ); + describedby = $.trim( describedby.join( " " ) ); + if ( describedby ) { + elem.attr( "aria-describedby", describedby ); + } else { + elem.removeAttr( "aria-describedby" ); + } +} + +$.widget( "ui.tooltip", { + version: "1.10.2", + options: { + content: function() { + // support: IE<9, Opera in jQuery <1.7 + // .text() can't accept undefined, so coerce to a string + var title = $( this ).attr( "title" ) || ""; + // Escape title, since we're going from an attribute to raw HTML + return $( "<a>" ).text( title ).html(); + }, + hide: true, + // Disabled elements have inconsistent behavior across browsers (#8661) + items: "[title]:not([disabled])", + position: { + my: "left top+15", + at: "left bottom", + collision: "flipfit flip" + }, + show: true, + tooltipClass: null, + track: false, + + // callbacks + close: null, + open: null + }, + + _create: function() { + this._on({ + mouseover: "open", + focusin: "open" + }); + + // IDs of generated tooltips, needed for destroy + this.tooltips = {}; + // IDs of parent tooltips where we removed the title attribute + this.parents = {}; + + if ( this.options.disabled ) { + this._disable(); + } + }, + + _setOption: function( key, value ) { + var that = this; + + if ( key === "disabled" ) { + this[ value ? "_disable" : "_enable" ](); + this.options[ key ] = value; + // disable element style changes + return; + } + + this._super( key, value ); + + if ( key === "content" ) { + $.each( this.tooltips, function( id, element ) { + that._updateContent( element ); + }); + } + }, + + _disable: function() { + var that = this; + + // close open tooltips + $.each( this.tooltips, function( id, element ) { + var event = $.Event( "blur" ); + event.target = event.currentTarget = element[0]; + that.close( event, true ); + }); + + // remove title attributes to prevent native tooltips + this.element.find( this.options.items ).addBack().each(function() { + var element = $( this ); + if ( element.is( "[title]" ) ) { + element + .data( "ui-tooltip-title", element.attr( "title" ) ) + .attr( "title", "" ); + } + }); + }, + + _enable: function() { + // restore title attributes + this.element.find( this.options.items ).addBack().each(function() { + var element = $( this ); + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + }); + }, + + open: function( event ) { + var that = this, + target = $( event ? event.target : this.element ) + // we need closest here due to mouseover bubbling, + // but always pointing at the same event target + .closest( this.options.items ); + + // No element to show a tooltip for or the tooltip is already open + if ( !target.length || target.data( "ui-tooltip-id" ) ) { + return; + } + + if ( target.attr( "title" ) ) { + target.data( "ui-tooltip-title", target.attr( "title" ) ); + } + + target.data( "ui-tooltip-open", true ); + + // kill parent tooltips, custom or native, for hover + if ( event && event.type === "mouseover" ) { + target.parents().each(function() { + var parent = $( this ), + blurEvent; + if ( parent.data( "ui-tooltip-open" ) ) { + blurEvent = $.Event( "blur" ); + blurEvent.target = blurEvent.currentTarget = this; + that.close( blurEvent, true ); + } + if ( parent.attr( "title" ) ) { + parent.uniqueId(); + that.parents[ this.id ] = { + element: this, + title: parent.attr( "title" ) + }; + parent.attr( "title", "" ); + } + }); + } + + this._updateContent( target, event ); + }, + + _updateContent: function( target, event ) { + var content, + contentOption = this.options.content, + that = this, + eventType = event ? event.type : null; + + if ( typeof contentOption === "string" ) { + return this._open( event, target, contentOption ); + } + + content = contentOption.call( target[0], function( response ) { + // ignore async response if tooltip was closed already + if ( !target.data( "ui-tooltip-open" ) ) { + return; + } + // IE may instantly serve a cached response for ajax requests + // delay this call to _open so the other call to _open runs first + that._delay(function() { + // jQuery creates a special event for focusin when it doesn't + // exist natively. To improve performance, the native event + // object is reused and the type is changed. Therefore, we can't + // rely on the type being correct after the event finished + // bubbling, so we set it back to the previous value. (#8740) + if ( event ) { + event.type = eventType; + } + this._open( event, target, response ); + }); + }); + if ( content ) { + this._open( event, target, content ); + } + }, + + _open: function( event, target, content ) { + var tooltip, events, delayedShow, + positionOption = $.extend( {}, this.options.position ); + + if ( !content ) { + return; + } + + // Content can be updated multiple times. If the tooltip already + // exists, then just update the content and bail. + tooltip = this._find( target ); + if ( tooltip.length ) { + tooltip.find( ".ui-tooltip-content" ).html( content ); + return; + } + + // if we have a title, clear it to prevent the native tooltip + // we have to check first to avoid defining a title if none exists + // (we don't want to cause an element to start matching [title]) + // + // We use removeAttr only for key events, to allow IE to export the correct + // accessible attributes. For mouse events, set to empty string to avoid + // native tooltip showing up (happens only when removing inside mouseover). + if ( target.is( "[title]" ) ) { + if ( event && event.type === "mouseover" ) { + target.attr( "title", "" ); + } else { + target.removeAttr( "title" ); + } + } + + tooltip = this._tooltip( target ); + addDescribedBy( target, tooltip.attr( "id" ) ); + tooltip.find( ".ui-tooltip-content" ).html( content ); + + function position( event ) { + positionOption.of = event; + if ( tooltip.is( ":hidden" ) ) { + return; + } + tooltip.position( positionOption ); + } + if ( this.options.track && event && /^mouse/.test( event.type ) ) { + this._on( this.document, { + mousemove: position + }); + // trigger once to override element-relative positioning + position( event ); + } else { + tooltip.position( $.extend({ + of: target + }, this.options.position ) ); + } + + tooltip.hide(); + + this._show( tooltip, this.options.show ); + // Handle tracking tooltips that are shown with a delay (#8644). As soon + // as the tooltip is visible, position the tooltip using the most recent + // event. + if ( this.options.show && this.options.show.delay ) { + delayedShow = this.delayedShow = setInterval(function() { + if ( tooltip.is( ":visible" ) ) { + position( positionOption.of ); + clearInterval( delayedShow ); + } + }, $.fx.interval ); + } + + this._trigger( "open", event, { tooltip: tooltip } ); + + events = { + keyup: function( event ) { + if ( event.keyCode === $.ui.keyCode.ESCAPE ) { + var fakeEvent = $.Event(event); + fakeEvent.currentTarget = target[0]; + this.close( fakeEvent, true ); + } + }, + remove: function() { + this._removeTooltip( tooltip ); + } + }; + if ( !event || event.type === "mouseover" ) { + events.mouseleave = "close"; + } + if ( !event || event.type === "focusin" ) { + events.focusout = "close"; + } + this._on( true, target, events ); + }, + + close: function( event ) { + var that = this, + target = $( event ? event.currentTarget : this.element ), + tooltip = this._find( target ); + + // disabling closes the tooltip, so we need to track when we're closing + // to avoid an infinite loop in case the tooltip becomes disabled on close + if ( this.closing ) { + return; + } + + // Clear the interval for delayed tracking tooltips + clearInterval( this.delayedShow ); + + // only set title if we had one before (see comment in _open()) + if ( target.data( "ui-tooltip-title" ) ) { + target.attr( "title", target.data( "ui-tooltip-title" ) ); + } + + removeDescribedBy( target ); + + tooltip.stop( true ); + this._hide( tooltip, this.options.hide, function() { + that._removeTooltip( $( this ) ); + }); + + target.removeData( "ui-tooltip-open" ); + this._off( target, "mouseleave focusout keyup" ); + // Remove 'remove' binding only on delegated targets + if ( target[0] !== this.element[0] ) { + this._off( target, "remove" ); + } + this._off( this.document, "mousemove" ); + + if ( event && event.type === "mouseleave" ) { + $.each( this.parents, function( id, parent ) { + $( parent.element ).attr( "title", parent.title ); + delete that.parents[ id ]; + }); + } + + this.closing = true; + this._trigger( "close", event, { tooltip: tooltip } ); + this.closing = false; + }, + + _tooltip: function( element ) { + var id = "ui-tooltip-" + increments++, + tooltip = $( "<div>" ) + .attr({ + id: id, + role: "tooltip" + }) + .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + + ( this.options.tooltipClass || "" ) ); + $( "<div>" ) + .addClass( "ui-tooltip-content" ) + .appendTo( tooltip ); + tooltip.appendTo( this.document[0].body ); + this.tooltips[ id ] = element; + return tooltip; + }, + + _find: function( target ) { + var id = target.data( "ui-tooltip-id" ); + return id ? $( "#" + id ) : $(); + }, + + _removeTooltip: function( tooltip ) { + tooltip.remove(); + delete this.tooltips[ tooltip.attr( "id" ) ]; + }, + + _destroy: function() { + var that = this; + + // close open tooltips + $.each( this.tooltips, function( id, element ) { + // Delegate to close method to handle common cleanup + var event = $.Event( "blur" ); + event.target = event.currentTarget = element[0]; + that.close( event, true ); + + // Remove immediately; destroying an open tooltip doesn't use the + // hide animation + $( "#" + id ).remove(); + + // Restore the title + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + element.removeData( "ui-tooltip-title" ); + } + }); + } +}); + +}( jQuery ) ); diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.min.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.min.js new file mode 100644 index 0000000..629f140 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/3rdparty/jquery-ui/js/jquery-ui.min.js @@ -0,0 +1,12 @@ +/*! jQuery UI - v1.10.2 - 2013-03-14 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js +* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ +(function(t,e){function i(e,i){var n,o,a,r=e.nodeName.toLowerCase();return"area"===r?(n=e.parentNode,o=n.name,e.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap=#"+o+"]")[0],!!a&&s(a)):!1):(/input|select|textarea|button|object/.test(r)?!e.disabled:"a"===r?e.href||i:i)&&s(e)}function s(e){return t.expr.filters.visible(e)&&!t(e).parents().addBack().filter(function(){return"hidden"===t.css(this,"visibility")}).length}var n=0,o=/^ui-id-\d+$/;t.ui=t.ui||{},t.extend(t.ui,{version:"1.10.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),t.fn.extend({focus:function(e){return function(i,s){return"number"==typeof i?this.each(function(){var e=this;setTimeout(function(){t(e).focus(),s&&s.call(e)},i)}):e.apply(this,arguments)}}(t.fn.focus),scrollParent:function(){var e;return e=t.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(t.css(this,"position"))&&/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!e.length?t(document):e},zIndex:function(i){if(i!==e)return this.css("zIndex",i);if(this.length)for(var s,n,o=t(this[0]);o.length&&o[0]!==document;){if(s=o.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(n=parseInt(o.css("zIndex"),10),!isNaN(n)&&0!==n))return n;o=o.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){o.test(this.id)&&t(this).removeAttr("id")})}}),t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])},focusable:function(e){return i(e,!isNaN(t.attr(e,"tabindex")))},tabbable:function(e){var s=t.attr(e,"tabindex"),n=isNaN(s);return(n||s>=0)&&i(e,!n)}}),t("<a>").outerWidth(1).jquery||t.each(["Width","Height"],function(i,s){function n(e,i,s,n){return t.each(o,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),n&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var o="Width"===s?["Left","Right"]:["Top","Bottom"],a=s.toLowerCase(),r={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+s]=function(i){return i===e?r["inner"+s].call(this):this.each(function(){t(this).css(a,n(this,i)+"px")})},t.fn["outer"+s]=function(e,i){return"number"!=typeof e?r["outer"+s].call(this,e):this.each(function(){t(this).css(a,n(this,e,!0,i)+"px")})}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(t.fn.removeData=function(e){return function(i){return arguments.length?e.call(this,t.camelCase(i)):e.call(this)}}(t.fn.removeData)),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),t.support.selectstart="onselectstart"in document.createElement("div"),t.fn.extend({disableSelection:function(){return this.bind((t.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(t){t.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),t.extend(t.ui,{plugin:{add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i){var s,n=t.plugins[e];if(n&&t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType)for(s=0;n.length>s;s++)t.options[n[s][0]]&&n[s][1].apply(t.element,i)}},hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)}})})(jQuery),function(t,e){var i=0,s=Array.prototype.slice,n=t.cleanData;t.cleanData=function(e){for(var i,s=0;null!=(i=e[s]);s++)try{t(i).triggerHandler("remove")}catch(o){}n(e)},t.widget=function(i,s,n){var o,a,r,h,l={},c=i.split(".")[0];i=i.split(".")[1],o=c+"-"+i,n||(n=s,s=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},a=t[c][i],r=t[c][i]=function(t,i){return this._createWidget?(arguments.length&&this._createWidget(t,i),e):new r(t,i)},t.extend(r,a,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),h=new s,h.options=t.widget.extend({},h.options),t.each(n,function(i,n){return t.isFunction(n)?(l[i]=function(){var t=function(){return s.prototype[i].apply(this,arguments)},e=function(t){return s.prototype[i].apply(this,t)};return function(){var i,s=this._super,o=this._superApply;return this._super=t,this._superApply=e,i=n.apply(this,arguments),this._super=s,this._superApply=o,i}}(),e):(l[i]=n,e)}),r.prototype=t.widget.extend(h,{widgetEventPrefix:a?h.widgetEventPrefix:i},l,{constructor:r,namespace:c,widgetName:i,widgetFullName:o}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,r,i._proto)}),delete a._childConstructors):s._childConstructors.push(r),t.widget.bridge(i,r)},t.widget.extend=function(i){for(var n,o,a=s.call(arguments,1),r=0,h=a.length;h>r;r++)for(n in a[r])o=a[r][n],a[r].hasOwnProperty(n)&&o!==e&&(i[n]=t.isPlainObject(o)?t.isPlainObject(i[n])?t.widget.extend({},i[n],o):t.widget.extend({},o):o);return i},t.widget.bridge=function(i,n){var o=n.prototype.widgetFullName||i;t.fn[i]=function(a){var r="string"==typeof a,h=s.call(arguments,1),l=this;return a=!r&&h.length?t.widget.extend.apply(null,[a].concat(h)):a,r?this.each(function(){var s,n=t.data(this,o);return n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(s=n[a].apply(n,h),s!==n&&s!==e?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):e):t.error("no such method '"+a+"' for "+i+" widget instance"):t.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var e=t.data(this,o);e?e.option(a||{})._init():t.data(this,o,new n(a,this))}),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this.bindings=t(),this.hoverable=t(),this.focusable=t(),s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(i,s){var n,o,a,r=i;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof i)if(r={},n=i.split("."),i=n.shift(),n.length){for(o=r[i]=t.widget.extend({},this.options[i]),a=0;n.length-1>a;a++)o[n[a]]=o[n[a]]||{},o=o[n[a]];if(i=n.pop(),s===e)return o[i]===e?null:o[i];o[i]=s}else{if(s===e)return this.options[i]===e?null:this.options[i];r[i]=s}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!e).attr("aria-disabled",e),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var o,a=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=o=t(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,o=this.widget()),t.each(n,function(n,r){function h(){return i||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?a[r]:r).apply(a,arguments):e}"string"!=typeof r&&(h.guid=r.guid=r.guid||h.guid||t.guid++);var l=n.match(/^(\w+)\s*(.*)$/),c=l[1]+a.eventNamespace,u=l[2];u?o.delegate(u,c,h):s.bind(c,h)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(e).undelegate(e)},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}})}(jQuery),function(t){var e=!1;t(document).mouseup(function(){e=!1}),t.widget("ui.mouse",{version:"1.10.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!e){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,o="string"==typeof this.options.cancel&&i.target.nodeName?t(i.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===t.data(i.target,this.widgetName+".preventClickEvent")&&t.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return s._mouseMove(t)},this._mouseUpDelegate=function(t){return s._mouseUp(t)},t(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),e=!0,!0)):!0}},_mouseMove:function(e){return t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button?this._mouseUp(e):this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})}(jQuery),function(t){t.widget("ui.draggable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(t(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){t("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(t(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),i.containment&&this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_mouseDrag:function(e,i){if(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i,s=this,n=!1,o=!1;for(t.ui.ddmanager&&!this.options.dropBehaviour&&(o=t.ui.ddmanager.drop(this,e)),this.dropped&&(o=this.dropped,this.dropped=!1),i=this.element[0];i&&(i=i.parentNode);)i===document&&(n=!0);return n||"original"!==this.options.helper?("invalid"===this.options.revert&&!o||"valid"===this.options.revert&&o||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,o)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",e)!==!1&&s._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1):!1},_mouseUp:function(e){return t("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.element.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;if("parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=["document"===n.containment?0:t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,"document"===n.containment?0:t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,("document"===n.containment?0:t(window).scrollLeft())+t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,("document"===n.containment?0:t(window).scrollTop())+(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||n.containment.constructor===Array)n.containment.constructor===Array&&(this.containment=n.containment);else{if(i=t(n.containment),s=i[0],!s)return;e="hidden"!==t(s).css("overflow"),this.containment=[(parseInt(t(s).css("borderLeftWidth"),10)||0)+(parseInt(t(s).css("paddingLeft"),10)||0),(parseInt(t(s).css("borderTopWidth"),10)||0)+(parseInt(t(s).css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(t(s).css("borderRightWidth"),10)||0)-(parseInt(t(s).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(t(s).css("borderBottomWidth"),10)||0)-(parseInt(t(s).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i}},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n,o,a=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName),l=e.pageX,c=e.pageY;return this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.left<i[0]&&(l=i[0]+this.offset.click.left),e.pageY-this.offset.click.top<i[1]&&(c=i[1]+this.offset.click.top),e.pageX-this.offset.click.left>i[2]&&(l=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(c=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((c-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,c=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,l=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o)),{top:c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s]),"drag"===e&&(this.positionAbs=this._convertPositionTo("absolute")),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i){var s=t(this).data("ui-draggable"),n=s.options,o=t.extend({},i,{item:s.element});s.sortables=[],t(n.connectToSortable).each(function(){var i=t.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",e,o))})},stop:function(e,i){var s=t(this).data("ui-draggable"),n=t.extend({},i,{item:s.element});t.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(e),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",e,n))})},drag:function(e,i){var s=t(this).data("ui-draggable"),n=this;t.each(s.sortables,function(){var o=!1,a=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(o=!0,t.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==a&&this.instance._intersectsWith(this.instance.containerCache)&&t.contains(a.instance.element[0],this.instance.element[0])&&(o=!1),o})),o?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=t(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},e.target=this.instance.currentItem[0],this.instance._mouseCapture(e,!0),this.instance._mouseStart(e,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",e),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(e)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",e,this.instance._uiHash(this.instance)),this.instance._mouseStop(e,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",e),s.dropped=!1)})}}),t.ui.plugin.add("draggable","cursor",{start:function(){var e=t("body"),i=t(this).data("ui-draggable").options;e.css("cursor")&&(i._cursor=e.css("cursor")),e.css("cursor",i.cursor)},stop:function(){var e=t(this).data("ui-draggable").options;e._cursor&&t("body").css("cursor",e._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._opacity&&t(i.helper).css("opacity",s._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(){var e=t(this).data("ui-draggable");e.scrollParent[0]!==document&&"HTML"!==e.scrollParent[0].tagName&&(e.overflowOffset=e.scrollParent.offset())},drag:function(e){var i=t(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-e.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:e.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-e.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:e.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(e.pageY-t(document).scrollTop()<s.scrollSensitivity?n=t(document).scrollTop(t(document).scrollTop()-s.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<s.scrollSensitivity&&(n=t(document).scrollTop(t(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(e.pageX-t(document).scrollLeft()<s.scrollSensitivity?n=t(document).scrollLeft(t(document).scrollLeft()-s.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<s.scrollSensitivity&&(n=t(document).scrollLeft(t(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&t.ui.ddmanager&&!s.dropBehaviour&&t.ui.ddmanager.prepareOffsets(i,e)}}),t.ui.plugin.add("draggable","snap",{start:function(){var e=t(this).data("ui-draggable"),i=e.options;e.snapElements=[],t(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=t(this),s=i.offset();this!==e.element[0]&&e.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(e,i){var s,n,o,a,r,h,l,c,u,d,p=t(this).data("ui-draggable"),f=p.options,g=f.snapTolerance,m=i.offset.left,v=m+p.helperProportions.width,_=i.offset.top,b=_+p.helperProportions.height;for(u=p.snapElements.length-1;u>=0;u--)r=p.snapElements[u].left,h=r+p.snapElements[u].width,l=p.snapElements[u].top,c=l+p.snapElements[u].height,m>r-g&&h+g>m&&_>l-g&&c+g>_||m>r-g&&h+g>m&&b>l-g&&c+g>b||v>r-g&&h+g>v&&_>l-g&&c+g>_||v>r-g&&h+g>v&&b>l-g&&c+g>b?("inner"!==f.snapMode&&(s=g>=Math.abs(l-b),n=g>=Math.abs(c-_),o=g>=Math.abs(r-v),a=g>=Math.abs(h-m),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||o||a,"outer"!==f.snapMode&&(s=g>=Math.abs(l-_),n=g>=Math.abs(c-b),o=g>=Math.abs(r-m),a=g>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c-p.helperProportions.height,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[u].snapping&&(s||n||o||a||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=s||n||o||a||d):(p.snapElements[u].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=!1)}}),t.ui.plugin.add("draggable","stack",{start:function(){var e,i=this.data("ui-draggable").options,s=t.makeArray(t(i.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});s.length&&(e=parseInt(t(s[0]).css("zIndex"),10)||0,t(s).each(function(i){t(this).css("zIndex",e+i)}),this.css("zIndex",e+s.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._zIndex&&t(i.helper).css("zIndex",s._zIndex)}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}t.widget("ui.droppable",{version:"1.10.2",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e=this.options,i=e.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(i)?i:function(t){return t.is(i)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},t.ui.ddmanager.droppables[e.scope]=t.ui.ddmanager.droppables[e.scope]||[],t.ui.ddmanager.droppables[e.scope].push(this),e.addClasses&&this.element.addClass("ui-droppable") +},_destroy:function(){for(var e=0,i=t.ui.ddmanager.droppables[this.options.scope];i.length>e;e++)i[e]===this&&i.splice(e,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(e,i){"accept"===e&&(this.accept=t.isFunction(i)?i:function(t){return t.is(i)}),t.Widget.prototype._setOption.apply(this,arguments)},_activate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var e=t.data(this,"ui-droppable");return e.options.greedy&&!e.options.disabled&&e.options.scope===s.options.scope&&e.accept.call(e.element[0],s.currentItem||s.element)&&t.ui.intersect(s,t.extend(e,{offset:e.element.offset()}),e.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}}}),t.ui.intersect=function(t,i,s){if(!i.offset)return!1;var n,o,a=(t.positionAbs||t.position.absolute).left,r=a+t.helperProportions.width,h=(t.positionAbs||t.position.absolute).top,l=h+t.helperProportions.height,c=i.offset.left,u=c+i.proportions.width,d=i.offset.top,p=d+i.proportions.height;switch(s){case"fit":return a>=c&&u>=r&&h>=d&&p>=l;case"intersect":return a+t.helperProportions.width/2>c&&u>r-t.helperProportions.width/2&&h+t.helperProportions.height/2>d&&p>l-t.helperProportions.height/2;case"pointer":return n=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,o=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(o,d,i.proportions.height)&&e(n,c,i.proportions.width);case"touch":return(h>=d&&p>=h||l>=d&&p>=l||d>h&&l>p)&&(a>=c&&u>=a||r>=c&&u>=r||c>a&&r>u);default:return!1}},t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions.height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions={width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight})}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&t.ui.intersect(e,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").bind("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=t.ui.intersect(e,this,this.options.tolerance),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t.data(this,"ui-droppable").options.scope===n}),o.length&&(s=t.data(o[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").unbind("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}}}(jQuery),function(t){function e(t){return parseInt(t,10)||0}function i(t){return!isNaN(parseInt(t,10))}t.widget("ui.resizable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var e,i,s,n,o,a=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(t("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),o="ui-resizable-"+s,n=t("<div class='ui-resizable-handle "+o+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=t(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),t(this.handles[i]).length},this._renderAxis(this.element),this._handles=t(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){a.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),a.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),a._handles.show())}).mouseleave(function(){r.disabled||a.resizing||(t(this).addClass("ui-resizable-autohide"),a._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,o,a=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=e(this.helper.css("left")),n=e(this.helper.css("top")),a.containment&&(s+=t(a.containment).scrollLeft()||0,n+=t(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,o=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===o?this.axis+"-resize":o),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(e){var i,s=this.helper,n={},o=this.originalMousePosition,a=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,c=this.size.height,u=e.pageX-o.left||0,d=e.pageY-o.top||0,p=this._change[a];return p?(i=p.apply(this,[e,u,d]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==c&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(n)||this._trigger("resize",e,this.ui()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&t.ui.hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null,h=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(t){var e,s,n,o,a,r=this.options;a={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||t)&&(e=a.minHeight*this.aspectRatio,n=a.minWidth/this.aspectRatio,s=a.maxHeight*this.aspectRatio,o=a.maxWidth/this.aspectRatio,e>a.minWidth&&(a.minWidth=e),n>a.minHeight&&(a.minHeight=n),a.maxWidth>s&&(a.maxWidth=s),a.maxHeight>o&&(a.maxHeight=o)),this._vBoundaries=a},_updateCache:function(t){this.offset=this.helper.offset(),i(t.left)&&(this.position.left=t.left),i(t.top)&&(this.position.top=t.top),i(t.height)&&(this.size.height=t.height),i(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,s=this.size,n=this.axis;return i(t.height)?t.width=t.height*this.aspectRatio:i(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===n&&(t.left=e.left+(s.width-t.width),t.top=null),"nw"===n&&(t.top=e.top+(s.height-t.height),t.left=e.left+(s.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,s=this.axis,n=i(t.width)&&e.maxWidth&&e.maxWidth<t.width,o=i(t.height)&&e.maxHeight&&e.maxHeight<t.height,a=i(t.width)&&e.minWidth&&e.minWidth>t.width,r=i(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,c=/sw|nw|w/.test(s),u=/nw|ne|n/.test(s);return a&&(t.width=e.minWidth),r&&(t.height=e.minHeight),n&&(t.width=e.maxWidth),o&&(t.height=e.maxHeight),a&&c&&(t.left=h-e.minWidth),n&&c&&(t.left=h-e.maxWidth),r&&u&&(t.top=l-e.minHeight),o&&u&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var t,e,i,s,n,o=this.helper||this.element;for(t=0;this._proportionallyResizeElements.length>t;t++){if(n=this._proportionallyResizeElements[t],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],e=0;i.length>e;e++)this.borderDif[e]=(parseInt(i[e],10)||0)+(parseInt(s[e],10)||0);n.css({height:o.height()-this.borderDif[0]-this.borderDif[2]||0,width:o.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&t.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,c=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,o,a,r,h,l=t(this).data("ui-resizable"),c=l.options,u=l.element,d=c.containment,p=d instanceof t?d.get(0):/parent/.test(d)?u.parent().get(0):d;p&&(l.containerElement=t(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(i=t(p),s=[],t(["Top","Right","Left","Bottom"]).each(function(t,n){s[t]=e(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,o=l.containerSize.height,a=l.containerSize.width,r=t.ui.hasScroll(p,"left")?p.scrollWidth:a,h=t.ui.hasScroll(p)?p.scrollHeight:o,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(e){var i,s,n,o,a=t(this).data("ui-resizable"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio),a.position.top=a._helper?h.top:0),a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top,i=Math.abs((a._helper?a.offset.left-u.left:a.offset.left-u.left)+a.sizeDiff.width),s=Math.abs((a._helper?a.offset.top-u.top:a.offset.top-h.top)+a.sizeDiff.height),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o&&(i-=a.parentData.left),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio))},stop:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=function(e){t(e).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):t.each(i.alsoResize,function(t){s(t)})},resize:function(e,i){var s=t(this).data("ui-resizable"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0},h=function(e,s){t(e).each(function(){var e=t(this),n=t(this).data("ui-resizable-alsoresize"),o={},a=s&&s.length?s:e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(a,function(t,e){var i=(n[e]||0)+(r[e]||0);i&&i>=0&&(o[e]=i||null)}),e.css(o)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):t.each(n.alsoResize,function(t,e){h(t,e)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).data("ui-resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).data("ui-resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,a=e.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,c=Math.round((s.width-n.width)/h)*h,u=Math.round((s.height-n.height)/l)*l,d=n.width+c,p=n.height+u,f=i.maxWidth&&d>i.maxWidth,g=i.maxHeight&&p>i.maxHeight,m=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,m&&(d+=h),v&&(p+=l),f&&(d-=h),g&&(p-=l),/^(se|s|e)$/.test(a)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.top=o.top-u):/^(sw)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.left=o.left-c):(e.size.width=d,e.size.height=p,e.position.top=o.top-u,e.position.left=o.left-c)}})}(jQuery),function(t){t.widget("ui.selectable",t.ui.mouse,{version:"1.10.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e=t(i.options.filter,i.element[0]),e.addClass("ui-selectee"),e.each(function(){var e=t(this),i=e.offset();t.data(this,"selectable-item",{element:this,$element:e,left:i.left,top:i.top,right:i.left+e.outerWidth(),bottom:i.top+e.outerHeight(),startselected:!1,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=e.addClass("ui-selectee"),this._mouseInit(),this.helper=t("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||o>i.right||i.top>h||a>i.bottom):"fit"===n.tolerance&&(l=i.left>o&&r>i.right&&i.top>a&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):undefined}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("<style>*{ cursor: "+a.cursor+" !important; }</style>").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<a.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+a.scrollSpeed:e.pageY-this.overflowOffset.top<a.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-a.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<a.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+a.scrollSpeed:e.pageX-this.overflowOffset.left<a.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-a.scrollSpeed)):(e.pageY-t(document).scrollTop()<a.scrollSensitivity?r=t(document).scrollTop(t(document).scrollTop()-a.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<a.scrollSensitivity&&(r=t(document).scrollTop(t(document).scrollTop()+a.scrollSpeed)),e.pageX-t(document).scrollLeft()<a.scrollSensitivity?r=t(document).scrollLeft(t(document).scrollLeft()-a.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<a.scrollSensitivity&&(r=t(document).scrollLeft(t(document).scrollLeft()+a.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break; +this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u=s+l>r&&h>s+l&&e+c>o&&a>e+c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?u:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,o=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return n?this.floating?a&&"right"===a||"down"===o?2:1:o&&("down"===o?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return this.floating&&o?"right"===o&&s||"left"===o&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){var i,s,n,o,a=[],r=[],h=this._connectWith();if(h&&e)for(i=h.length-1;i>=0;i--)for(n=t(h[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&r.push([t.isFunction(o.options.items)?o.options.items.call(o.element):t(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(r.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=r.length-1;i>=0;i--)r[i][0].each(function(){a.push(this)});return t(a)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t(e.document[0].createElement(s)).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?n.append("<td colspan='99'> </td>"):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,o,a,r,h,l,c,u,d,p,f=null,g=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],g=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[g].containerCache.over||(this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1);else{for(a=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],o=this.items.length-1;o>=0;o--)t.contains(this.containers[g].element[0],this.items[o].item[0])&&this.items[o].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[o].top,this.items[o].height))&&(u=this.items[o].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[o][l]-c)&&(d=!0,u+=this.items[o][l]),a>Math.abs(u-c)&&(a=Math.abs(u-c),r=this.items[o],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[g])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[g].element,!0),this._trigger("change",s,this._uiHash()),this.containers[g]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[g],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(o=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(a=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)e||s.push(function(t){return function(e){t._trigger("deactivate",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(t){return function(e){t._trigger("out",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})}(jQuery),function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function s(e,i){var s,n,a={};for(s in i)n=i[s],e[s]!==n&&(o[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(a[s]=n));return a}var n=["add","remove","toggle"],o={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var e=t(this);return{el:e,start:i(this)}}),o=function(){t.each(n,function(t,i){e[i]&&a[i+"Class"](e[i])})},o(),l=l.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,o,a,r){return"boolean"==typeof n||n===e?o?t.effects.animateClass.call(this,n?{add:s}:{remove:s},o,a,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,o,a)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.2",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,o;for(o=0;s.length>o;o++)null!==s[o]&&(n=t.data(i+s[o]),n===e&&(n=""),t.css(s[o],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(o)&&o.call(n[0]),t.isFunction(e)&&e()}var n=t(this),o=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):a.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,o=i.queue,a=t.effects.effect[i.effect];return t.fx.off||!a?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):o===!1?this.each(e):this.queue(o||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()}(jQuery),function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("<span>").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove() +},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),o.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),(e.active===!1&&e.collapsible===!0||!this.headers.length)&&(e.active=!1,this.active=t()),e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,o=this.element.parent(),a=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),o=n.attr("id");s||(s=a+"-header-"+e,i.attr("id",s)),o||(o=a+"-panel-"+e,n.attr("id",o)),i.attr("aria-controls",o),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=o.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n[0]===s[0],a=o&&i.collapsible,r=a?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:a?t():n,newPanel:r};e.preventDefault(),o&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=a?!1:this.headers.index(n),this.active=o?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),o||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-expanded":"false","aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr("tabIndex",-1):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(t,e,n){var o,a,r,h=this,l=0,c=t.length&&(!e.length||t.index()<e.index()),u=this.options.animate||{},d=c&&u.down||u,p=function(){h._toggleComplete(n)};return"number"==typeof d&&(r=d),"string"==typeof d&&(a=d),a=a||d.easing||u.easing,r=r||d.duration||u.duration,e.length?t.length?(o=t.show().outerHeight(),e.animate(i,{duration:r,easing:a,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(s,{duration:r,easing:a,complete:p,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?l+=i.now:"content"!==h.options.heightStyle&&(i.now=Math.round(o-e.outerHeight()-l),l=0)}}),undefined):e.animate(i,r,a,p):t.animate(s,r,a,p)},_toggleComplete:function(t){var e=t.oldPanel;e.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}})}(jQuery),function(t){var e=0;t.widget("ui.autocomplete",{version:"1.10.2",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n;this.isMultiLine=o?!0:a?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,undefined;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:case o.NUMPAD_ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,s.preventDefault(),undefined;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),undefined):(this._searchTimeout(t),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(t),this._change(t),undefined)}}),this._initSource(),this.menu=t("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({input:t(),role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];t(e.target).closest(".ui-menu-item").length||this._delay(function(){var e=this;this.document.one("mousedown",function(s){s.target===e.element[0]||s.target===i||t.contains(i,s.target)||e.close()})})},menufocus:function(e,i){if(this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",e,{item:s})?e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=t("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertAfter(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e||(e=this.element.closest(".ui-front")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):undefined},_search:function(t){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var t=this,i=++e;return function(s){i===e&&t.__response(s),t.pending--,t.pending||t.element.removeClass("ui-autocomplete-loading")}},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({label:e.label||e.value,value:e.value||e.label},e)})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<a>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[t](e),undefined):(this.search(null,e),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.text(e))}})}(jQuery),function(t){var e,i,s,n,o="ui-button ui-widget ui-state-default ui-corner-all",a="ui-state-hover ui-state-active ",r="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",h=function(){var e=t(this).find(":ui-button");setTimeout(function(){e.button("refresh")},1)},l=function(e){var i=e.name,s=e.form,n=t([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?t(s).find("[name='"+i+"']"):t("[name='"+i+"']",e.ownerDocument).filter(function(){return!this.form})),n};t.widget("ui.button",{version:"1.10.2",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,h),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var a=this,r=this.options,c="checkbox"===this.type||"radio"===this.type,u=c?"":"ui-state-active",d="ui-state-focus";null===r.label&&(r.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(o).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){r.disabled||this===e&&t(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){r.disabled||t(this).removeClass(u)}).bind("click"+this.eventNamespace,function(t){r.disabled&&(t.preventDefault(),t.stopImmediatePropagation())}),this.element.bind("focus"+this.eventNamespace,function(){a.buttonElement.addClass(d)}).bind("blur"+this.eventNamespace,function(){a.buttonElement.removeClass(d)}),c&&(this.element.bind("change"+this.eventNamespace,function(){n||a.refresh()}),this.buttonElement.bind("mousedown"+this.eventNamespace,function(t){r.disabled||(n=!1,i=t.pageX,s=t.pageY)}).bind("mouseup"+this.eventNamespace,function(t){r.disabled||(i!==t.pageX||s!==t.pageY)&&(n=!0)})),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return r.disabled||n?!1:undefined}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(r.disabled||n)return!1;t(this).addClass("ui-state-active"),a.buttonElement.attr("aria-pressed","true");var e=a.element[0];l(e).not(e).map(function(){return t(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return r.disabled?!1:(t(this).addClass("ui-state-active"),e=this,a.document.one("mouseup",function(){e=null}),undefined)}).bind("mouseup"+this.eventNamespace,function(){return r.disabled?!1:(t(this).removeClass("ui-state-active"),undefined)}).bind("keydown"+this.eventNamespace,function(e){return r.disabled?!1:((e.keyCode===t.ui.keyCode.SPACE||e.keyCode===t.ui.keyCode.ENTER)&&t(this).addClass("ui-state-active"),undefined)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){t(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===t.ui.keyCode.SPACE&&t(this).click()})),this._setOption("disabled",r.disabled),this._resetButton()},_determineButtonType:function(){var t,e,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(t=this.element.parents().last(),e="label[for='"+this.element.attr("id")+"']",this.buttonElement=t.find(e),this.buttonElement.length||(t=t.length?t.siblings():this.element.siblings(),this.buttonElement=t.filter(e),this.buttonElement.length||(this.buttonElement=t.find(e))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(o+" "+a+" "+r).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(t,e){return this._super(t,e),"disabled"===t?(e?this.element.prop("disabled",!0):this.element.prop("disabled",!1),undefined):(this._resetButton(),undefined)},refresh:function(){var e=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");e!==this.options.disabled&&this._setOption("disabled",e),"radio"===this.type?l(this.element[0]).each(function(){t(this).is(":checked")?t(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):t(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),undefined;var e=this.buttonElement.removeClass(r),i=t("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,o=[];s.primary||s.secondary?(this.options.text&&o.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&e.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&e.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(o.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||e.attr("title",t.trim(i)))):o.push("ui-button-text-only"),e.addClass(o.join(" "))}}),t.widget("ui.buttonset",{version:"1.10.2",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(t,e){"disabled"===t&&this.buttons.button("option",t,e),this._super(t,e)},refresh:function(){var e="rtl"===this.element.css("direction");this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(e?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(e?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})}(jQuery),function(t,e){function i(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.dpDiv=s(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function s(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(i,"mouseout",function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",function(){t.datepicker._isDisabledDatepicker(o.inline?e.parent()[0]:o.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))})}function n(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}t.extend(t.ui,{datepicker:{version:"1.10.2"}});var o,a="datepicker",r=(new Date).getTime();t.extend(i.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return n(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,o;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),o=this._newInst(t(e),n),o.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,o):n&&this._inlineDatepicker(e,o)},_newInst:function(e,i){var n=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?s(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),t.data(e,a,i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,o,a=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),a&&(i.append=t("<span class='"+this._appendClass+"'>"+a+"</span>"),e[r?"before":"after"](i.append)),e.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),o=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:o,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(o?t("<img/>").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.click(function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,a,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,o,r){var h,l,c,u,d,p=this._dialogInst;return p||(this.uuid+=1,h="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+h+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),t("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},t.data(this._dialogInput[0],a,p)),n(p.settings,o||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=r?r.length?r:[r.pageX,r.pageY]:null,this._pos||(l=document.documentElement.clientWidth,c=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[l/2-100+u,c/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],a,p),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,a);s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,a),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty())},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,a)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,s,o){var a,r,h,l,c=this._getInst(i);return 2===arguments.length&&"string"==typeof s?"defaults"===s?t.extend({},t.datepicker._defaults):c?"all"===s?t.extend({},c.settings):this._get(c,s):null:(a=s||{},"string"==typeof s&&(a={},a[s]=o),c&&(this._curInst===c&&this._hideDatepicker(),r=this._getDateDatepicker(i,!0),h=this._getMinMaxDate(c,"min"),l=this._getMinMaxDate(c,"max"),n(c.settings,a),null!==h&&a.dateFormat!==e&&a.minDate===e&&(c.settings.minDate=this._formatDate(c,h)),null!==l&&a.dateFormat!==e&&a.maxDate===e&&(c.settings.maxDate=this._formatDate(c,l)),"disabled"in a&&(a.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(t(i),c),this._autoSize(c),this._setDate(c,r),this._updateAlternate(c),this._updateDatepicker(c)),e)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M"); +break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(i){var s,n,o=t.datepicker._getInst(i.target);return t.datepicker._get(o,"constrainInput")?(s=t.datepicker._possibleChars(t.datepicker._get(o,"dateFormat")),n=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">n||!s||s.indexOf(n)>-1):e},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var i,s,o,a,r,h,l;i=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==i&&(t.datepicker._curInst.dpDiv.stop(!0,!0),i&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),s=t.datepicker._get(i,"beforeShow"),o=s?s.apply(e,[e,i]):{},o!==!1&&(n(i.settings,o),i.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(i),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),a=!1,t(e).parents().each(function(){return a|="fixed"===t(this).css("position"),!a}),r={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(i),r=t.datepicker._checkOffset(i,r,a),i.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":a?"fixed":"absolute",display:"none",left:r.left+"px",top:r.top+"px"}),i.inline||(h=t.datepicker._get(i,"showAnim"),l=t.datepicker._get(i,"duration"),i.dpDiv.zIndex(t(e).zIndex()+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[h]?i.dpDiv.show(h,t.datepicker._get(i,"showOptions"),l):i.dpDiv[h||"show"](h?l:null),i.input.is(":visible")&&!i.input.is(":disabled")&&i.input.focus(),t.datepicker._curInst=i))}},_updateDatepicker:function(e){this.maxRows=4,o=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,s=this._getNumberOfMonths(e),n=s[1],a=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&e.input[0]!==document.activeElement&&e.input.focus(),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_getBorders:function(t){var e=function(t){return{thin:1,medium:2,thick:3}[t]||t};return[parseFloat(e(t.css("border-left-width"))),parseFloat(e(t.css("border-top-width")))]},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,r=this._curInst;!r||e&&r!==t.data(e,a)||this._datepickerShowing&&(i=this._get(r,"showAnim"),s=this._get(r,"duration"),n=function(){t.datepicker._tidyDialog(r)},t.effects&&(t.effects.effect[i]||t.effects[i])?r.dpDiv.hide(i,t.datepicker._get(r,"showOptions"),s,n):r.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(r,"onClose"),o&&o.apply(r.input?r.input[0]:null,[r.input?r.input.val():"",r]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).each(function(){t(this).val(n)}))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(i,s,n){if(null==i||null==s)throw"Invalid arguments";if(s="object"==typeof s?""+s:s+"",""===s)return null;var o,a,r,h,l=0,c=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof c?c:(new Date).getFullYear()%100+parseInt(c,10),d=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,p=(n?n.dayNames:null)||this._defaults.dayNames,f=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,g=(n?n.monthNames:null)||this._defaults.monthNames,m=-1,v=-1,_=-1,b=-1,y=!1,w=function(t){var e=i.length>o+1&&i.charAt(o+1)===t;return e&&o++,e},k=function(t){var e=w(t),i="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n=RegExp("^\\d{1,"+i+"}"),o=s.substring(l).match(n);if(!o)throw"Missing number at position "+l;return l+=o[0].length,parseInt(o[0],10)},x=function(i,n,o){var a=-1,r=t.map(w(i)?o:n,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(r,function(t,i){var n=i[1];return s.substr(l,n.length).toLowerCase()===n.toLowerCase()?(a=i[0],l+=n.length,!1):e}),-1!==a)return a+1;throw"Unknown name at position "+l},D=function(){if(s.charAt(l)!==i.charAt(o))throw"Unexpected literal at position "+l;l++};for(o=0;i.length>o;o++)if(y)"'"!==i.charAt(o)||w("'")?D():y=!1;else switch(i.charAt(o)){case"d":_=k("d");break;case"D":x("D",d,p);break;case"o":b=k("o");break;case"m":v=k("m");break;case"M":v=x("M",f,g);break;case"y":m=k("y");break;case"@":h=new Date(k("@")),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"!":h=new Date((k("!")-this._ticksTo1970)/1e4),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"'":w("'")?D():y=!0;break;default:D()}if(s.length>l&&(r=s.substr(l),!/^\s+/.test(r)))throw"Extra/unparsed characters found in date: "+r;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),b>-1)for(v=1,_=b;;){if(a=this._getDaysInMonth(m,v-1),a>=_)break;v++,_-=a}if(h=this._daylightSavingAdjust(new Date(m,v-1,_)),h.getFullYear()!==m||h.getMonth()+1!==v||h.getDate()!==_)throw"Invalid date";return h},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getYear()%100?"0":"")+e.getYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,i){return t.settings[i]!==e?t.settings[i]:this._defaults[i]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){window["DP_jQuery_"+r].datepicker._adjustDate(s,-i,"M")},next:function(){window["DP_jQuery_"+r].datepicker._adjustDate(s,+i,"M")},hide:function(){window["DP_jQuery_"+r].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+r].datepicker._gotoToday(s)},selectDay:function(){return window["DP_jQuery_"+r].datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+r].datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+r].datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,v,_,b,y,w,k,x,D,C,I,P,T,M,S,z,A,H,N,E,W,O,F,R,j=new Date,L=this._daylightSavingAdjust(new Date(j.getFullYear(),j.getMonth(),j.getDate())),Y=this._get(t,"isRTL"),B=this._get(t,"showButtonPanel"),V=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),q=this._get(t,"showCurrentAtPos"),Q=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],$=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),G=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-q,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=G&&G>e?G:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-Q,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":V?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+Q,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":V?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?$:L,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+a+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),v=this._get(t,"showOtherMonths"),_=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,D=0;U[1]>D;D++){if(C=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",P="",X){if(P+="<div class='ui-datepicker-group",U[1]>1)switch(D){case 0:P+=" ui-datepicker-group-first",I=" ui-corner-"+(Y?"right":"left");break;case U[1]-1:P+=" ui-datepicker-group-last",I=" ui-corner-"+(Y?"left":"right");break;default:P+=" ui-datepicker-group-middle",I=""}P+="'>"}for(P+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+I+"'>"+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,G,J,k>0||D>0,f,g)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",T=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",w=0;7>w;w++)M=(w+c)%7,T+="<th"+((w+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[M]+"'>"+p[M]+"</span></th>";for(P+=T+"</tr></thead><tbody>",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),z=(this._getFirstDayOfMonth(te,Z)-c+7)%7,A=Math.ceil((z+S)/7),H=X?this.maxRows>A?this.maxRows:A:A,this.maxRows=H,N=this._daylightSavingAdjust(new Date(te,Z,1-z)),E=0;H>E;E++){for(P+="<tr>",W=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(N)+"</td>":"",w=0;7>w;w++)O=m?m.apply(t.input?t.input[0]:null,[N]):[!0,""],F=N.getMonth()!==Z,R=F&&!_||!O[0]||G&&G>N||J&&N>J,W+="<td class='"+((w+c+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(N.getTime()===C.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===N.getTime()&&b.getTime()===C.getTime()?" "+this._dayOverClass:"")+(R?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!v?"":" "+O[1]+(N.getTime()===$.getTime()?" "+this._currentClass:"")+(N.getTime()===L.getTime()?" ui-datepicker-today":""))+"'"+(F&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"'")+"'")+(R?"":" data-handler='selectDay' data-event='click' data-month='"+N.getMonth()+"' data-year='"+N.getFullYear()+"'")+">"+(F&&!v?" ":R?"<span class='ui-state-default'>"+N.getDate()+"</span>":"<a class='ui-state-default"+(N.getTime()===L.getTime()?" ui-state-highlight":"")+(N.getTime()===$.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+"' href='#'>"+N.getDate()+"</a>")+"</td>",N.setDate(N.getDate()+1),N=this._daylightSavingAdjust(N);P+=W+"</tr>"}Z++,Z>11&&(Z=0,te++),P+="</tbody></table>"+(X?"</div>"+(U[0]>0&&D===U[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),x+=P}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),v=this._get(t,"changeYear"),_=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(o||!m)y+="<span class='ui-datepicker-month'>"+a[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+r[c]+"</option>");y+="</select>"}if(_||(b+=y+(!o&&m&&v?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";g>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),_&&(b+=(!o&&m&&v?"":" ")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.drawYear+("Y"===i?e:0),n=t.drawMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).mousedown(t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new i,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.10.2",window["DP_jQuery_"+r]=t}(jQuery),function(t){var e={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};t.widget("ui.dialog",{version:"1.10.2",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._destroyOverlay(),this.opener.filter(":focusable").focus().length||t(this.document[0].activeElement).blur(),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,e){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!e&&this._trigger("focus",t),i},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=t(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var t=this.element.find("[autofocus]");t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).focus()},_keepFocus:function(e){function i(){var e=this.document[0].activeElement,i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),undefined;if(e.keyCode===t.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(n.focus(1),e.preventDefault()):(s.focus(1),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=t("<button></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(e),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title||t.html(" "),t.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(e.element[0],arguments)},o={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,t("<button></button>",s).button(o).appendTo(e.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){t(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){s.position=[o.position.left-i.document.scrollLeft(),o.position.top-i.document.scrollTop()],t(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o)) +}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){t(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){s.height=t(this).height(),s.width=t(this).width(),t(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(s){var n=this,o=!1,a={};t.each(s,function(t,s){n._setOption(t,s),t in e&&(o=!0),t in i&&(a[t]=s)}),o&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",a)},_setOption:function(t,e){var i,s,n=this.uiDialog;"dialogClass"===t&&n.removeClass(this.options.dialogClass).addClass(e),"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:""+e}),"draggable"===t&&(i=n.is(":data(ui-draggable)"),i&&!e&&n.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&(s=n.is(":data(ui-resizable)"),s&&!e&&n.resizable("destroy"),s&&"string"==typeof e&&n.resizable("option","handles",e),s||e===!1||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=this,i=this.widgetFullName;t.ui.dialog.overlayInstances||this._delay(function(){t.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(s){e._allowInteraction(s)||(s.preventDefault(),t(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=t("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),t.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(t.ui.dialog.overlayInstances--,t.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),t.ui.dialog.overlayInstances=0,t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{_position:function(){var e,i=this.options.position,s=[],n=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(s=i.split?i.split(" "):[i[0],i[1]],1===s.length&&(s[1]=s[0]),t.each(["left","top"],function(t,e){+s[t]===s[t]&&(n[t]=s[t],s[t]=e)}),i={my:s[0]+(0>n[0]?n[0]:"+"+n[0])+" "+s[1]+(0>n[1]?n[1]:"+"+n[1]),at:s.join(" ")}),i=t.extend({},t.ui.dialog.prototype.options.position,i)):i=t.ui.dialog.prototype.options.position,e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.position(i),e||this.uiDialog.hide()}})}(jQuery),function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var o,a,r,h=t(this),l=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(h,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",g=i.test(u),m={},v="show"===c;h.parent().is(".ui-effects-wrapper")?t.effects.save(h.parent(),l):t.effects.save(h,l),h.show(),o=t.effects.createWrapper(h).css({overflow:"hidden"}),a=o[p](),r=parseFloat(o.css(f))||0,m[p]=v?a:0,g||(h.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),m[f]=v?r:a+r),v&&(o.css(p,0),g||o.css(f,r+a)),o.animate(m,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&h.hide(),t.effects.restore(h,l),t.effects.removeWrapper(h),n()}})}}(jQuery),function(t){t.effects.effect.bounce=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"effect"),l="hide"===h,c="show"===h,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||l?1:0),g=e.duration/f,m=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=a.queue(),y=b.length;for((c||l)&&r.push("opacity"),t.effects.save(a,r),a.show(),t.effects.createWrapper(a),d||(d=a["top"===v?"outerHeight":"outerWidth"]()/3),c&&(o={opacity:1},o[v]=0,a.css("opacity",0).css(v,_?2*-d:2*d).animate(o,g,m)),l&&(d/=Math.pow(2,p-1)),o={},o[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m).animate(o,g,m),d=l?2*d:d/2;l&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m)),a.queue(function(){l&&a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),a.dequeue()}}(jQuery),function(t){t.effects.effect.clip=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"hide"),l="show"===h,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(a,r),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n="IMG"===a[0].tagName?s:a,o=n[d](),l&&(n.css(d,0),n.css(p,o/2)),f[d]=l?o:0,f[p]=l?0:o/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){l||a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","opacity","height","width"],a=t.effects.setMode(n,e.mode||"hide"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,o),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===c?-s:s),u[l]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),g||p.hide(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),g="show"===f,m=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*_,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*v,l=a-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-a*v,top:-o*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(g?l*v:0),top:h+(g?c*_:0),opacity:g?0:1}).animate({left:r+(g?0:l*v),top:h+(g?0:c*_),opacity:g?1:0},e.duration||500,e.easing,s)}}(jQuery),function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}}(jQuery),function(t){t.effects.effect.fold=function(e,i){var s,n,o=t(this),a=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(o,e.mode||"hide"),h="show"===r,l="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=h!==d,f=p?["width","height"]:["height","width"],g=e.duration/2,m={},v={};t.effects.save(o,a),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[l?0:1]),h&&s.css(d?{height:0,width:c}:{height:c,width:0}),m[f[0]]=h?n[0]:c,v[f[1]]=h?n[1]:0,s.animate(m,g,e.easing).animate(v,g,e.easing,function(){l&&o.hide(),t.effects.restore(o,a),t.effects.removeWrapper(o),i()})}}(jQuery),function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],o=t.effects.setMode(s,e.mode||"show"),a={backgroundColor:s.css("backgroundColor")};"hide"===o&&(a.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(a,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&s.hide(),t.effects.restore(s,n),i()}})}}(jQuery),function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),o=t.effects.setMode(n,e.mode||"show"),a="show"===o,r="hide"===o,h=a||"hide"===o,l=2*(e.times||5)+(h?1:0),c=e.duration/l,u=0,d=n.queue(),p=d.length;for((a||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;l>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,l+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),o="hide"===n,a=parseInt(e.percent,10)||150,r=a/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:o?a:100,from:o?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),o=t.effects.setMode(s,e.mode||"effect"),a=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===o?0:100),r=e.direction||"both",h=e.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?a/100:1,x:"vertical"!==r?a/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==o&&(n.origin=h||["middle","center"],n.restore=!0),n.from=e.from||("show"===o?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*c.y,width:l.width*c.x,outerHeight:l.outerHeight*c.y,outerWidth:l.outerWidth*c.x},n.fade&&("show"===o&&(n.from.opacity=0,n.to.opacity=1),"hide"===o&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(a,e.mode||"effect"),f=e.restore||"effect"!==p,g=e.scale||"both",m=e.origin||["middle","center"],v=a.css("position"),_=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&a.show(),s={height:a.height(),width:a.width(),outerHeight:a.outerHeight(),outerWidth:a.outerWidth()},"toggle"===e.mode&&"show"===p?(a.from=e.to||b,a.to=e.from||s):(a.from=e.from||("show"===p?b:s),a.to=e.to||("hide"===p?b:s)),o={from:{y:a.from.height/s.height,x:a.from.width/s.width},to:{y:a.to.height/s.height,x:a.to.width/s.width}},("box"===g||"both"===g)&&(o.from.y!==o.to.y&&(_=_.concat(u),a.from=t.effects.setTransition(a,u,o.from.y,a.from),a.to=t.effects.setTransition(a,u,o.to.y,a.to)),o.from.x!==o.to.x&&(_=_.concat(d),a.from=t.effects.setTransition(a,d,o.from.x,a.from),a.to=t.effects.setTransition(a,d,o.to.x,a.to))),("content"===g||"both"===g)&&o.from.y!==o.to.y&&(_=_.concat(c).concat(l),a.from=t.effects.setTransition(a,c,o.from.y,a.from),a.to=t.effects.setTransition(a,c,o.to.y,a.to)),t.effects.save(a,_),a.show(),t.effects.createWrapper(a),a.css("overflow","hidden").css(a.from),m&&(n=t.effects.getBaseline(m,s),a.from.top=(s.outerHeight-a.outerHeight())*n.y,a.from.left=(s.outerWidth-a.outerWidth())*n.x,a.to.top=(s.outerHeight-a.to.outerHeight)*n.y,a.to.left=(s.outerWidth-a.to.outerWidth)*n.x),a.css(a.from),("content"===g||"both"===g)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),l=r.concat(u).concat(d),a.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,l),i.from={height:s.height*o.from.y,width:s.width*o.from.x,outerHeight:s.outerHeight*o.from.y,outerWidth:s.outerWidth*o.from.x},i.to={height:s.height*o.to.y,width:s.width*o.to.x,outerHeight:s.height*o.to.y,outerWidth:s.width*o.to.x},o.from.y!==o.to.y&&(i.from=t.effects.setTransition(i,u,o.from.y,i.from),i.to=t.effects.setTransition(i,u,o.to.y,i.to)),o.from.x!==o.to.x&&(i.from=t.effects.setTransition(i,d,o.from.x,i.from),i.to=t.effects.setTransition(i,d,o.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,l)})})),a.animate(a.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===a.to.opacity&&a.css("opacity",a.from.opacity),"hide"===p&&a.hide(),t.effects.restore(a,_),f||("static"===v?a.css({position:"relative",top:a.to.top,left:a.to.left}):t.each(["top","left"],function(t,e){a.css(e,function(e,i){var s=parseInt(i,10),n=t?a.to.left:a.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","height","width"],a=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",h=e.distance||20,l=e.times||3,c=2*l+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},g={},m={},v=n.queue(),_=v.length;for(t.effects.save(n,o),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+h,g[d]=(p?"+=":"-=")+2*h,m[d]=(p?"-=":"+=")+2*h,n.animate(f,u,e.easing),s=1;l>s;s++)n.animate(g,u,e.easing).animate(m,u,e.easing);n.animate(g,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","width","height"],a=t.effects.setMode(n,e.mode||"show"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u={};t.effects.save(n,o),n.show(),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,c?isNaN(s)?"-"+s:-s:s),u[l]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}}(jQuery),function(t){t.widget("ui.menu",{version:"1.10.2",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.mouseHandled=!0,this.select(e),i.has(".ui-menu").length?this.expand(e):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,o,a,r,h=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:h=!1,n=this.previousFilter||"",o=String.fromCharCode(e.keyCode),a=!1,clearTimeout(this.filterTimer),o===n?a=!0:o=n+o,r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=a&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(o=String.fromCharCode(e.keyCode),r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=o,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}h&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("<span>").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)}})}(jQuery),function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var o,a=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(o!==e)return o;var i,s,n=t("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),a=n.children()[0];return t("body").append(n),i=a.offsetWidth,n.css("overflow","scroll"),s=a.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),o=i-s},getScrollInfo:function(e){var i=e.isWindow?"":e.element.css("overflow-x"),s=e.isWindow?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,o="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:o?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]);return{element:i,isWindow:s,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s?i.width():i.outerWidth(),height:s?i.height():i.outerHeight()}}},t.fn.position=function(e){if(!e||!e.of)return f.apply(this,arguments);e=t.extend({},e);var o,p,g,m,v,_,b=t(e.of),y=t.position.getWithinInfo(e.within),w=t.position.getScrollInfo(y),k=(e.collision||"flip").split(" "),x={};return _=n(b),b[0].preventDefault&&(e.at="left top"),p=_.width,g=_.height,m=_.offset,v=t.extend({},m),t.each(["my","at"],function(){var t,i,s=(e[this]||"").split(" ");1===s.length&&(s=l.test(s[0])?s.concat(["center"]):c.test(s[0])?["center"].concat(s):["center","center"]),s[0]=l.test(s[0])?s[0]:"center",s[1]=c.test(s[1])?s[1]:"center",t=u.exec(s[0]),i=u.exec(s[1]),x[this]=[t?t[0]:0,i?i[0]:0],e[this]=[d.exec(s[0])[0],d.exec(s[1])[0]]}),1===k.length&&(k[1]=k[0]),"right"===e.at[0]?v.left+=p:"center"===e.at[0]&&(v.left+=p/2),"bottom"===e.at[1]?v.top+=g:"center"===e.at[1]&&(v.top+=g/2),o=i(x.at,p,g),v.left+=o[0],v.top+=o[1],this.each(function(){var n,l,c=t(this),u=c.outerWidth(),d=c.outerHeight(),f=s(this,"marginLeft"),_=s(this,"marginTop"),D=u+f+s(this,"marginRight")+w.width,C=d+_+s(this,"marginBottom")+w.height,I=t.extend({},v),P=i(x.my,c.outerWidth(),c.outerHeight());"right"===e.my[0]?I.left-=u:"center"===e.my[0]&&(I.left-=u/2),"bottom"===e.my[1]?I.top-=d:"center"===e.my[1]&&(I.top-=d/2),I.left+=P[0],I.top+=P[1],t.support.offsetFractions||(I.left=h(I.left),I.top=h(I.top)),n={marginLeft:f,marginTop:_},t.each(["left","top"],function(i,s){t.ui.position[k[i]]&&t.ui.position[k[i]][s](I,{targetWidth:p,targetHeight:g,elemWidth:u,elemHeight:d,collisionPosition:n,collisionWidth:D,collisionHeight:C,offset:[o[0]+P[0],o[1]+P[1]],my:e.my,at:e.at,within:y,elem:c})}),e.using&&(l=function(t){var i=m.left-I.left,s=i+p-u,n=m.top-I.top,o=n+g-d,h={target:{element:b,left:m.left,top:m.top,width:p,height:g},element:{element:c,left:I.left,top:I.top,width:u,height:d},horizontal:0>s?"left":i>0?"right":"center",vertical:0>o?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>g&&g>r(n+o)&&(h.vertical="middle"),h.important=a(r(i),r(s))>a(r(n),r(o))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(I,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,o=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-o-n;e.collisionWidth>o?h>0&&0>=l?(i=t.left+h+e.collisionWidth-o-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+o-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=a(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,o=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-o-n;e.collisionHeight>o?h>0&&0>=l?(i=t.top+h+e.collisionHeight-o-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+o-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=a(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,a=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-a-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-a-o,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,a=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-a-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-a-o,t.top+p+f+g>c&&(0>s||r(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,t.top+p+f+g>u&&(i>0||u>r(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,o,a=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(a?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},a&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)e.style[o]=s[o];e.appendChild(r),i=a||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()}(jQuery),function(t,e){t.widget("ui.progressbar",{version:"1.10.2",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=t("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue() +},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})}(jQuery),function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.2",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",a=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)a.push(o);this.handles=n.add(t(a.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):this.range=t([])},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,o,a,r,h,l,c=this,u=this.options;return u.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-c.values(e));(n>i||n===i&&(e===c._lastChangedValue||c.values(e)===u.min))&&(n=i,o=t(this),a=e)}),r=this._start(e,a),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=a,o.addClass("ui-state-active").focus(),h=o.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-o.width()/2,top:e.pageY-h.top-o.height()/2-(parseInt(o.css("borderTopWidth"),10)||0)-(parseInt(o.css("borderBottomWidth"),10)||0)+(parseInt(o.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,a,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,o;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),o=this._valueMin()+s*n,this._trimAlignValue(o)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,o;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,o=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),o!==!1&&this.values(e,i,!0))):i!==this.value()&&(o=this._trigger("slide",t,{handle:this.handles[e],value:i}),o!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,o;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],o=0;s.length>o;o+=1)s[o]=this._trimAlignValue(n[o]),this._change(null,o);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,o,a=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,c={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),c["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](c,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),o=this._valueMax(),i=o!==n?100*((s-n)/(o-n)):0,c["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](c,r.animate),"min"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===a&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===a&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,o,a,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(a=this.options.step,n=o=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:o=this._valueMin();break;case t.ui.keyCode.END:o=this._valueMax();break;case t.ui.keyCode.PAGE_UP:o=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:o=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;o=this._trimAlignValue(n+a);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;o=this._trimAlignValue(n-a)}this._slide(i,r,o)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})}(jQuery),function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.2",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>▲</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>▼</span>"+"</a>"},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})}(jQuery),function(t,e){function i(){return++n}function s(t){return t.hash.length>1&&decodeURIComponent(t.href.replace(o,""))===decodeURIComponent(location.href.replace(o,""))}var n=0,o=/#.*$/;t.widget("ui.tabs",{version:"1.10.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,o){return t(o).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),o=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:o=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,o),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var o,a,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),c=l.attr("aria-controls");s(n)?(o=n.hash,a=e.element.find(e._sanitizeSelector(o))):(r=e._tabId(l),o="#"+r,a=e.element.find(o),a.length||(a=e._createPanel(r),a.insertAfter(e.panels[i-1]||e.tablist)),a.attr("aria-live","polite")),a.length&&(e.panels=e.panels.add(a)),c&&l.data("ui-tabs-aria-controls",c),l.attr({"aria-controls":o.substring(1),"aria-labelledby":h}),a.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,o=this.tabs.eq(e),a=o.find(".ui-tabs-anchor"),r=this._getPanelForTab(o),h={tab:o,panel:r};s(a[0])||(this.xhr=t.ajax(this._ajaxSettings(a,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(o.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),o.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})}(jQuery),function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.2",options:{content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=o),this._open(e,t,i) +})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function o(t){l.of=t,a.is(":hidden")||a.position(l)}var a,r,h,l=t.extend({},this.options.position);if(n){if(a=this._find(s),a.length)return a.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),a=this._tooltip(s),e(s,a.attr("id")),a.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:o}),o(i)):a.position(t.extend({of:s},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){a.is(":visible")&&(o(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:a}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(a)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),o.stop(!0),this._hide(o,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:o}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("<div>").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("<div>").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})}(jQuery);
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/common-functions.tld b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/common-functions.tld new file mode 100644 index 0000000..ffe076d --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/common-functions.tld @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- +/******************************************************************************* + * Copyright (c) 2012-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<taglib + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" + version="2.1"> + + <tlib-version>1.0</tlib-version> + <short-name>Winery_Common_Functions</short-name> + <uri>http://www.eclipse.org/winery/functions</uri> + + <!-- from org.eclipse.winery.common.ModelUtilities --> + <function> + <name>winerysPropertiesDefinition</name> + <function-class>org.eclipse.winery.common.ModelUtilities</function-class> + <function-signature>org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition getWinerysPropertiesDefinition(org.eclipse.winery.model.tosca.TEntityType)</function-signature> + </function> + + <!-- from org.eclipse.winery.common.Util --> + <function> + <name>convertQNameListToNamespaceToLocalNameList</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.util.SortedMap convertQNameListToNamespaceToLocalNameList(java.util.List)</function-signature> + </function> + <function> + <name>getType</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>org.eclipse.winery.model.tosca.TEntityType getType(org.eclipse.winery.common.interfaces.IWineryRepository, javax.xml.namespace.QName, java.lang.Class)</function-signature> + </function> + <function> + <name>makeCSSName</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String makeCSSName(java.lang.String, java.lang.String)</function-signature> + </function> + <function> + <name>XMLAsString</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String getXMLAsString(java.lang.Class, java.lang.Object)</function-signature> + </function> + <function> + <name>DOMElementAsString</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String getXMLAsString(org.w3c.dom.Element)</function-signature> + </function> + <function> + <name>qname2href</name> + <function-class>org.eclipse.winery.common.Util</function-class> + <function-signature>java.lang.String qname2href(java.lang.String, java.lang.Class, javax.xml.namespace.QName)</function-signature> + </function> + + <!-- from Apache Commons Lang3 --> + <function> + <name>escapeHtml4</name> + <function-class>org.apache.commons.lang3.StringEscapeUtils</function-class> + <function-signature>java.lang.String escapeHtml4(java.lang.String)</function-signature> + </function> +</taglib> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/functions.tld b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/functions.tld new file mode 100644 index 0000000..4157f96 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/functions.tld @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<taglib + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" + version="2.1"> + + <tlib-version>1.0</tlib-version> + <short-name>Winery_TopologyModeler_Functions</short-name> + <uri>http://www.eclipse.org/winery/topologymodeler/functions</uri> + + <function> + <name>convertQNameWithNameListToNamespaceToLocalNameNamePairList</name> + <function-class>org.eclipse.winery.topologymodeler.WineryUtil</function-class> + <function-signature>java.util.SortedMap convertQNameWithNameListToNamespaceToLocalNameNamePairList(java.util.List)</function-signature> + </function> + + <function> + <name>escapeHtml4</name> + <function-class>org.apache.commons.lang3.StringEscapeUtils</function-class> + <function-signature>java.lang.String escapeHtml4(java.lang.String)</function-signature> + </function> +</taglib> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/about.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/about.tag new file mode 100644 index 0000000..7cb73b2 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/about.tag @@ -0,0 +1,58 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@tag description="About for the repository" pageEncoding="UTF-8"%> + +<div class="modal fade" id="about"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Winery Topology Modeler ${project.version}</h4> + </div> + <div class="modal-body"> + <p> Supporting <a href="docs.oasis-open.org/tosca/TOSCA/v1.0/os/TOSCA-v1.0-os.html">TOSCA-v1.0 – + Topology and Orchestration Specification for Cloud Applications Version 1.0. 25 November 2013. OASIS Standard.</a><br/> + <br/> + Part of the <a href="http://www.cloudcycle.org">CloudCycle</a> ecosystem.<br/> + <br/> + Code contributions by Oliver Kopp, Uwe Breitenbücher, Kálmán Képes, Yves Schubert, and Tobias Unger. + </p> + <h3>License</h3> + <p>The Eclipse Foundation makes available all content of this software (“Content”). + Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 (“EPL”) and the and the Apache License 2.0. + A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. + A copy of the ASL is available at <a href="http://www.apache.org/licenses/LICENSE-2.0.html">http://www.apache.org/licenses/LICENSE-2.0.html</a>. + For purposes of the EPL, “Program” will mean the Content.</p> + <p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (“Redistributor”) and different terms and conditions may apply to your use of any object code in the Content. + Check the Redistributor's license that was provided with the Content. + If no such license exists, contact the Redistributor. + Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" data-dismiss="modal" id="aboutDiagOKButton">Ok</button> + </div> + </div> + </div> +</div> + +<script> +$("#about").on("shown.bs.modal", function() { + $("#aboutDiagOKButton").focus(); +}); + +function showAbout() { + $("#about").modal("show"); +} +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/QNameChooser.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/QNameChooser.tag new file mode 100644 index 0000000..7a2c067 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/QNameChooser.tag @@ -0,0 +1,46 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Dialog parts for choosing a QName" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> + +<%@attribute name="allQNames" required="true" type="java.util.Collection" description="Collection<QName> of all available QNames" %> +<%@attribute name="includeNONE" required="false" type="java.lang.Boolean" description="Should (none) be included as option?"%> +<%@attribute name="selected" required="false" description="The initial value to select"%> +<%@attribute name="labelOfSelectField" required="true"%> +<%@attribute name="idOfSelectField" required="true"%> + +<div class="form-group"> + <c:if test="${not empty labelOfSelectField}"><label for="${idOfSelectField}" class="control-label">${labelOfSelectField}:</label></c:if> + <select id="${idOfSelectField}" name="${idOfSelectField}" class="form-control"> + <c:if test="${includeNONE}"><option value="(none)">(none)</option></c:if> + <c:forEach var="namespaceEntry" items="${wc:convertQNameListToNamespaceToLocalNameList(allQNames)}"> + <optgroup label="${namespaceEntry.key}"> + <c:forEach var="localName" items="${namespaceEntry.value}"> + <option value="{${namespaceEntry.key}}${localName}">${localName}</option> + </c:forEach> + </optgroup> + </c:forEach> + </select> +</div> + +<script> +$(function(){ + $("#${idOfSelectField}").select2(); + <c:if test="${not empty selected}"> + $("#${idOfSelectField}").select2("val", "${selected}"); + </c:if> +}); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/artifactcreationdialog.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/artifactcreationdialog.tag new file mode 100644 index 0000000..5e49b04 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/artifactcreationdialog.tag @@ -0,0 +1,443 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Dialog for adding an implementation / deployment artifact" pageEncoding="UTF-8"%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="fup" tagdir="/WEB-INF/tags/common"%> + +<%@attribute name="name" required="true" description="Implementation | Deployment"%> +<%@attribute name="repositoryURL" required="true" description="the URL of Winery's repository"%> +<%@attribute name="onSuccessfulArtifactCreationFunction" required="true" description="javascript code to be executed when the artifact has been successfully created. Parameter: artifactInfo"%> +<%@attribute name="allArtifactTypes" required="true" type="java.util.Collection" description="All available artifact types"%> +<%@attribute name="allNamespaces" required="true" type="java.util.Collection" description="All known namespaces"%> +<%@attribute name="defaultNSForArtifactTemplate" required="true" description="the default namespace of the artifact template"%> + +<%-- either URL or a function to be called for addition --%> +<%@attribute name="URL" required="true" description="the URL of the artifact collection. May also be a function returning the correct URL (used at the topology modeler). I.e., it is an expression being evaluated"%> + +<%@attribute name="isDeploymentArtifact" required="true" type="java.lang.Boolean" description="Is this dialog used to create deployment artifacts?"%> +<%-- required if implementation artifact --%> +<%@attribute name="interfacesOfAssociatedType" type="java.util.List" %> + +<script> +// TODO: check if allArtifactTypes is empty -> then an error message should be shown. Alternative: Add "Manage" button next to "artifact types" + +function addArtifact() { + if (highlightRequiredFields()) { + vShowError("Please fill out required fields."); + return; + } + + var artifactTemplateCreationMode = $("input[name='artifactTemplateCreation']:checked").val(); + var autoCreateArtifactTemplate = (artifactTemplateCreationMode=="createArtifactTemplate"); + + if (autoCreateArtifactTemplate && ($("#artifactTemplateNameIsValid:visible").hasClass("invalid"))) { + vShowError("Please ensure that the artifact template QName is valid."); + return; + } + + + /* begin: form serialization */ + + var theForm = $('#add${name}ArtifactForm'); + + // do not serialze hidden fields + // theForm.find("select:hidden,input:hidden").attr("disabled", "disabled"); + // Because we use "select2", the user-visible select fields are divs. The "real" selects are hidden. + // Therefore, we disable fields manually :) + var disabledFields; + if (artifactTemplateCreationMode == "skipArtifactTemplate") { + disabledFields = ["artifactTemplateName", "artifactTemplateNS", "artifactTemplateToLink"]; + } else if (artifactTemplateCreationMode == "createArtifactTemplate") { + disabledFields = ["artifactTemplateToLink"]; + } else if (artifactTemplateCreationMode == "linkArtifactTemplate") { + disabledFields = ["artifactTemplateName", "artifactTemplateNS", "artifactType"]; + } else { + vShowError("Code not consistent with UI"); + } + + // make a clean form + disabledFields.forEach(function(element) { + $("#"+element).attr("disabled", "disabled"); + }); + $("input[name='artifactTemplateCreation']").attr("disabled", "disabled"); + + // do not serialize choice directly, but ... + // ... append "autoCreateArtifactTemplate=true" in case the artifact template should be auto created + var data = theForm.serialize(); + if (autoCreateArtifactTemplate) { + data = data + "&autoCreateArtifactTemplate=true"; + } + + // enable fields again + disabledFields.forEach(function(element) { + $("#"+element).removeAttr("disabled"); + }); + $("input[name='artifactTemplateCreation']").removeAttr("disabled"); + + /* end: form serialization */ + + <c:if test="${not isDeploymentArtifact}"> + var operationVal = $("#operationName").val(); + if ((operationVal) && (operationVal != "")) { + var operationName = $("#operationName option:selected").text(); + // The operationname is prefixed with the namespace, because of "nextselect" + // we have to undo that effect. + // Therefore, we replace the complete operationName parameter + + var pos = data.indexOf("operationName="); + var posNextParam = data.indexOf("&", pos); + data = data.substr(0, pos) + "operationName=" + operationName + data.substr(posNextParam); + } + </c:if> + + // We assume that the artifact type exists + // i.e., that it was not deleted during loading of the dialog + + // The deployment artifact resource allows auto creation of the artifact template + // We do not need to do that manually using a separate POST call + // TODO: In a future version, this might be better have a clean way to create additional content for an artifact template + + // do the addCall + $.ajax({ + url: ${URL}, + type: "POST", + async: false, + "data": data, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not create ${name} Artifact", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + // prepare data for onSuccessfulArtifactCreationFunction + // even though interaceName and operationName do not exist at DA, accessing it via jQuery works: then "undefined" is returned, which is OK + var artifactInfo = { + name: $("#artifactName").val(), + interfaceName: $("#interfaceName").val(), + operationName: $("#operationName option:selected").text() + }; + if (artifactTemplateCreationMode == "skipArtifactTemplate") { + // artifactTemplate remains unset as there is not artifactTemplate to be created + artifactInfo.artifactType = $("#artifactType").val(); + } else if (artifactTemplateCreationMode == "createArtifactTemplate") { + artifactInfo.artifactTemplateName = $("#artifactTemplateName").val(); + // FIXME: This is a quick hack - the name could have been changed at the server as it might contain invalid characters for an id + // In other words, $("#artifactTemplateName").val() might not be the localName of the artifactTemplate + artifactInfo.artifactTemplate = "{" + $("#artifactTemplateNS").val() + "}" + $("#artifactTemplateName").val(); + artifactInfo.artifactType = $("#artifactType").val(); + } else if (artifactTemplateCreationMode == "linkArtifactTemplate") { + artifactInfo.artifactTemplateName = $("#artifactTemplateToLink option:selected").text(); + artifactInfo.artifactTemplate = $("#artifactTemplateToLink").val(); + // artifact type is a mandantory field + // we have to ask the artifact template for the QName of its type and then use this data + require(["winery-support-common"], function(wsc) { + var nsAndId = wsc.getNamespaceAndLocalNameFromQName(artifactInfo.artifactTemplate); + var url = makeArtifactTemplateURL("${repositoryURL}", nsAndId.namespace, nsAndId.localname); + $.ajax({ + type: "GET", + async: false, + url: url + "?type", + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not get type of artifact template", jqXHR, errorThrown); + return; + }, + success: function(resData, textStatus, jqXHR) { + // QName is directly returned + artifactInfo.artifactType = resData; + } + }); + }); + } else { + vShowError("Code not consistent with UI"); + } + // now, artifactInfo is filled completly + + // the function can be called + ${onSuccessfulArtifactCreationFunction}(artifactInfo); + + $('#add${name}ArtifactDiag').modal('hide'); + vShowSuccess("Artifact added successfully"); + + if (autoCreateArtifactTemplate) { + var aritfactTemplateNS = $("#artifactTemplateNS").val(); + var artifactTemplateName = $("#artifactTemplateName").val(); + var artifactTemplateURL = makeArtifactTemplateURL("${repositoryURL}", aritfactTemplateNS, artifactTemplateName); + $("#artifactTemplateNameAtUploadFiles").text(artifactTemplateName).attr("href", artifactTemplateURL); + var url = artifactTemplateURL + "files/"; + $('#fileupload').fileupload('option', 'url', url); + $("#addFilesToArtifactTemplate").modal('show'); + } + } + }); + +} +</script> + +<c:if test="${not isDeploymentArtifact}"> + <script type="text/javascript" src="${pageContext.request.contextPath}/js/nextselect.js"></script> + <script> + var dependendSelects = {"#interfaceName": "#operationName"}; + var interfaceOpData = { + "": { + label : "(none)", + "options" : [] + }<c:if test="${not empty interfacesOfAssociatedType}">,</c:if> + <c:forEach var="t" items="${interfacesOfAssociatedType}"> + // no label necessary as this list is pre-filled + "${t.name}": { + "options" : [ + "", + <c:forEach var="u" varStatus="loop" items="${t.operationsResouce.listOfAllEntityIdsAsList}"> + "${t.name}:${u}"<c:if test="${!loop.last}">,</c:if> + </c:forEach> + ] + }, + </c:forEach> + <c:forEach var="t" varStatus="outerLoop" items="${interfacesOfAssociatedType}"> + <c:forEach var="u" varStatus="innerLoop" items="${t.operationsResouce.listOfAllEntityIdsAsList}"> + "${t.name}:${u}" : { + "label": "${u}" + }<c:if test="${!innerLoop.last or !outerLoop.last}">,</c:if> + </c:forEach> + </c:forEach> + }; + </script> +</c:if> + +<div class="modal fade" id="add${name}ArtifactDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add ${name} Artifact</h4> + </div> + <div class="modal-body"> + <form id="add${name}ArtifactForm" enctype="multipart/form-data"> + <fieldset> + + <div class="form-group"> + <label>Name</label> + <input class="form-control" name="artifactName" id="artifactName" type="text" required="required" autocomplete="on" /> + </div> + + <c:if test="${not isDeploymentArtifact}"> + <div class="form-group"> + <label for="interfaceName">Interface Name</label> + <select name="interfaceName" id="interfaceName" class="form-control" onchange="updateListContent(this.value, '#operationName', dependendSelects, interfaceOpData);"> + <option value="" selected="selected">(none)</option> + <c:forEach var="t" items="${interfacesOfAssociatedType}"> + <option value="${t.name}">${t.name}</option> + </c:forEach> + </select> + </div> + + <div class="form-group"> + <label for="operationName">Operation Name</label> + <select name="operationName" id="operationName" class="form-control"> + <%-- options filled by updateListContent defined by nextselect.js --%> + </select> + </div> + </c:if> + + <h4>Artifact Template Creation</h4> + <div class="radio"> + <label> + <input type="radio" name="artifactTemplateCreation" value="createArtifactTemplate" checked="checked" id="createArtifactTemplateInput">Create Artifact Template</input> + </label> + <p class="help-block">Check if you want to upload <strong>new</strong> files, you do not want to reuse existing files and you do not point to an image library.</p> + </div> + <div class="radio"> + <label> + <input type="radio" name="artifactTemplateCreation" value="linkArtifactTemplate">Link Artifact Template</input> + </label> + <p class="help-block">Check if you want to reuse existing files.</p> + </div> + <div class="radio"> + <label> + <input type="radio" name="artifactTemplateCreation" value="skipArtifactTemplate">Do not create an artifact template</input> + </label> + <p class="help-block">Check if you want to point to an image library.</p> + </div> + </fieldset> + <fieldset id="artifactTypeFieldset"> + <div class="form-group" id="artifactTypeDiv"> + <label for="artifactType">Artifact Type</label> + <select name="artifactType" class="form-control" id="artifactType"> + <c:forEach var="t" items="${allArtifactTypes}"> + <option value="${t.toString()}">${t.localPart}</option> + </c:forEach> + </select> + </div> + </fieldset> + <fieldset> + + <fup:artifacttemplateselection allNamespaces="${allNamespaces}" repositoryURL="${repositoryURL}" defaultNSForArtifactTemplate="${defaultNSForArtifactTemplate}"/> + + <div id="linkArtifactTemplate" class="form-group" style="display:none;"> + <label for="divArtifactTemplateToLink">Artifact Template</label> + <div id="divArtifactTemplateToLink"> + <%-- filled by jQuery at openAdd${name}ArtifactDiag() --%> + <select id=artifactTemplateToLink name="artifactTemplate" class="form-control" style="max-width: 90%"> + </select> + <%-- URL is changed each time the selection is changed --%> + <a href="#" target="_blank" class="btn btn-info btn-sm" id="viewArtifactTemplateToLink">view</a> + </div> + </div> + </fieldset> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" onclick="addArtifact();">Add</button> + </div> + </div> + </div> +</div> + + +<script> +function openAdd${name}ArtifactDiag() { + $.ajax({ + url: "${repositoryURL}/artifacttemplates/", + dataType: "json", + async: false, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch available artifact templates", jqXHR, errorThrown); + }, + success: function(data, textStatus, jqXHR) { + var select = $("#artifactTemplateToLink"); + select.empty(); + $.each(data, function(index, o) { + var qname = "{" + this.namespace + "}" + this.id; + var option = '<option value="' + qname + '">' + this.name + '</option>'; + select.append(option); + if (index==0) { + // first element + // this is the selected element + // we put it as href to the "view" button + $("#viewArtifactTemplateToLink").attr("href", makeArtifactTemplateURL("${repositoryURL}", this.namespace, this.id)); + } + }); + select.trigger("change"); + $('#add${name}ArtifactDiag').modal('show'); + } + }); +} + +requirejs(["select2"], function() { + $("#interfaceName").select2(); + <c:if test="${not isDeploymentArtifact}"> + // the dependend select cannot be a select2 until https://github.com/ivaynberg/select2/issues/1656 is resolved + //$("#operationName").select2(); + </c:if> + $("#artifactType").select2(); + $("#artifactTemplateToLink").select2(); +}); + +requirejs(['tmpl', 'jquery.ui.widget', 'jquery.fileupload', 'jquery.fileupload-ui'], function() { + $('#fileupload').fileupload({ + "autoUpload": true + }); +}); + +$(function(){ + $("input[name='artifactTemplateCreation']").on("change", function(e) { + var choice = $(e.target).attr("value"); + if (choice == "skipArtifactTemplate") { + $(".createArtifactTemplate").hide(); + $("#linkArtifactTemplate").hide(); + $("#artifactTypeFieldset").removeAttr("disabled"); + $("#artifactTypeDiv").show(); + } else if (choice == "createArtifactTemplate") { + $(".createArtifactTemplate").show(); + $("#linkArtifactTemplate").hide(); + $("#artifactTypeFieldset").removeAttr("disabled"); + $("#artifactTypeDiv").show(); + // one might be copy the template name to the artifact template name (if ($("#artifactTemplateName").val() == "")) + } else if (choice == "linkArtifactTemplate") { + $(".createArtifactTemplate").hide(); + $("#linkArtifactTemplate").show(); + $("#artifactTypeFieldset").attr("disabled", "disabled"); + $("#artifactTypeDiv").hide(); + } else { + vShowError("Code not consistent with UI"); + }; + }); + + $("#add${name}ArtifactDiag").on('shown.bs.modal', function() { + $(this).find('form')[0].reset(); + // createArtifactTemplate is the default seeting for the form + // reset the dialog to this choice + $("#createArtifactTemplateInput").trigger("change"); + }); + + $("#artifactName").typing({ + start: function(event, $elem) { + if (syncDAnameWithATname) { + require(["artifacttemplateselection"], function(ats) { + ats.flagArtifactTemplateNameAsUpdating(); + }); + } + }, + stop: function(event, $elem) { + // value is copied at the "change keyup input" event at #artifactName + require(["artifacttemplateselection"], function(ats) { + ats.checkArtifactTemplateName(); + }); + } + }); + + $("#artifactName") + // tip by http://solicitingfame.com/2011/11/09/jquery-keyup-vs-bind/ + .bind("change keyup input", function() { + if (syncDAnameWithATname) { + $("#artifactTemplateName").val(this.value); + } + }) + .on("focus", function() { + syncDAnameWithATname = ($("#artifactTemplateName").is(":visible")) && (this.value == $("#artifactTemplateName").val()); + }); + + $("#artifactTemplateToLink").on("change", function(evt) { + if (evt.val) { + // TODO: possibly use makeArtifactTemplateURL("${repositoryURL}", this.namespace, this.id)) here + require(["winery-support-common"], function(w) { + var fragment = w.getURLFragmentOutOfFullQName(evt.val); + var url = "${repositoryURL}/artifacttemplates/" + fragment + "/"; + $("#viewArtifactTemplateToLink").attr("href", url); + }); + } + }); +}); +</script> + + +<%-- file uploading part --%> + +<div class="modal fade" id="addFilesToArtifactTemplate"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Add files to artifact template <a id="artifactTemplateNameAtUploadFiles"></a></h4> + </div> + <div class="modal-body"> + <fup:jquery-file-upload-full loadexistingfiles="false"></fup:jquery-file-upload-full> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + <!-- addFilesToArtifactTemplate --> + </div> + </div> +</div> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/artifacttemplateselection.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/artifacttemplateselection.tag new file mode 100644 index 0000000..05c6138 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/artifacttemplateselection.tag @@ -0,0 +1,41 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="dialog for selecting one artifacttemplate" pageEncoding="UTF-8"%> + +<%@attribute name="allNamespaces" required="true" type="java.util.Collection" description="All known namespaces"%> +<%@attribute name="repositoryURL" required="true" description="the URL of Winery's repository"%> +<%@attribute name="defaultNSForArtifactTemplate" required="true" description="the default namespace of the artifact template"%> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags"%> + +<div class="form-group-grouping"> + <!-- createArtifactTemplate class is required for artifactcreationdialog --> + <div class="form-group createArtifactTemplate"> + <label>Artifact Template Name</label> + <!-- name is an NCName --> + <input class="artifactData form-control" id="artifactTemplateName" name="artifactTemplateName" type="text" required="required" autocomplete="on" placeholder="Enter name for artifact template" pattern="[\i-[:]][\c-[:]]*"/> + <div id="artifactTemplateNameIsValid" class="invalid"> + <span id="artifactTemplateNameIsInvalidReason"></span> + </div> + </div> + + <t:namespaceChooser allNamespaces="${allNamespaces}" idOfInput="artifactTemplateNS" selected="${defaultNSForArtifactTemplate}"></t:namespaceChooser> +</div> + +<script> +require(["artifacttemplateselection"], function(ast) { + // configure the plugin + ast.setRepositoryURL("${repositoryURL}"); +}); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/id_name_type.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/id_name_type.tag new file mode 100644 index 0000000..b88a9a9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/id_name_type.tag @@ -0,0 +1,36 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Dialog parts for name and type choosing" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> +<%@taglib prefix="w" tagdir="/WEB-INF/tags/common"%> + + +<%@attribute name="allTypes" required="true" type="java.util.Collection" description="Collection<QName> of all available types" %> +<%@attribute name="idPrefix" required="true" description="prefix used for name and type field. E.g., 'Req' becomes 'ReqType'."%> +<%@attribute name="hideIdField" required="false" description="if given, id field is not displayed. Quick hack to have this dialog reusable. Future versions might always show the id dialog and provide sync between name and id"%> + + <c:if test="${not hideIdField}"> + <div class="form-group"> + <label for="${idPrefix}Id" class="control-label">Id:</label> + <input id="${idPrefix}Id" class="form-control" name="${shortName}Name" type="text" required="required" disabled="disabled"/> + </div> + </c:if> + <div class="form-group"> + <label for="${idPrefix}Name" class="control-label">Name:</label> + <input id="${idPrefix}Name" class="form-control" name="${shortName}Name" type="text" required="required" /> + </div> + +<w:QNameChooser allQNames="${allTypes}" idOfSelectField="${idPrefix}Type" labelOfSelectField="Type" /> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/jquery-file-upload-full.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/jquery-file-upload-full.tag new file mode 100644 index 0000000..5bc1057 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/jquery-file-upload-full.tag @@ -0,0 +1,181 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="HTML + JavaScript enabling the full jQuery file upload as shown at http://blueimp.github.com/jQuery-File-Upload/" pageEncoding="UTF-8"%> + +<%-- Original Source https://raw.github.com/blueimp/jQuery-File-Upload/9.5.4/jquery-ui.html, License: MIT; See also CQ 8006 --%> + +<%@attribute name="action" required="false" description="custom action for the upload"%> +<%@attribute name="loadexistingfiles" type="java.lang.Boolean" required="true" description="load existing files from files/ url. false if that should not happen"%> + +<%-- +!! USES HARD-CODED URL "files/" for data !! +It is OK since it is currently only used in "files.jsp" +If it will be used in other places, there has to be a parameter "url" introduced +(and this jsp updated to a tag file) +--%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + +<%-- The File Upload user interface plugin --%> + + <!-- The file upload form used as target for the file upload widget --> + <form id="fileupload" method="POST" enctype="multipart/form-data" <c:if test="${not empty action}">action="${action}"</c:if>> + <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload --> + <div class="row fileupload-buttonbar"> + <div class="span7"> <!-- should be col-lg-7, but then the add button does not work any more --> + <!-- The fileinput-button span is used to style the file input field as button --> + <span class="btn btn-success fileinput-button"> + <i class="glyphicon glyphicon-plus"></i> + <span>Add files...</span> + <input type="file" name="files[]" multiple> + </span> + </div> + <!-- The global progress information --> + <div class="span5 fileupload-progress fade"> + <!-- The global progress bar --> + <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100"> + <div class="bar" style="width:0%;"></div> + </div> + <!-- The extended global progress information --> + <div class="progress-extended"> </div> + </div> + </div> + <!-- The loading indicator is shown during file processing --> + <div class="fileupload-loading"></div> + <br> + <!-- The table listing the files available for upload/download --> + <table role="presentation" class="table table-striped"><tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery"></tbody></table> + </form> + +<!-- The template to display files available for upload --> +<script id="template-upload" type="text/x-tmpl"> +{% for (var i=0, file; file=o.files[i]; i++) { %} + <tr class="template-upload fade"> + <td> + <span class="preview"></span> + </td> + <td> + <p class="name">{%=file.name%}</p> + <strong class="error text-danger"></strong> + </td> + <td> + <p class="size">Processing...</p> + <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div> + </td> + <td> + {% if (!i && !o.options.autoUpload) { %} + <button class="btn btn-primary start" disabled> + <i class="glyphicon glyphicon-upload"></i> + <span>Start</span> + </button> + {% } %} + {% if (!i) { %} + <button class="btn btn-warning cancel"> + <i class="glyphicon glyphicon-ban-circle"></i> + <span>Cancel</span> + </button> + {% } %} + </td> + </tr> +{% } %} +</script> +<!-- The template to display files available for download --> +<script id="template-download" type="text/x-tmpl"> +{% for (var i=0, file; file=o.files[i]; i++) { %} + <tr class="template-download fade"> + <td> + <span class="preview"> + {% if (file.thumbnailUrl) { %} + <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a> + {% } %} + </span> + </td> + <td> + <p class="name"> + {% if (file.url) { %} + <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a> + {% } else { %} + <span>{%=file.name%}</span> + {% } %} + </p> + {% if (file.error) { %} + <div><span class="label label-danger">Error</span> {%=file.error%}</div> + {% } %} + </td> + <td> + <span class="size">{%=o.formatFileSize(file.size)%}</span> + </td> + <td> + {% if (file.deleteUrl) { %} + <button class="btn btn-danger btn-sm delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}> + <i class="glyphicon glyphicon-trash"></i> + <span>Delete</span> + </button> + {% } else { %} + <button class="btn btn-warning cancel"> + <i class="glyphicon glyphicon-ban-circle"></i> + <span>Cancel</span> + </button> + {% } %} + </td> + </tr> +{% } %} +</script> + +<script> +/* + * Based on jQuery File Upload Plugin JS Example + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/*jslint nomen: true, unparam: true, regexp: true */ +/*global $, window, document */ + +$(function () { + 'use strict'; + + // jquery.fileupload.process for image resizing capabilities + // has to be included in all cases as jquery.ui.widget depends on it without specifying the depencency explicitly + requirejs(['tmpl', 'jquery.ui.widget', 'jquery.fileupload', 'jquery.fileupload-ui', 'jquery.fileupload-process'], function() { + // Initialize the jQuery File Upload widget: + $('#fileupload').fileupload( { + autoUpload: true, + url: "files/" + }); + + <c:if test="${loadexistingfiles}"> + // Load existing files + $('#fileupload').addClass('fileupload-processing'); + $.ajax({ + url: $('#fileupload').fileupload('option', 'url'), + dataType: 'json', + context: $('#fileupload')[0] + }).always(function () { + $(this).removeClass('fileupload-processing'); + }).done(function (result) { + $(this).fileupload('option', 'done') + .call(this, $.Event('done'), {result: result}); + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add upload file", jqXHR, errorThrown); + }); + </c:if> + }); +}); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/orioneditor/orioneditorarea.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/orioneditor/orioneditorarea.tag new file mode 100644 index 0000000..70a1cdf --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/orioneditor/orioneditorarea.tag @@ -0,0 +1,110 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Wrapper for an orion editing area" pageEncoding="UTF-8"%> + +<%@attribute name="areaid" required="true" description="The id of the editing area."%> +<%@attribute name="withoutsavebutton" required="false"%> +<%@attribute name="initialtext" required="false" description="The value to put in the editor. Can be also passed as body of this tag"%> +<%@attribute name="url" required="false"%> +<%@attribute name="hidden" required="false" description="if not empty, the form is hidden"%> +<%@attribute name="method" required="false" description="the method to use. Defaults to PUT"%> + +<%-- QUICK HACK to change the method from POST to PUT after saving an empty documentation the first time --%> +<%@attribute name="reloadAfterSuccess" required="false" description="Trigger a page reload after success (if true)"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> + +<div> + <div id="${areaid}" class="orionxmleditordiv" <c:if test="{$not empty hidden}">style="display: none;"</c:if>><pre>${wc:escapeHtml4(initialtext)}<jsp:doBody/></pre></div> + <c:if test="${empty withoutsavebutton}"> + <button class="btn btn-primary" type="button" onclick="window.winery.orionareas['${areaid}'].save(this);" data-loading-text="Saving...">Save</button> + </c:if> +</div> + +<script> +if (window.winery === undefined) { + window.winery = {}; +} +if (window.winery.orionareas === undefined) { + window.winery.orionareas = {}; +} +require(["orioneditor"], function(edit) { + var config = { + id: "${areaid}", // used for URL update + reloadAfterSuccess : "${reloadAfterSuccess}", + editor: edit({ + contentType: "application/xml", + parent: "${areaid}" + // todo: we can set the initial text by the parameter "contents" + }), + ajaxOptions : { + contentType: "text/xml" + }, + fixEditorHeight: function() { + // fix the editor + // orion puts "height:0px" -> we remove that + $("#${areaid}").removeAttr("style"); + // due to the CSS style, the height is 300px + // "just" adapt the editor to that size + this.editor.resize(); + }, + save: function(button) { + var btn = $(button); // also works if button is undefined + btn.button("loading"); + + var options = this.ajaxOptions; + options.data = this.editor.getText(); + + // ensure that "config" variable is initialized within the ajax call + var config = this; + // the following code does not use "this" anymore as the "this" in the function references to the jqXHR instead of config + $.ajax(options).done(function( data, textStatus, jqXHR ) { + if (data !== undefined) { + // data contains the new id + url = url.replace(config.id, data); + conifg.id = data; + config.ajaxOptions.url = url; + } + if (config.reloadAfterSuccess) { + location.reload(); + } else { + vShowSuccess("sucessfully saved"); + btn.button("reset"); + } + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add update XML", jqXHR, errorThrown); + btn.button("reset"); + }); + } + }; + + // now, editor is defined + // we cannot "fix" the appearance as the editor height determination does not work on hidden fields + + // url is an optional parameter to the .tag + if ("${url}" != "") { + config.ajaxOptions.url = "${url}"; + } + // method is an optional parameter to the .tag + if ("${method}" == "") { + config.ajaxOptions.type = "PUT"; + } else { + config.ajaxOptions.type = "${method}"; + } + + // store the config in global variable + window.winery.orionareas["${areaid}"] = config; +}); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/policies/policies.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/policies/policies.tag new file mode 100644 index 0000000..5bd7bd9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/policies/policies.tag @@ -0,0 +1,54 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%-- This is mostly inspired by the reqscaps handling. Future work: Generalize the dialogs somehow to avoid copy'n'paste of code --%> + +<%@tag import="org.apache.taglibs.standard.lang.jstl.test.PageContextImpl"%> +<%@tag description="Renders the list of policies of a node template" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> + +<%@attribute name="list" required="true" type="java.util.List"%> +<%@attribute name="repositoryURL" required="true" type="java.lang.String" %> + +<div class="policiesContainer"> + <div class="header">Policies</div> + <div class="content"> + <div class="row"> + <div class="col-xs-4">Name</div> + <div class="cell col-xs-4">Type</div> + <div class="cell col-xs-4">Template</div> + </div> + <c:forEach var="item" items="${list}" varStatus="loopStatus"><%-- this HTML has to be kept consistent with the tmpl-policy HTML at policydiag.tag --%> + <div class="policy row ${loopStatus.index % 2 == 0 ? 'even' : 'odd'}"> + <div class="col-xs-4 policy name">${item.name}</div> + + <c:set var="clazz" value="<%=org.eclipse.winery.model.tosca.TPolicyType.class%>" /> + <div class="col-xs-4 policy type">${wc:qname2href(repositoryURL, clazz, item.policyType)}</div> + <span class="type">${item.policyType}</span> + + <c:set var="clazz" value="<%=org.eclipse.winery.model.tosca.TPolicyTemplate.class%>" /> + <div class="col-xs-4 policy template">${wc:qname2href(repositoryURL, clazz, item.policyRef)}</div> + <span class="template">${item.policyRef}</span> + + <c:set var="clazz" value="<%=org.eclipse.winery.model.tosca.TPolicy.class%>" /> + <textarea class="policy_xml">${wc:XMLAsString(clazz, item)}</textarea> + </div> + </c:forEach> + <div class="addnewpolicy row" style="display:none;"> + <button class="btn btn-default center-block btn-xs" onclick="showAddDiagForPolicy($(this).parent().parent().parent().parent());">Add new</button> + </div> + </div> +</div> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/policies/policydiag.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/policies/policydiag.tag new file mode 100644 index 0000000..2554b8c --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/policies/policydiag.tag @@ -0,0 +1,205 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> + +<%@tag import="org.eclipse.winery.model.tosca.TPolicyTemplate"%> +<%@tag description="Dialog to add or update a policy. Offers function showUpdateDiagForPolicy(policyElement) / showAddDiagForPolicy(nodeTemplateElement)" pageEncoding="UTF-8"%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> +<%@taglib prefix="w" tagdir="/WEB-INF/tags"%> +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common"%> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> + +<%@attribute name="allPolicyTypes" required="true" type="java.util.Collection" description="Collection<QName> of all available policy types" %> +<%@attribute name="repositoryURL" required="true" type="java.lang.String" description="The URL of winery's repository"%> + +<div class="modal fade" id="PolicyDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Policy</h4> + </div> + <div class="modal-body"> + <ct:id_name_type idPrefix="policy" allTypes="${allPolicyTypes}" hideIdField="true" /> + + <div class="form-group"> + <label for="policyTemplate" class="control-label">Policy Template:</label> + + <input id="policyTemplate" class="form-control" name="policyTemplate"></input> + </div> + + <o:orioneditorarea areaid="OrionpolicyXML" withoutsavebutton="true" /> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" id="deletePolicy" class="btn btn-danger" onclick="deletePolicy();">Delete</button> + <button type="button" id="updatePolicy" class="btn btn-primary" onclick="addOrUpdatePolicy(false);">Update</button> + <button type="button" id="addPolicy" class="btn btn-primary" onclick="addOrUpdatePolicy(true);">Add</button> + </div> + </div> + </div> +</div> + +<c:set var="clazz" value="<%=org.eclipse.winery.model.tosca.TPolicy.class%>" /> +<textarea id="emptyPolicy" class="hidden">${wc:XMLAsString(clazz, null)}</textarea> + +<script> +//global variable set by showUpdateDiagForPolicy and read by addOrUpdatePolicy +var currentPolicyElement; + +// possibly this is a duplicate information as we also have "currentlySelectedNodeTemplate" (or similar) +var currentNodeTemplateElement; + +function updatePolicyTemplateSelect(valueToSelect) { + require(["winery-support-common"], function(w) { + var type = $("#policyType").val(); + var fragment = w.getURLFragmentOutOfFullQName(type); + var url = "${repositoryURL}/policytypes/" + fragment + "/instances/"; + $.ajax(url, { + dataType: 'json' + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not get policy templates", jqXHR, errorThrown); + }).done(function(data) { + // add "(none)" to available items + var none = { + id: "(none)", + text: "(none)" + }; + data.unshift(none); + + if (typeof valueToSelect === "undefined") { + valueToSelect = "(none)"; + } + + $("#policyTemplate") + .select2({data: data}) + .select2("val", valueToSelect); + }); + }); +} + +function showUpdateDiagForPolicy(policyElement) { + currentPolicyElement = policyElement; + + $("#deletePolicy").show(); + $("#updatePolicy").show(); + $("#addPolicy").hide(); + + var name = policyElement.children("div.name").text(); + var type = policyElement.children("span.type").text(); + + $("#policyName").val(name); + $("#policyType").val(type); + + // onchange of type is not called, we have to update the template selection field for ourselves + // we also have to select the current user's choice + updatePolicyTemplateSelect(policyElement.children("span.template").text()); + + var diag = $("#PolicyDiag"); + require(["winery-support-common"], function(w) { + w.replaceDialogShownHookForOrionUpdate(diag, "OrionpolicyXML", currentPolicyElement.children("textarea").val()); + diag.modal("show"); + }); +} + +function showAddDiagForPolicy(nodeTemplateElement) { + currentNodeTemplateElement = nodeTemplateElement; + + $("#deletePolicy").hide(); + $("#updatePolicy").hide(); + $("#addPolicy").show(); + + $("#policyName").val(""); + + // fill policy template select field + updatePolicyTemplateSelect(); + + var diag = $("#PolicyDiag"); + require(["winery-support-common"], function(w) { + w.replaceDialogShownHookForOrionUpdate(diag, "OrionpolicyXML", $("#emptyPolicy").val()); + diag.modal("show"); + }); +} + +function addOrUpdatePolicy(doAdd) { + if (highlightRequiredFields()) { + vShowError("Please fill in all required fields"); + return; + } + + require(["winery-support-common", "tmpl"], function(wsc, tmpl) { + var res = wsc.synchronizeNameAndType("policy", false, [{ + attribute: "policyType", + fieldSuffix: "Type", + }, { + attribute: "policyRef", + fieldSuffix: "Template" + }]); + + if (res) { + var policyTemplate = $("#policyTemplate").select2("data"); + var renderData = { + name: $("#policyName").val(), + + policyTypeText: $("#policyType :selected").text(), + policyTypeVal: $("#policyType").val(), + + policyTemplateText: policyTemplate.text, + policyTemplateVal: policyTemplate.id, + + xml: res.xml + }; + var div = tmpl("tmpl-policy", renderData); + if (doAdd) { + currentNodeTemplateElement.children("div.policiesContainer").children("div.content").children("div.addnewpolicy").before(div); + } else { + currentPolicyElement.replaceWith(div); + } + $("#PolicyDiag").modal("hide"); + } else { + vShowError("Could not synchronize XML fields"); + } + }); +} + + +function deletePolicy() { + // We just have to remove the HTML element: + // The save operation converts the information in the HTML to XML + currentPolicyElement.remove(); + $("#PolicyDiag").modal("hide"); +} + + +$("#policyType") + .select2() + .on("change", updatePolicyTemplateSelect); +</script> + +<%-- parameters: o.id, o.name, o.policyType, o.policyRef, o.xml. Has to be consistent with the HTML generated by policies.tag --%> +<script type="text/x-tmpl" id="tmpl-policy"> + <div class="policy row"> <%-- "even"/"odd" is not set. Could be done by using $.prev() --%> + <div class="col-xs-4 policy name">{%=o.name%}</div> + + <%-- we do not provide a link here. Link is only available at reload. Makes life easier here. makeArtifactTemplateURL at winery-common.js is a first hint of how to generate links --%> + <div class="col-xs-4 policy type">{%=o.policyTypeText%}</div> + <span class="type">{%=o.policyTypeVal%}</span> + + <div class="col-xs-4 policy template">{%=o.policyTemplateText%}</div> + <span class="template">{%=o.policyTemplateVal%}</span> + + <textarea class="policy_xml">{%=o.xml%}</textarea> + </div> +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/spinnerwithinphty.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/spinnerwithinphty.tag new file mode 100644 index 0000000..a77c9d9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/spinnerwithinphty.tag @@ -0,0 +1,92 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Yves Schubert - initial API and implementation and/or initial documentation + * Oliver Kopp - minor improvements + *******************************************************************************/ +--%> +<%@tag description="A spinner with the possibility to set to inphty via button" pageEncoding="UTF-8"%> +<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + +<%-- Code copied between repository and topology-modeler --%> + +<%-- +Could also be realized as + * HTML5 Web Component (http://www.ibm.com/developerworks/library/wa-html5components1/) or + * x-tags (http://www.x-tags.org/) +We decided to use JSP tags to avoid an additional JavaScript library +--%> + +<%@attribute name="label" required="true"%> +<%@attribute name="id" required="true"%> +<%@attribute name="min"%> +<%@attribute name="max" required="false" description="Maximum value. Default is 1000. The underlying library does not allow arbitrary high values."%> +<%@attribute name="name" required="false" description="The name of the input field. Defaults to the id"%> +<%@attribute name="withinphty" required="false" description="If set, then an inphty button is provded"%> +<%@attribute name="value"%> +<%@attribute name="width" required="false" description="The Column with according to bootstrap rules. Default is 3 (should not be smaller)."%> +<%@attribute name="changedfunction" required="false" description="Called if value changed"%> + +<%-- Set default name value if required --%> +<c:if test="${empty name}"> + <c:set var="name" value="${id}"></c:set> +</c:if> + +<c:if test="${empty width}"> + <c:set var="width" value="3"></c:set> +</c:if> + +<div class="form-group"> + <label for="${id}">${label}</label> + <div class="row"> + <div class="col-lg-${width}"> + <div class="input-group"> + <input id="${id}" class="spinner form-control" name="${name}" type="text" <c:if test="${not empty changedfunction}">onblur="${changedfunction}();"</c:if>/> + <c:if test="${not empty withinphty}"> + <span class="input-group-addon" style="cursor: pointer; border-left:0" onclick="setToInfin('${id}'<c:if test="${not empty changedfunction}">, ${changedfunction}</c:if>);">∞</span> + </c:if> + </div> + </div> + </div> +</div> + +<script> +<%-- +included multiple times. +Drawback when not using HTML5 components and keeping the JavaScript functions closed to the HTML code +--%> +function setToInfin(id, changedFunction) { + var spinner = $("#" + id); + spinner.val('∞'); // &inphty; - jQuery does not decode that, but places the plain text. Therefore, we directly pass the char we want + if (changedFunction !== undefined) { + changedFunction(); + } +} + +$(function() { + var param = {} + <c:if test="${not empty min}"> + param.minimum = "${min}"; + </c:if> + <c:if test="${empty max}"> + param.maximum = 1000; + </c:if> + + // use bootstrap-spinedit plugin + $("#${id}").spinedit(param); + + <c:if test="${not empty changedfunction}"> + $("#${id}").on('valueChanged', ${changedfunction}); + </c:if> + +}); + +</script> + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/CSSForTypes.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/CSSForTypes.tag new file mode 100644 index 0000000..1df2d82 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/CSSForTypes.tag @@ -0,0 +1,50 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Generates style element for node types and relationship types" pageEncoding="UTF-8" %> + +<%@attribute name="nodeTypes" required="true" type="java.util.Collection" %> +<%@attribute name="relationshipTypes" required="true" type="java.util.Collection" %> + +<%@tag import="java.util.Collection"%> +<%@tag import="javax.xml.namespace.QName"%> +<%@tag import="org.eclipse.winery.common.ModelUtilities"%> +<%@tag import="org.eclipse.winery.common.Util"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeType"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> + +<style> +<% + for (TNodeType nt: (Collection<TNodeType>) nodeTypes) { + String borderColor = ModelUtilities.getBorderColor(nt); + String cssName = Util.makeCSSName(nt.getTargetNamespace(), nt.getName()); +%> + div.NodeTemplateShape.<%=cssName%> { + border-color: <%=borderColor%>; + } +<% + } + + // relationship types CSS + for (TRelationshipType rt: (Collection<TRelationshipType>) relationshipTypes) { + String color = ModelUtilities.getColor(rt); + QName qname = new QName(rt.getTargetNamespace(), rt.getName()); + String cssName = Util.makeCSSName(qname) + "_box"; +%> + div.<%=cssName%> { + background: <%=color%>; + } +<% + } +%> +</style> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/defineCreateConnectorEndpointsFunction.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/defineCreateConnectorEndpointsFunction.tag new file mode 100644 index 0000000..26f139a --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/defineCreateConnectorEndpointsFunction.tag @@ -0,0 +1,42 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Defines the javascript function createConnectorEndpoints globally. Quick hack to avoid huge hacking at the repository" pageEncoding="UTF-8"%> + +<%@tag import="java.util.Collection"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.common.Util"%> + +<%@attribute name="relationshipTypes" type="java.util.Collection" required="true" %> + +<script> +function createConnectorEndpoints(nodeTemplateShapeSet) { +<% + for (TRelationshipType relationshipType: (Collection<TRelationshipType>) relationshipTypes) { +%> + nodeTemplateShapeSet.find(".<%=Util.makeCSSName(relationshipType.getTargetNamespace(), relationshipType.getName()) %>").each(function(i,e) { + var p = $(e).parent(); + var grandparent = $(p).parent(); + + jsPlumb.makeSource($(e), { + parent:grandparent, + anchor:"Continuous", + connectionType: "{<%=relationshipType.getTargetNamespace()%>}<%=relationshipType.getName()%>", + endpoint:"Blank" + }); + }); +<% + } +%> +} +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/nodeTemplateRenderer.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/nodeTemplateRenderer.tag new file mode 100644 index 0000000..16bc737 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/nodeTemplateRenderer.tag @@ -0,0 +1,266 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - skeletton for node template shapes + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag language="java" pageEncoding="UTF-8" description="This tag is used for both real nodeTemplate node rendering and rendering of a 'template' used to create a nodeTemplateShape. The latter is called by palette.jsp. Therefore, this tag has to be more general."%> +<%-- Parameters --%> + +<%-- template and palette --%> +<%@attribute name="client" required="true" description="IWineryRepository" type="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@attribute name="repositoryURL" required="true" type="java.lang.String" description="The URL of winery's repository"%> +<%@attribute name="topologyModelerURI" required="false" type="java.lang.String" description="The URL of winery topology modeler's URI - required for images/. Has to end with '/'. Can be left blank."%> +<%@attribute name="relationshipTypes" description="the known relationship types" required="true" type="java.util.Collection"%> + +<%-- only for topology modeler --%> +<%@attribute name="nodeTemplate" type="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@attribute name="top"%> +<%@attribute name="left"%> + +<%-- only for palette.jsp --%> +<%@attribute name="nodeType" type="org.eclipse.winery.model.tosca.TNodeType" %> +<%@attribute name="nodeTypeQName" type="javax.xml.namespace.QName"%> + +<%@tag import="org.eclipse.winery.model.tosca.TArtifactTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TArtifactType"%> +<%@tag import="org.eclipse.winery.model.tosca.TCapability"%> +<%@tag import="org.eclipse.winery.model.tosca.TDeploymentArtifact"%> +<%@tag import="org.eclipse.winery.model.tosca.TDeploymentArtifacts"%> +<%@tag import="org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate.Capabilities"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate.Requirements"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate.Policies"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeType"%> +<%@tag import="org.eclipse.winery.model.tosca.TPolicy"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.model.tosca.TRequirement"%> +<%@tag import="org.eclipse.winery.common.ModelUtilities"%> +<%@tag import="org.eclipse.winery.common.Util"%> +<%@tag import="org.eclipse.winery.common.ids.definitions.ArtifactTemplateId"%> +<%@tag import="org.eclipse.winery.common.ids.definitions.ArtifactTypeId"%> +<%@tag import="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@tag import="org.w3c.dom.Element" %> +<%@tag import="org.apache.commons.configuration.Configuration"%> +<%@tag import="org.apache.commons.lang3.StringUtils"%> +<%@tag import="org.apache.commons.lang3.StringEscapeUtils"%> +<%@tag import="java.io.StringWriter" %> +<%@tag import="java.util.Collections"%> +<%@tag import="java.util.Collection"%> +<%@tag import="java.util.Iterator"%> +<%@tag import="java.util.List"%> +<%@tag import="java.util.Map"%> +<%@tag import="java.util.UUID"%> +<%@tag import="javax.xml.namespace.QName"%> +<%@tag import="javax.xml.transform.OutputKeys"%> +<%@tag import="javax.xml.transform.Transformer"%> +<%@tag import="javax.xml.transform.TransformerFactory"%> +<%@tag import="javax.xml.transform.dom.DOMSource"%> +<%@tag import="javax.xml.transform.stream.StreamResult"%> + +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> +<%@taglib prefix="ntrq" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="pol" tagdir="/WEB-INF/tags/common/policies" %> +<%@taglib prefix="props" tagdir="/WEB-INF/tags/common/templates" %> + +<% + String visualElementId; + + boolean paletteMode; + if (nodeTemplate == null) { + // we are in palette mode + // --> we render a template to be inserted in the drawing area by drag'n'drop + paletteMode = true; + assert(nodeType != null); + assert(nodeTypeQName != null); + + // these values are only pseudo values, they get all overwritten in drop function of palette.jsp + visualElementId = UUID.randomUUID().toString(); + left = "0"; + top = "0"; + } else { + // we render a real node template + paletteMode = false; + nodeTypeQName = nodeTemplate.getType(); + nodeType = client.getType(nodeTypeQName, TNodeType.class); + if (nodeType == null) { +%> + <script>vShowError("Could not get node type <%=nodeTypeQName%>");</script> +<% + return; + } + + visualElementId = nodeTemplate.getId(); + } + + String nodeTypeCSSName = Util.makeCSSName(nodeTypeQName); +%> + + <div class="NodeTemplateShape unselectable <%=nodeTypeCSSName%> <%if (paletteMode){%> hidden<%}%>" id="<%=visualElementId%>" style="left: <%=left%>px; top: <%=top%>px"> + <div class="headerContainer"> + <img class="icon" onerror="var that=this; require(['winery-common-topologyrendering'], function(wct){wct.imageError(that);});" src="<%=repositoryURL%>/nodetypes/<%=Util.DoubleURLencode(nodeTypeQName)%>/visualappearance/50x50" /> + <% + String name; + if (paletteMode) { + name = ""; // will be changed on drop + } else { + name = nodeTemplate.getName(); + if (StringUtils.isEmpty(name)) { + name = visualElementId; + } + } + %> + <div class="minMaxInstances"> + <span class="minInstances"><% + if (!paletteMode) { + %><%=Util.renderMinInstances(nodeTemplate.getMinInstances())%><% + } + %></span> + <span class="maxInstances"><% + if (!paletteMode) { + %><%=Util.renderMaxInstances(nodeTemplate.getMaxInstances())%><% + } + %></span> + </div> + <div class="id nodetemplate"><%=visualElementId%></div> + <div class="name nodetemplate"><%=name%></div> + <div class="type nodetemplate"><%=Util.qname2hrefWithName(repositoryURL, TNodeType.class, nodeTypeQName, nodeType.getName())%></div> + <span class="typeQName hidden"><%=nodeTypeQName%></span> + <span class="typeNamespace hidden"><%=nodeTypeQName.getNamespaceURI()%></span> + </div> + <div class="endpointContainer"> + <% + for (TRelationshipType relationshipType: (Collection<TRelationshipType>) relationshipTypes) { + %> + <div class="connectorEndpoint <%=Util.makeCSSName(relationshipType.getTargetNamespace(), relationshipType.getName())%>"> + <div class="connectorBox <%=Util.makeCSSName(relationshipType.getTargetNamespace(), relationshipType.getName())%>_box"></div> + <div class="connectorLabel"><%=relationshipType.getName()%></div> + </div> + <% + } + %> + </div> + + <%-- Properties --%> + <props:properties + propertiesDefinition="<%=nodeType.getPropertiesDefinition()%>" + wpd="<%=ModelUtilities.getWinerysPropertiesDefinition(nodeType)%>" + template="<%=paletteMode ? null : nodeTemplate %>" + pathToImages="${topologyModelerURI}images/" /> + + <%-- Deployment Artifacts --%> + + <% + List<TDeploymentArtifact> deploymentArtifacts; + if (paletteMode) { + deploymentArtifacts = Collections.emptyList(); + } else { + TDeploymentArtifacts tDeploymentArtifacts = nodeTemplate.getDeploymentArtifacts(); + if (tDeploymentArtifacts == null) { + deploymentArtifacts = Collections.emptyList(); + } else { + deploymentArtifacts = tDeploymentArtifacts.getDeploymentArtifact(); + } + } + // Render even if (deploymentArtifacts.isEmpty()), because user could add some with drag'n'drop + + // following is required to render artifact specific content + TransformerFactory transFactory = TransformerFactory.newInstance(); + Transformer transformer = transFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + %> + + <div class="deploymentArtifactsContainer"> + + <div class="header">Deployment Artifacts</div> + <div class="content"> + <% + if (!paletteMode) { + for (TDeploymentArtifact deploymentArtifact : deploymentArtifacts) { + %> + <div class="deploymentArtifact row" onclick="showDeploymentArtifactInformation('<%=visualElementId%>', '<%=deploymentArtifact.getName()%>');"> + <textarea class="hidden"><%=org.eclipse.winery.common.Util.getXMLAsString(org.eclipse.winery.model.tosca.TDeploymentArtifact.class, deploymentArtifact)%></textarea> + <div class="col-xs-4 overflowhidden deploymentArtifact name"><%=deploymentArtifact.getName()%></div> + <div class="col-xs-4 overflowhidden artifactTemplate"><% + QName artifactRef; + if ((artifactRef = deploymentArtifact.getArtifactRef()) != null) { + ArtifactTemplateId atId = new ArtifactTemplateId(artifactRef); + %><%=client.getName(atId)%><% + } + %></div> + <div class="col-xs-4 overflowhidden artifactType"><% + ArtifactTypeId atyId = new ArtifactTypeId(deploymentArtifact.getArtifactType()); + %><%=client.getName(atyId)%></div> + </div> + <% + } + } + %> + + <div class="row addDA"> + <button class="btn btn-default btn-xs center-block addDA">Add new</button> + </div> + + <div class="row addnewartifacttemplate"> + <div class="center-block">Drop to add new deployment artifact. Not yet implemented.</div> + </div> + </div> + </div> + + <%-- Requirements and Capabilities --%> + <% + List<TRequirement> reqList; + if (paletteMode) { + reqList = null; + } else { + Requirements reqs = nodeTemplate.getRequirements(); + if (reqs == null) { + reqList = null; + } else { + reqList = reqs.getRequirement(); + } + } + %> + <ntrq:reqs list="<%=reqList%>" repositoryURL="${repositoryURL}" pathToImages="${topologyModelerURI}images/" client="${client}" /> + + <% + List<TCapability> capList; + if (paletteMode) { + capList = null; + } else { + Capabilities caps = nodeTemplate.getCapabilities(); + if (caps == null) { + capList = null; + } else { + capList = caps.getCapability(); + } + } + %> + <ntrq:caps list="<%=capList%>" repositoryURL="${repositoryURL}" pathToImages="${topologyModelerURI}images/" client="${client}"/> + + <%-- Policies --%> + <% + List<TPolicy> policyList; + if (paletteMode) { + policyList = null; + } else { + Policies policies = nodeTemplate.getPolicies(); + if (policies == null) { + policyList = null; + } else { + policyList = policies.getPolicy(); + } + } + %> + <pol:policies list="<%=policyList%>" repositoryURL="${repositoryURL}" /> +</div> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/caps.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/caps.tag new file mode 100644 index 0000000..af70ff6 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/caps.tag @@ -0,0 +1,33 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Renders the list of requirements or capabilties" pageEncoding="UTF-8"%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> + +<%@attribute name="client" required="true" description="IWineryRepository" type="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@attribute name="list" required="false" type="java.util.List"%> +<%@attribute name="repositoryURL" required="true" %> +<%@attribute name="pathToImages" required="true" description="The path (URI path) to the image/ url, where xml.png is available. Has to end with '/'"%> + +<nt:reqsorcaps + headerLabel="Capabilities" + cssClassPrefix="capabilities" + list="${list}" + shortName="Cap" + TReqOrCapTypeClass="<%=org.eclipse.winery.model.tosca.TCapabilityType.class%>" + repositoryURL="${repositoryURL}" + typeURLFragment="capabilitytypes" + pathToImages="${pathToImages}" + client="${client}" +/> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/reqs.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/reqs.tag new file mode 100644 index 0000000..473443e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/reqs.tag @@ -0,0 +1,33 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Renders the list of requirements or capabilties" pageEncoding="UTF-8"%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> + +<%@attribute name="client" required="true" description="IWineryRepository" type="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@attribute name="list" required="false" type="java.util.List"%> +<%@attribute name="repositoryURL" required="true" %> +<%@attribute name="pathToImages" required="true" description="The path (URI path) to the image/ url, where xml.png is available. Has to end with '/'"%> + +<nt:reqsorcaps + headerLabel="Requirements" + cssClassPrefix="requirements" + list="${list}" + shortName="Req" + TReqOrCapTypeClass="<%=org.eclipse.winery.model.tosca.TRequirementType.class%>" + repositoryURL="${repositoryURL}" + typeURLFragment="requirementtypes" + pathToImages="${pathToImages}" + client="${client}" +/> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/reqsorcaps.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/reqsorcaps.tag new file mode 100644 index 0000000..6046730 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/nodetemplates/reqscaps/reqsorcaps.tag @@ -0,0 +1,63 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Renders the list of requirements or capabilties" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="props" tagdir="/WEB-INF/tags/common/templates" %> + +<%@attribute name="list" required="false" type="java.util.List" %> +<%@attribute name="headerLabel" required="true" description="Used for the heading" %> +<%@attribute name="cssClassPrefix" required="true" %> +<%@attribute name="TReqOrCapTypeClass" required="true" type="java.lang.Class" %> +<%@attribute name="repositoryURL" required="true" %> +<%@attribute name="typeURLFragment" required="true" description="requirementtypes|capabilitytypes"%> +<%@attribute name="shortName" required="true" description="Used for diag id, function name suffix, Req|Cap"%> +<%@attribute name="client" required="true" description="IWineryRepository" type="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@attribute name="pathToImages" required="true" description="The path (URI path) to the image/ url, where xml.png is available. Has to end with '/'"%> + +<%@tag import="org.eclipse.winery.common.ModelUtilities"%> + +<div class="${cssClassPrefix}Container"> + <div class="header">${headerLabel}</div> + <div class="content"> + <c:forEach var="item" items="${list}"> + <div class="reqorcap ${cssClassPrefix} row" id="${item.id}"> + <div class="col-xs-4 id reqorcap">${item.id}</div> + <div class="col-xs-4 name reqorcap">${item.name}</div> + <div class="col-xs-4 type reqorcap">${wc:qname2href(repositoryURL, TReqOrCapTypeClass, item.type)}</div> + <c:set var="type" value="${wc:getType(client, item.type, TReqOrCapTypeClass)}" /> + <props:properties + template="${item}" + propertiesDefinition="${type.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(type)}" + pathToImages="${pathToImages}" /> + </div> + </c:forEach> + <div class="addnewreqorcap row" style="display:none;"> + <button class="btn btn-default btn-xs center-block" onclick="showAddOrUpdateDiagFor${shortName}($(this).parent().parent().parent().parent().attr('id'));">Add new</button> + </div> + </div> +</div> + +<%-- parameters: o.id, o.name, o.type, o.xml. Has to be consistent with above HTML --%> +<script type="text/x-tmpl" id="tmpl-${shortName}"> + <div class="reqorcap ${cssClassPrefix}" id="{%=o.id%}"> + <div class="col-xs-4 id reqorcap">{%=o.id%}</div> + <div class="col-xs-4 name reqorcap">{%=o.name%}</div> + <div class="col-xs-4 type reqorcap">{%#require("winery-support-common").qname2href("${repositoryURL}", "${typeURLFragment}", o.type)%}</div> + <div id="toBeReplacedByProperties"></div> + </div> +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/properties.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/properties.tag new file mode 100644 index 0000000..4cc6f0a --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/properties.tag @@ -0,0 +1,103 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Rendering for properties. A separate CSS has to be provided to style the content. Thus, this tag is reusable both in the topology modeler and in the management UI. Requires global javaScript function editPropertiesXML(visualElementId)" pageEncoding="UTF-8"%> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + +<%@attribute name="propertiesDefinition" required="true" type="org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition" description="The TOSCA-conforming properties definition. May be null."%> +<%@attribute name="wpd" required="true" type="org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition" description="Winery's K/V properties definition. May be null"%> +<%@attribute name="template" required="true" type="org.eclipse.winery.model.tosca.TEntityTemplate" description="The template to display properties. Has to be null in case of the palette mode of the topology modeler"%> +<%@attribute name="pathToImages" required="true" description="The path (URI path) to the image/ url, where xml.png is available. Has to end with '/'"%> + +<%@tag import="org.eclipse.winery.common.ModelUtilities"%> +<%@tag import="org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition"%> +<%@tag import="org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV"%> +<%@tag import="org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList"%> + +<% +if ((propertiesDefinition != null) || (wpd != null)) { +// properties exist +%> + <div class="propertiesContainer"> + <div class="header">Properties</div> + <div class="content"> + <% + if (wpd == null) { + // no winery's special properties definition, but "normal" TOSCA properties definition + + if (propertiesDefinition.getType() != null) { + %> + <span class="properties_type">XSD Type: <%=propertiesDefinition.getType()%></span> + <% + } else { + %> + <span class="properties_element">XSD Element: <%=propertiesDefinition.getElement()%></span> + <% + } + %> + <textarea class="properties_xml"><% + if (template != null) { + %><%=org.eclipse.winery.common.Util.getXMLAsString(org.eclipse.winery.model.tosca.TEntityTemplate.Properties.class, template.getProperties())%><% + } + %></textarea> + <%-- We have to do use $(this).parent().parent().parent().attr('id') instead of <%=visualElementId%> as on drag'n'drop from the palette, this binding is NOT changed, but the Id changes --> the user does NOT want to edit the properties from the palette entry, but from the node template --%> + <button class="btn btn-default" onclick="editPropertiesXML($(this).parent().parent().parent().attr('id'));"><img src="${pathToImages}xml.png"></img>View</button> + <% + } else { + // Winery special mode + java.util.Properties props; + if (template == null) { + // setting null only because of dump compiler. + // We never read props if in paletteMode + props = null; + } else { + props = ModelUtilities.getPropertiesKV(template); + } + %> + <%-- stores wrapper element name and namespace to ease serialization--%> + <span class="elementName"><%=wpd.getElementName()%></span> + <span class="namespace"><%=wpd.getNamespace()%></span> + <table> + <% + PropertyDefinitionKVList list = wpd.getPropertyDefinitionKVList(); + if (list != null) { + // iterate on all defined properties + for (PropertyDefinitionKV propdef: list) { + String key = propdef.getKey(); + String value; + if (template == null) { + value = ""; + } else { + // assign value, but change "null" to "" if no property is defined + if ((value = props.getProperty(key)) == null) { + value = ""; + } + } + %> + <tr class="KVProperty"> + <td><span class="<%= key %> KVPropertyKey"><%= key %></span></td> + <td><a class="KVPropertyValue" href="#" data-type="text" data-title="Enter <%= key %>"><%=value %></a></td> + </tr> + <% + } + } + %> + </table> + <% + } + %> + </div> + </div> +<% +} +%> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/propertiesBasic.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/propertiesBasic.tag new file mode 100644 index 0000000..5e850b1 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/propertiesBasic.tag @@ -0,0 +1,112 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Has to be included once before ussage of properties.tag. Used in topology modeler and in properties.jsp of entitytemplates" pageEncoding="UTF-8"%> + +<%@tag import="org.eclipse.winery.common.constants.Namespaces" %> + +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> + +<div class="modal fade" id="PropertyXMLDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Property</h4> + </div> + <div class="modal-body"> + <!-- embed the XML editor without a save button. We provide the save button by ourselves --> + <o:orioneditorarea areaid="PropertyXML" withoutsavebutton="true"/> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" onclick="savePropertiesXMLChanges();">Save</button> + </div> + </div> + </div> +</div> + +<script> +// global variable set by editPropertiesXML and read by savePropertiesXMLChanges +var nodeTemplateIdsTextAreaPropertiesXMLEditing; + +function editPropertiesXML(nodeTemplateId) { + // code mirror does not update content if field not fully shown + // therefore, we hook in into the "shown" event + $("#PropertyXMLDiag").off("shown.bs.modal"); + $("#PropertyXMLDiag").on("shown.bs.modal", function() { + nodeTemplateIdsTextAreaPropertiesXMLEditing = $("#" + nodeTemplateId).children(".propertiesContainer").children(".content").children("textarea"); + var val = nodeTemplateIdsTextAreaPropertiesXMLEditing.val(); + window.winery.orionareas["PropertyXML"].editor.setText(val); + window.winery.orionareas["PropertyXML"].fixEditorHeight(); + }); + $("#PropertyXMLDiag").modal("show"); + nodeTemplateIdSelectedForPropertiesXMLEditing = nodeTemplateId; +} + +function savePropertiesXMLChanges() { + var val = window.winery.orionareas["PropertyXML"].editor.getText(); + nodeTemplateIdsTextAreaPropertiesXMLEditing.text(val); + $("#PropertyXMLDiag").modal("hide"); +} + +/** + * @param properties - the properties div + * @param w - an XMLWriter + */ +function savePropertiesFromDivToXMLWriter(properties, w, writeNamespaceDeclaration) { + if (properties.length != 0) { + // properties exist + var contentDiv = properties.children("div.content"); + var xmlProperties = contentDiv.children("textarea.properties_xml"); + if (xmlProperties.length == 0) { + // K/V properties -> winery special: XSD defined at node type + + var elementName = contentDiv.children("span.elementName").text(); + var namespace = contentDiv.children("span.namespace").text(); + + w.writeStartElement("Properties"); + if (writeNamespaceDeclaration){ + w.writeAttributeString("xmlns", "<%=Namespaces.TOSCA_NAMESPACE%>"); + } + w.writeStartElement(elementName); + w.writeAttributeString("xmlns", namespace); + properties.children("div.content").children("table").children("tbody").children("tr").each(function() { + var keyEl = $(this).children("td:first-child"); + var key = keyEl.text(); + var valueEl = keyEl.next().children("a"); + var value; + if (valueEl.hasClass("editable-empty")) { + value = ""; + } else { + value = valueEl.text(); + value = value.replace(/\]\]>/g, "]]]]><![CDATA[>"); + value = "<![CDATA[" + value + "]]>"; + } + w.writeStartElement(key); + w.writeString(value); + w.writeEndElement(); + }); + w.writeEndElement(); + // close "Properties" + w.writeEndElement(); + } else { + // just put the content of the XML field as child of the current node template + // The sourrinding tag "properties" is included in the XML field + var data = xmlProperties.text(); + w.writeXML(data); + } + } + +} +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/registerConnectionTypesAndConnectNodeTemplates.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/registerConnectionTypesAndConnectNodeTemplates.tag new file mode 100644 index 0000000..fb55f9e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/registerConnectionTypesAndConnectNodeTemplates.tag @@ -0,0 +1,205 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Registers the connection types to jsPlumb" pageEncoding="UTF-8"%> + +<%@attribute name="relationshipTypes" description="the known relationship types" required="true" type="java.util.Collection"%> +<%@attribute name="relationshipTemplates" description="the relationship templates to render" required="true" type="java.util.Collection"%> +<%@attribute name="ondone" description="JavaScript code executed when everything has been done" required="false"%> +<%@attribute name="repositoryURL" required="true" %> +<%@attribute name="readOnly" required="false" type="java.lang.Boolean"%> + +<%@tag import="java.util.Collection"%> +<%@tag import="org.eclipse.winery.model.tosca.TRequirement"%> +<%@tag import="org.eclipse.winery.model.tosca.TCapability"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate.TargetElement"%> +<%@tag import="org.eclipse.winery.common.Util"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + +<% +Collection<TRelationshipType> relationshipTypesCasted = (Collection<TRelationshipType>) relationshipTypes; +Collection<TRelationshipTemplate> relationshipTemplatesCasted = (Collection<TRelationshipTemplate>) relationshipTemplates; +%> + +<script> +// we should load jquery and jquery.ui to have it available at jsPlumb +// however, jquery.ui cannot be loaded as it conflicts with bootstrap (when using toogle buttons) +require(["jquery", "jsplumb", "winery-common-topologyrendering"], function(globallyavailablea, jsPlumb, wct) { + jsPlumb.bind("ready", function() { + /** + * Shows error if req or cap does not exist + */ + function getNodeTemplateIdForReqOrCapId(id) { + var reqOrCap = $("#" + id); + if (reqOrCap.length == 0) { + vShowError("Requirement/Capability with id " + id + " not found"); + } + var res = reqOrCap.parent().parent().parent().attr("id"); + return res; + } + + // register the "selected" type to enable selection of arrows + jsPlumb.registerConnectionTypes({ + "selected":{ + paintStyle:{ strokeStyle:"red", lineWidth:5 }, + hoverPaintStyle:{ lineWidth: 7 } + } + }); + +<% + int i=0; + String when = ""; + String whenRes = ""; + if (relationshipTypesCasted.isEmpty()) { +%> + vShowError("No relationship types exist. Please add relationship types to the repository"); +<% + } + for (TRelationshipType relationshipType: relationshipTypesCasted) { + String fnName = "ajaxRTdata" + i; + when = when + fnName + "(), "; + whenRes = whenRes + fnName + ", "; +%> + function <%=fnName%>() { return $.ajax({ + url: "<%=repositoryURL%>/relationshiptypes/<%=Util.DoubleURLencode(relationshipType.getTargetNamespace())%>/<%=Util.DoubleURLencode(relationshipType.getName())%>/visualappearance/", + dataType: "json", + success: function(data, textStatus, jqXHR) { + jsPlumb.registerConnectionType( + "{<%=relationshipType.getTargetNamespace()%>}<%=relationshipType.getName()%>", + data); + }, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not load relationship type {<%=relationshipType.getTargetNamespace()%>}<%=relationshipType.getName()%>", jqXHR, errorThrown); + } + });}; +<% + i++; + } + + if (!relationshipTypesCasted.isEmpty()) { + // strip last comma + when = when.substring(0, when.length()-2); + whenRes = whenRes.substring(0, whenRes.length()-2); + } +%> + // as soon as all relationship types are registered as jsPlumb object, + // create connection end points and connect the nodes + $.when(<%=when%>).done(function(<%=whenRes%>){ + require(["winery-common-topologyrendering"], function(wct) { + // A NodeTemplateShape also appears in the palette. There, it is hidden. + // These should not be initialized as the template will be initialized later on + + <c:if test="${readOnly}">wct.setReadOnly();</c:if> + + // Quick hack: All node templates are draggable, even in the readonly view + wct.initNodeTemplate(jsPlumb.getSelector(".NodeTemplateShape:not('.hidden')"), true); + + var sourceId; + var targetId; +<% + for (TRelationshipTemplate relationshipTemplate : relationshipTemplatesCasted) { +%> + var req = undefined; + var cap = undefined; +<% + // Source: Either NodeTemplate or Requirement + SourceElement sourceElement = relationshipTemplate.getSourceElement(); + if (sourceElement == null) { + %>vShowError("sourceElement is null for <%=relationshipTemplate.getId()%>");<% + continue; + } + Object source = sourceElement.getRef(); + if (source instanceof TRequirement) { +%> + req = "<%=((TRequirement)source).getId()%>"; + sourceId = getNodeTemplateIdForReqOrCapId(req); +<% + } else { + TNodeTemplate sourceT = (TNodeTemplate) source; + if (sourceT == null) { + %>vShowError("sourceElement.getRef() is null for <%=relationshipTemplate.getId()%>");<% + continue; + } +%> + sourceId = "<%=sourceT.getId()%>"; +<% + } + + // Target: Either NodeTemplate or Requirement + TargetElement targetElement = relationshipTemplate.getTargetElement(); + if (targetElement == null) { + %>vShowError("targetElement is null for <%=relationshipTemplate.getId()%>");<% + continue; + } + Object target = targetElement.getRef(); + if (target instanceof TCapability) { +%> + cap = "<%=((TCapability)target).getId()%>"; + targetId = getNodeTemplateIdForReqOrCapId(cap); +<% + } else { + TNodeTemplate targetT = (TNodeTemplate) target; + if (targetT == null) { + %>vShowError("targetElement.getRef() is null for <%=relationshipTemplate.getId()%>");<% + continue; + } +%> + targetId = "<%=targetT.getId()%>"; +<% + } +%> + var c = jsPlumb.connect({ + source: sourceId, + target: targetId, + type:"<%=relationshipTemplate.getType()%>" + }); + wct.handleConnectionCreated(c); + // we have to store the TOSCA id as jsPlumb does not allow to pass ids from user's side + // we could overwrite c.id, but we are not aware the side effects... + winery.connections[c.id].id = "<%=relationshipTemplate.getId()%>"; + if (req) { + winery.connections[c.id].req = req; + } + if (cap) { + winery.connections[c.id].cap = cap; + } +<% + if (relationshipTemplate.getName() != null) { +%> + winery.connections[c.id].name = "<%=relationshipTemplate.getName()%>"; +<% + } + } +%> + + // all connections are there + // we can register the events now + + jsPlumb.bind("connection", wct.handleConnectionCreated); + + ${ondone} + + // end of the when waiting for all relationship types + }); + // end of require binding + }); + // jsPlumb.ready + }); +// requirejs +}); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/toggleButtons.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/toggleButtons.tag new file mode 100644 index 0000000..05ed289 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/templates/toggleButtons.tag @@ -0,0 +1,131 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Toggle buttons for visual appearance" pageEncoding="UTF-8"%> +<script> +var JQUERY_ANIMATION_DURATION = 400; + +function doShowOrHide(elements, showThem) { + if (elements.length == 0) { + // e.g., no properties defined + return; + } + if (showThem) { + elements.slideDown(); + } else { + elements.slideUp(); + } + window.setTimeout(function() { + jsPlumb.repaint(elements.parent()); + }, JQUERY_ANIMATION_DURATION); +} + +function showIds(cb) { + var elements; + if ($("div.NodeTemplateShape.selected").size() > 0) { + elements = $("div.NodeTemplateShape.selected div.id.nodetemplate"); + } else { + elements = $("div.NodeTemplateShape:visible div.id.nodetemplate"); + } + + if ($(cb).hasClass("active")) { + elements.fadeOut(); + } else { + elements.fadeIn(); + } + // no repaint required as no nodes are moved + // window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); +} + +/** + * Toogles visiblity of both node types and relationship types + */ +function showTypes(showThem) { + // types at node templates + var elements; + var typesOfRelationshipTemplates; + if ($("div.NodeTemplateShape.selected").size() > 0) { + elements = $("div.NodeTemplateShape.selected div.type.nodetemplate"); + // TODO: We should put into typesOfRelationshipTemplates all type divs of relationshiptemplates connecting highlighted node templates + // This should be done when doing the multiselect + // And there should be a second if similar to the node templates for relationship templates + typesOfRelationshipTemplates = $(".todo"); + } else { + elements = $("div.NodeTemplateShape:visible div.type.nodetemplate"); + // TODO: we should check for a single relationship template being selected + typesOfRelationshipTemplates = $(".relationshipTypeLabel"); + } + + if (showThem) { + elements.fadeIn(); + typesOfRelationshipTemplates.fadeIn(); + } else { + elements.fadeOut(); + typesOfRelationshipTemplates.fadeOut(); + } + + // no repaint required as no nodes are moved + // window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); +} + +function showOrHideProperties(showThem) { + var elements; + if ($("div.NodeTemplateShape.selected").size() > 0) { + elements = $("div.NodeTemplateShape.selected > div.propertiesContainer"); + } else { + elements = $("div.NodeTemplateShape:visible > div.propertiesContainer"); + } + doShowOrHide(elements, showThem); +} + + +function showOrHideDeploymentArtifacts(showThem) { + var elements; + if ($("div.NodeTemplateShape.selected").size() > 0) { + elements = $("div.NodeTemplateShape:visible.selected > div.deploymentArtifactsContainer"); + } else { + elements = $("div.NodeTemplateShape:visible > div.deploymentArtifactsContainer"); + } + doShowOrHide(elements, showThem); +} + +function showOrHideReqCaps(showThem) { + var elements; + if ($("div.NodeTemplateShape.selected").size() > 0) { + elements = $("div.NodeTemplateShape:visible.selected > div.requirementsContainer, div.NodeTemplateShape:visible.selected > div.capabilitiesContainer"); + } else { + elements = $("div.NodeTemplateShape:visible > div.requirementsContainer, div.NodeTemplateShape:visible > div.capabilitiesContainer"); + } + doShowOrHide(elements, showThem); +} + +function showOrHidePolicies(showThem) { + var elements; + if ($("div.NodeTemplateShape.selected").size() > 0) { + elements = $("div.NodeTemplateShape:visible.selected > div.policiesContainer"); + } else { + elements = $("div.NodeTemplateShape:visible > div.policiesContainer"); + } + doShowOrHide(elements, showThem); +} +</script> + +<div class="btn-group" data-toggle="buttons-checkbox" id="toggleButtons"> + <button class="btn btn-default" id="toggleIdVisibility" onclick="showIds(this);">Ids</button> + <button class="btn active" id="toggleTypeVisibility" onclick="showTypes(!$(this).hasClass('active'));">Types</button> + <button class="btn btn-default" id="togglePropertiesVisibility" onclick="showOrHideProperties(!$(this).hasClass('active'));">Properties</button> + <button class="btn btn-default" id="toggleDeploymentArtifactsVisibility" onclick="showOrHideDeploymentArtifacts(!$(this).hasClass('active'));">Deployment Artifacts</button> + <button class="btn btn-default" id="toggleReqCapsVisibility" onclick="showOrHideReqCaps(!$(this).hasClass('active'));">Requirements & Capabilities</button> + <button class="btn btn-default" id="PoliciesVisibility" onclick="showOrHidePolicies(!$(this).hasClass('active'));">Policies</button> +</div> + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/nodeTemplateSelector.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/nodeTemplateSelector.tag new file mode 100644 index 0000000..9d09fd3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/nodeTemplateSelector.tag @@ -0,0 +1,230 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ +%> +<%@tag language="java" pageEncoding="UTF-8" description="This tag is used to render Node and Relationship Templates for selection in a dialog."%> + +<%-- attributes for the NodeTemplate selection --%> +<%@attribute name="templateURL" type="java.lang.String"%> +<%@attribute name="topologyName" type="java.lang.String"%> +<%@attribute name="topologyNamespace" type="java.lang.String"%> +<%@attribute name="repositoryURL" type="java.lang.String" %> +<%@attribute name="stName" type="java.lang.String" %> +<%@attribute name="choices" type="java.util.Map<org.eclipse.winery.model.tosca.TNodeTemplate, java.util.Map<org.eclipse.winery.model.tosca.TNodeTemplate, java.util.List<org.eclipse.winery.model.tosca.TEntityTemplate>>>"%> + +<%@tag import="java.util.ArrayList"%> +<%@tag import="java.util.HashMap"%> +<%@tag import="java.util.List"%> +<%@tag import="java.util.Map"%> +<%@tag import="java.util.UUID"%> +<%@tag import="javax.xml.namespace.QName"%> +<%@tag import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.repository.client.WineryRepositoryClientFactory"%> +<%@tag import="org.eclipse.winery.repository.client.IWineryRepositoryClient"%> +<%@tag import="org.eclipse.winery.common.Util"%> + +<%@taglib prefix="ntrq" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> + +<div id="nodeTemplateSelector"> + <p> There are several possible Node Templates to be inserted. <br> Please select your desired NodeTemplate: </p> + + <% + // the pixel distance between the displayed NodeTemplates + final int NODE_TEMPLATE_DISTANCE = 150; + + IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + client.addRepository(repositoryURL); + + // instantiate variables + Map<String, String> idMap = new HashMap<String, String>(); + List<TRelationshipTemplate> possibleConnections = new ArrayList<TRelationshipTemplate>(); + String sourceId = ""; + String randomId = ""; + String id = ""; + + // a counter used for an ID + int counter = 0; + + // used for the position of the NodeTemplate in the EditorArea + int topCounter = 0; + %> + <script> + // array to collect the created IDs + IDs = new Array(); + + // save all created connections in an array to be able to detach them after the selection + Connections = new Array(); + </script> + <% + // render a topology for every choice to be displayed in the dialog + for (TNodeTemplate nt: choices.keySet()) { + + Map<TNodeTemplate, List<TEntityTemplate>> entityTemplates = choices.get(nt); + + for (TNodeTemplate choice: entityTemplates.keySet()) { + id = "choice" + Integer.toString(counter); + + %> + <div id="proposalEditorArea"> + <div id="proposaldrawingarea"> + <% + + topCounter = 0; + %> + <nt:nodeTemplateRenderer client="<%=client%>" relationshipTypes="<%=client.getAllTypes(TRelationshipType.class)%>" repositoryURL='<%=repositoryURL%>' nodeTemplate="<%=nt%>" top="<%=Integer.toString(topCounter)%>" left='<%="0"%>'/> + <script> + + //Map IDs here. ID mapping is necessary to avoid conflict with the modelled NodeTemplates in the background. + <% + randomId = UUID.randomUUID().toString(); + %> + document.getElementById("<%=nt.getId()%>").id = "<%=randomId%>"; + IDs.push("<%=randomId%>"); + <% + idMap.put(nt.getId(), randomId); + %> + </script> + <% + + topCounter = topCounter + NODE_TEMPLATE_DISTANCE; + %> + <!-- use the nodeTemplateRenderer tag to render NodeTemplates--> + <nt:nodeTemplateRenderer client="<%=client%>" relationshipTypes="<%=client.getAllTypes(TRelationshipType.class)%>" repositoryURL='<%=repositoryURL%>' nodeTemplate="<%=choice%>" top="<%=Integer.toString(topCounter)%>" left='<%="0"%>'/> + <script> + //Map IDs here + <% + randomId = UUID.randomUUID().toString(); + %> + document.getElementById("<%=choice.getId()%>").id = "<%=randomId%>"; + IDs.push("<%=randomId%>"); + <% + idMap.put(choice.getId(), randomId); + %> + </script> + </div> + </div> + <% if (entityTemplates.get(choice).size() > 1) { %> + <p> There are several possible Relationship Templates to connect the Node Templates <%=nt.getName()%> and <%=choice.getName()%>. Please choose at least one connection: </p> + <%} + for (TEntityTemplate rtChoice: entityTemplates.get(choice)) { + + TRelationshipTemplate connector = (TRelationshipTemplate) rtChoice; + if (entityTemplates.get(choice).size() > 1) { + %> + <input checked="checked" id="<%=connector.getName()%>" name="<%=connector.getName()%>" type="checkbox" value="<%=connector.getName()%>"> <%=connector.getName()%> <br/> + <% + } + sourceId = ((TNodeTemplate) connector.getSourceElement().getRef()).getId(); + String targetId = ((TNodeTemplate) connector.getTargetElement().getRef()).getId(); + QName type = connector.getType(); + String visualSourceId = idMap.get(sourceId); + String visualTargetId = idMap.get(targetId); + %> + <script> + // connect the rendered NodeTemplates + require(["winery-common-topologyrendering"], function(wct) { + wct.initNodeTemplate(jsPlumb.getSelector(".NodeTemplateShape:not('.hidden')"), true); + }); + var c; + require(["jsplumb"], function(_jsPlumb) { + _jsPlumb.ready(function() { + c = _jsPlumb.connect({ + source:"<%=visualSourceId%>", + target:"<%=visualTargetId%>", + endpoint:"Blank", + type: "<%=type%>" + }); + Connections.push(c); + }) + }); + + </script> + <%} + %> + <br> + <button type="button" class="btn btn-primary btn-default" data-dismiss="modal" id="<%=id%>" value='<%=choice.getName()%>' onclick="onSelected<%=choice.getName()%>()">Use Template: <%=choice.getName()%></button> + <script> + + /** + * Handles a click on the "Select" button. + * + * This selection handler method is created for every NodeTemplate that can be chosen by the user. + * This is realized by inserting the unique names of the NodeTemplate choices in the method name via JSP scriptlet. + */ + function onSelected<%=choice.getName()%>() { + + SelectedRTs = new Array(); + + for (var i = 0; i < Connections.length; i++) { + jsPlumb.detach(Connections[i]); + } + + <% + if (entityTemplates.get(choice).size() == 1) { + %> + SelectedRTs.push("<%=((TRelationshipTemplate) entityTemplates.get(choice).get(0)).getName()%>"); + <% + } else if (entityTemplates.get(choice).size() > 1) { + for (TEntityTemplate rtChoice: entityTemplates.get(choice)) { + TRelationshipTemplate connector = (TRelationshipTemplate) rtChoice; + %> + if (document.getElementById("<%=connector.getName()%>").checked) { + SelectedRTs.push(document.getElementById("<%=connector.getName()%>").value); + } + <% + }} + %> + SelectedItems = new Array(); + SelectedItems.push(document.getElementById("<%=id%>").value); + + if (SelectedItems.length == 0) { + vShowError("Please selected at least one Relationship Template."); + } else { + // add the selected Templates to the topology and restart the completion + var selectedNodeTemplates = JSON.stringify(SelectedItems); + var selectedRelationshipTemplates = JSON.stringify(SelectedRTs); + $.post("jsp/topologyCompletion/selectionHandler.jsp", {topology: topology, allChoices: choices, selectedNodeTemplates: selectedNodeTemplates, selectedRelationshipTemplates: selectedRelationshipTemplates}, + function(data){ + require(["winery-topologycompletion"], function(completer) { + completer.restartCompletion(data, document.getElementById('overwriteTopology').checked,document.getElementById('openInNewWindow').checked, + document.getElementById('topologyName').value, document.getElementById('topologyNamespace').value, true, "<%=stName%>", + "<%=templateURL%>", "<%=repositoryURL%>"); + }); + } + ); + } + } + </script> + <% + counter++; + } + }%> + <br> + <br> + <br> + <button type="button" class="btn btn-primary btn-default" data-dismiss="modal" id="cancel" onclick="onSelectedCancel()">Cancel Automatic Completion</button> + <p><i> Press this button if you want to continue the completion manually.</i> </p> + <script> + // save topology and refresh the page + function onSelectedCancel() { + $.post("jsp/topologyCompletion/topologySaver.jsp", {topology: topology, templateURL: "<%=templateURL%>", repositoryURL: "<%=repositoryURL%>", topologyName: "<%=topologyName%>", topologyNamespace: "<%=topologyNamespace%>", overwriteTopology: "true"}, + function(callback){ + document.location.reload(true); + } + ); + } + </script> +</div>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/relationshipTemplateSelector.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/relationshipTemplateSelector.tag new file mode 100644 index 0000000..58e2d85 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/relationshipTemplateSelector.tag @@ -0,0 +1,158 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ +%> + +<%@tag language="java" pageEncoding="UTF-8" description="This tag is used to render Relationship Templates for selection in a dialog."%> + +<%-- attributes for the topology selection --%> +<%@attribute name="templateURL" type="java.lang.String"%> +<%@attribute name="topologyName" type="java.lang.String"%> +<%@attribute name="topologyNamespace" type="java.lang.String"%> +<%@attribute name="repositoryURL" type="java.lang.String" %> +<%@attribute name="stName" type="java.lang.String" %> +<%@attribute name="choices" type="java.util.List<org.eclipse.winery.model.tosca.TEntityTemplate>"%> + +<%@tag import="java.util.ArrayList"%> +<%@tag import="java.util.HashMap"%> +<%@tag import="java.util.List"%> +<%@tag import="java.util.Map"%> +<%@tag import="java.util.UUID"%> +<%@tag import="javax.xml.namespace.QName"%> +<%@tag import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.repository.client.WineryRepositoryClientFactory"%> +<%@tag import="org.eclipse.winery.repository.client.IWineryRepositoryClient"%> +<%@tag import="org.eclipse.winery.common.Util"%> + +<%@taglib prefix="ntrq" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> +<%@taglib prefix="tc" tagdir="/WEB-INF/tags/common/topologycompletion"%> + +<div id="relationshipTemplateSelector"> +<p> There are several possible Relationship Templates for a connection. <br> Please select your desired connection(s): </p> +<script> + // save all created connections in an array to be able to detach them after the selection + Connections = new Array(); +</script> +<% + // the pixel distance between the displayed NodeTemplates + final int NODE_TEMPLATE_DISTANCE = 150; + + IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + client.addRepository(repositoryURL); + + Map<String, String> idMap = new HashMap<String, String>(); + String sourceId = ""; + String id = "choice"; + + // used for the position of the NodeTemplate in the EditorArea + int topCounter = 0; + + List<TRelationshipTemplate> possibleConnections = new ArrayList<TRelationshipTemplate>(); + + for (TEntityTemplate choice: choices) { + if (choice instanceof TRelationshipTemplate) { + possibleConnections.add((TRelationshipTemplate) choice); + } + } + for (TRelationshipTemplate connector: possibleConnections) { %> + <div id="proposalEditorArea"> + <div id="proposaldrawingarea"> + <div id="allRelationships"> + <% + topCounter = 0; + + for (TEntityTemplate choice: choices) { + if (choice instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) choice; + + topCounter = topCounter + NODE_TEMPLATE_DISTANCE; + %> + <nt:nodeTemplateRenderer client="<%=client%>" relationshipTypes="<%=client.getAllTypes(TRelationshipType.class)%>" repositoryURL='<%=repositoryURL%>' nodeTemplate="<%=nodeTemplate%>" top="<%=Integer.toString(topCounter)%>" left='<%="0"%>'/> + <script> + //Map IDs here + <% + String randomId = UUID.randomUUID().toString(); + %> + document.getElementById("<%=nodeTemplate.getId()%>").id = "<%=randomId%>"; + <% + idMap.put(nodeTemplate.getId(), randomId); + %> + </script> + <% + } + } + + sourceId = ((TNodeTemplate) connector.getSourceElement().getRef()).getId(); + String targetId = ((TNodeTemplate) connector.getTargetElement().getRef()).getId(); + QName type = connector.getType(); + + String visualSourceId = idMap.get(sourceId); + String visualTargetId = idMap.get(targetId); + %> + <script> + // connect the rendered NodeTemplates + require(["winery-common-topologyrendering"], function(wct) { + wct.initNodeTemplate(jsPlumb.getSelector(".NodeTemplateShape:not('.hidden')"), true); + }); + var c; + require(["jsplumb"], function(_jsPlumb) { + _jsPlumb.ready(function() { + c = _jsPlumb.connect({ + source:"<%=visualSourceId%>", + target:"<%=visualTargetId%>", + endpoint:"Blank", + type: "<%=type%>" + }); + Connections.push(c); + }) + }); + </script> + </div> + </div> + </div> + <input id="<%=id%>" name="<%=id%>" type="checkbox" value="<%=connector.getName()%>"> <%=connector.getName()%> <br> + + <%}%> + <button type="button" class="btn btn-primary btn-default" id="btnUseSelection" onclick="useRelationshipTemplateSelection()">Use Selection</button> + <script> + function useRelationshipTemplateSelection() { + // add the selected RelationshipTemplates to the topology and restart the completion + SelectedItems = new Array(); + for (var i= 0; i < document.getElementById("rtchoices").children[0].choice.length; i++) { + if (document.getElementById("rtchoices").children[0].choice[i].checked == true) { + SelectedItems.push(document.getElementById("rtchoices").children[0].choice[i].value); + } + } + + if (SelectedItems.length == 0) { + vShowError("Please selected at least one Relationship Template."); + } else { + $('#chooseRelationshipTemplateDiag').modal('hide'); + var selectedRelationshipTemplates = JSON.stringify(SelectedItems); + // add selected RelationshipTemplate(s) to the topology + $.post("jsp/topologyCompletion/selectionHandler.jsp", {topology: topology, allChoices: choices, selectedRelationshipTemplates: selectedRelationshipTemplates}, + function(data) { + require(["winery-topologycompletion"], function(completer) { + completer.restartCompletion(data, document.getElementById('overwriteTopology').checked,document.getElementById('openInNewWindow').checked, + topologyName, topologyNamespace, true, "<%=stName%>", + "<%=templateURL%>", "<%=repositoryURL%>"); + }); + } + ); + } + } + </script> +</div> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/selectionDialogs.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/selectionDialogs.tag new file mode 100644 index 0000000..9edfced --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/selectionDialogs.tag @@ -0,0 +1,175 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ +%> +<%@tag language="java" pageEncoding="UTF-8" description="This tag is used to create DIVs for the selection dialogs."%> + +<%@attribute name="repositoryURL" type="java.lang.String"%> +<%@attribute name="serviceTemplateName" type="java.lang.String"%> +<%@attribute name="topologyTemplateURL" type="java.lang.String"%> + +<!-- + Topology Completion: chooseRelationshipTemplateDiag. + This dialog serves the user selection of inserted RelationshipTemplates whenever there are several possibilities. +--> +<div class="modal fade" id="chooseRelationshipTemplateDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Topology Completion - Relationship Template Selection</h4> + </div> + <div class="modal-body"></div> + <div class="modal-footer"></div> + </div> + </div> +</div> + +<!-- + Topology Completion: chooseNodeTemplateDiag. + This dialog serves the user selection of inserted Node and RelationshipTemplates when the user selects "Complete topology step-by-step". +--> +<div class="modal fade" id="chooseNodeTemplateDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Topology Completion - Step by Step</h4> + </div> + <div class="modal-body"></div> + <div class="modal-footer"> + <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button> + </div> + </div> + </div> +</div> + +<!-- + Topology Completion: chooseTopologyDiag. + This dialog serves the user selection of completed topologies. +--> +<div class="modal fade" id="chooseTopologyDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Topology Completion - Choose possible solution </h4> + </div> + <div class="modal-body"></div> + <div class="modal-footer"> + <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button> + </div> + </div> + </div> +</div> + +<!-- + Topology Completion: enterCompletionInformationDiag. + This dialog serves the input of information before completing a topology automatically. +--> +<div class="modal fade" id="enterCompletionInformationDiag"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Topology Completion</h4> + </div> + <div class="modal-body"> + <form id="enterCompletionInformationForm" enctype="multipart/form-data"> + <fieldset> + <p> Select Save Option: </p> + <p> <input type="radio" id="overwriteTopology" name="overwriteTopology" onclick="document.getElementById('topologyNamespace').disabled = true; document.getElementById('topologyName').disabled = true; document.getElementById('openInNewWindow').disabled = true;" checked> Overwrite Topology<br> + <input type="radio" id="overwriteTopology" name="overwriteTopology" onclick="document.getElementById('topologyNamespace').disabled = false; document.getElementById('topologyName').disabled = false;document.getElementById('openInNewWindow').disabled = false;"> Create new Topology </p> <p> Name: <input id="topologyName" name="topologyName" disabled="disabled" type="text" size="30" maxlength="30"> </p> <p>Namespace: <input id="topologyNamespace" name="topologyNamespace" disabled="disabled" type="text" size="50" maxlength="60"> </p> + <input id="openInNewWindow" name="openInNewWindow" type="checkbox" disabled="disabled" /> Open Topology in new Window <br> + <input id="completionStyle" name="completionStyle" type="checkbox" /> Complete Topology Step-by-Step + </fieldset> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary btn-default" id="btnCompleteTopology" onclick="onClickCompleteTopology()">Complete Topology</button> + <script> + function onClickCompleteTopology() { + var namespace = document.getElementById('topologyNamespace').value; + var validURIregexp = new RegExp("([A-Za-z][A-Za-z0-9+\\-.]*):(?:(//)(?:((?:[A-Za-z0-9\\-._~!$&'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?((?:\\[(?:(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)|[Vv][0-9A-Fa-f]+\\.[A-Za-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[A-Za-z0-9\\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*))(?::([0-9]*))?((?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|/((?:(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)?)|((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|)(?:\\?((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?(?:\#((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?"); + if (!document.getElementById('overwriteTopology').checked && document.getElementById('topologyName').value == "") { + vShowError("Please enter a name for the new topology."); + } else if (!document.getElementById('overwriteTopology').checked && (document.getElementById('topologyNamespace').value == "" || !validURIregexp.test(namespace))) { + vShowError("Please enter a valid name space for the new topology."); + } + else { + $('#enterCompletionInformationDiag').modal('hide'); + + require(["winery-topologycompletion"], function(completer) { + completer.complete(document.getElementById('overwriteTopology').checked,document.getElementById('openInNewWindow').checked,document.getElementById('topologyName').value, document.getElementById('topologyNamespace').value, document.getElementById('completionStyle').checked, + "<%=repositoryURL%>", "<%=serviceTemplateName%>", "<%=topologyTemplateURL%>"); + }); + + } + } + </script> + </div> + </div> + </div> +</div> + +<script> + $(function() { + chooseRelationshipTemplateDiag = $('#chooseRelationshipTemplateDiag'); + + chooseRelationshipTemplateDiag.on('show', function() { + $(this).find('form')[0].reset(); + }); + + chooseNodeTemplateDiag = $('#chooseNodeTemplateDiag'); + + chooseNodeTemplateDiag.on('show', function() { + $(this).find('form')[0].reset(); + }); + + chooseNodeTemplateDiag.on('hidden.bs.modal', function () { + for (var i = 0; i < Connections.length; i++) { + jsPlumb.detach(Connections[i]); + } + $(document.getElementById("nodeTemplateSelector")).remove(); + }); + + chooseTopologyDiag = $('#chooseTopologyDiag'); + + chooseTopologyDiag.on('show', function() { + $(this).find('form')[0].reset(); + }); + + chooseTopologyDiag.on('hidden.bs.modal', function () { + for (var i = 0; i < Connections.length; i++) { + jsPlumb.detach(Connections[i]); + } + $(document.getElementById("topologyTemplateSelector")).remove(); + }); + + enterCompletionInformationDiag = $('#enterCompletionInformationDiag'); + + enterCompletionInformationDiag.on('show', function() { + $(this).find('form')[0].reset(); + }); + }); + + /** + * This function is invoked when the button "Complete Topology" is + * selected. It will open a dialog to enter necessary information for the + * completion. + */ + function completeTopology() { + // show the dialog to enter information for the topology completion + enterCompletionInformationDiag.modal("show"); + } +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/topologyTemplateSelector.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/topologyTemplateSelector.tag new file mode 100644 index 0000000..0d73a57 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/common/topologycompletion/topologyTemplateSelector.tag @@ -0,0 +1,246 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ +%> + +<%@tag language="java" pageEncoding="UTF-8" description="This tag is used to render Topology Templates for selection in a dialog."%> + +<%-- attributes for the topology selection --%> +<%@attribute name="templateURL" type="java.lang.String"%> +<%@attribute name="topologyName" type="java.lang.String"%> +<%@attribute name="topologyNamespace" type="java.lang.String"%> +<%@attribute name="repositoryURL" type="java.lang.String" %> +<%@attribute name="solutionTopologies" type="java.util.List<org.eclipse.winery.model.tosca.TTopologyTemplate>"%> + +<%@tag import="java.io.StringWriter"%> +<%@tag import="java.util.HashMap"%> +<%@tag import="java.util.Map"%> +<%@tag import="java.util.List"%> +<%@tag import="java.util.UUID"%> +<%@tag import="javax.xml.bind.Marshaller"%> +<%@tag import="javax.xml.bind.JAXBContext"%> +<%@tag import="javax.xml.bind.JAXBException"%> +<%@tag import="javax.xml.namespace.QName"%> +<%@tag import="org.eclipse.winery.model.tosca.Definitions"%> +<%@tag import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@tag import="org.eclipse.winery.model.tosca.TServiceTemplate"%> +<%@tag import="org.eclipse.winery.model.tosca.TTopologyTemplate"%> +<%@tag import="org.eclipse.winery.repository.client.WineryRepositoryClientFactory"%> +<%@tag import="org.eclipse.winery.repository.client.IWineryRepositoryClient"%> +<%@tag import="org.eclipse.winery.common.Util"%> + +<%@taglib prefix="ntrq" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates"%> + +<div id="topologyTemplateSelector"> +<p> There are several possible topology solutions <br> Please select your desired topology: </p> + <script> + // array to collect the created IDs + IDs = new Array(); + + // save all created connections in an array to be able to detach them after the selection + Connections = new Array(); + </script> +<% + // the pixel distance between the displayed NodeTemplates + final int NODE_TEMPLATE_DISTANCE = 150; + + List<TTopologyTemplate> topologyTemplateSelector = solutionTopologies; + int i = 0; + int counter = 0; + Map<String, String> idMap; + for (TTopologyTemplate choice: topologyTemplateSelector) { + Definitions definitions = new Definitions(); + TServiceTemplate st = new TServiceTemplate(); + st.setTopologyTemplate(choice); + definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(st); + JAXBContext context = JAXBContext.newInstance(Definitions.class); + Marshaller m = context.createMarshaller(); + StringWriter stringWriter = new StringWriter(); + + m.marshal(definitions, stringWriter); + int topCounter = 0; + IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + client.addRepository(repositoryURL); + String id = "solution" + Integer.toString(i); + + String sourceId = null; + idMap = new HashMap<String, String>(); + + %> + <div id="proposalEditorArea"> + <div id="proposaldrawingarea"> + <div id="<%=counter%>"> + <script> IDs.push("<%=id%>"); </script> + <% + for (TEntityTemplate entity: choice.getNodeTemplateOrRelationshipTemplate()) { + + if (entity instanceof TNodeTemplate) { + TNodeTemplate nodeTemplate = (TNodeTemplate) entity; + + %> + <nt:nodeTemplateRenderer client="<%=client%>" relationshipTypes="<%=client.getAllTypes(TRelationshipType.class)%>" repositoryURL='<%=repositoryURL%>' nodeTemplate="<%=nodeTemplate%>" top="<%=Integer.toString(topCounter)%>" left='<%="0"%>'/> + + <% + String randomId = UUID.randomUUID().toString(); + %> + <script> + document.getElementById("<%=nodeTemplate.getId()%>").id = "<%=randomId%>"; + </script> + <% + topCounter = topCounter + NODE_TEMPLATE_DISTANCE; + idMap.put(nodeTemplate.getId(), randomId); + %> + + <% + } + } + for (TEntityTemplate entity: choice.getNodeTemplateOrRelationshipTemplate()) { + if (entity instanceof TRelationshipTemplate) { + TRelationshipTemplate connector = (TRelationshipTemplate) entity; + sourceId = ((TNodeTemplate) connector.getSourceElement().getRef()).getId(); + String visualSourceId = idMap.get(sourceId); + String targetId = ((TNodeTemplate) connector.getTargetElement().getRef()).getId(); + String visualTargetId = idMap.get(targetId); + QName type = connector.getType(); + %> + <script type='text/javascript'> + var c; + require(["winery-common-topologyrendering"], function(wct) { + wct.initNodeTemplate(jsPlumb.getSelector(".NodeTemplateShape:not('.hidden')"), true); + require(["jsplumb"], function(_jsPlumb) { + _jsPlumb.ready(function() { + c = _jsPlumb.connect({ + source:"<%=visualSourceId%>", + target:"<%=visualTargetId%>", + endpoint:"Blank", + type: "<%=type%>" + }); + Connections.push(c); + }) + }); + wct.handleConnectionCreated(c); + }); + </script> <% + } + } + %> + </div> + </div> + </div> + <br> + <input name="<%=id%>" id="<%=id%>" type="checkbox" value='<%=stringWriter.toString()%>' onclick="onClick<%=id%>()"> Save this Topology + <script> + /** + * Handles a click on the "Save this Topology" checkbox. + */ + function onClick<%=id%>() { + if (document.getElementById('<%=id%>').checked) { + document.getElementById('<%=id + "overwrite"%>').disabled = false; + document.getElementById('<%=id + "name"%>').disabled = false; + document.getElementById('<%=id + "namespace"%>').disabled = false; + document.getElementById('<%=id + "newWindow"%>').disabled = false; + } + else { + document.getElementById('<%=id + "overwrite"%>').disabled = true; + document.getElementById('<%=id + "name"%>').disabled = true; + document.getElementById('<%=id + "namespace"%>').disabled = true; + document.getElementById('<%=id + "newWindow"%>').disabled = true; + } + } + </script> + <input disabled="disabled" name='<%=id + "overwrite"%>' id='<%=id + "overwrite"%>' type="checkbox" onclick='onClick<%=id + "overwrite"%>()'> Overwrite current Topology + <script> + /** + * Handles a click on the "Overwrite current Topology" checkbox. + */ + function onClick<%=id + "overwrite"%>() { + if (document.getElementById('<%=id + "overwrite"%>').checked) { + document.getElementById('<%=id + "name"%>').disabled = true; + document.getElementById('<%=id + "namespace"%>').disabled = true; + document.getElementById('<%=id + "newWindow"%>').disabled = true; + } else { + document.getElementById('<%=id + "name"%>').disabled = false; + document.getElementById('<%=id + "namespace"%>').disabled = false; + document.getElementById('<%=id + "newWindow"%>').disabled = false; + } + } + </script> + <input disabled="disabled" name='<%=id + "newWindow"%>' id='<%=id + "newWindow"%>' type="checkbox"> Open in new Window <br> <br> + <p>Name: <input disabled="disabled" id='<%=id + "name"%>' name='<%=id + "name"%>' value="<%=topologyName%>" type="text" size="30" maxlength="30"> </p> + <p>Namespace: <input disabled="disabled" id='<%=id + "namespace"%>' value="<%=topologyNamespace%>" name='<%=id + "namespace"%>' type="text" size="50" maxlength="60"> </p> + <% + counter++; + i++; + } +%> + <button type="button" id="save" class="btn btn-primary btn-default">Save Topologies</button> + <script> + $('#save').on('click', function() { + + for (var i = 0; i < IDs.length; i++) { + if (document.getElementById(IDs[i]).checked) { + + var name = document.getElementById(IDs[i] + 'name').value; + var namespace = document.getElementById(IDs[i] + 'namespace').value; + var overwrite = document.getElementById(IDs[i] + 'overwrite').checked; + var openInNewWindow = document.getElementById(IDs[i] + 'newWindow').checked; + + // check validity of the namespace + var validURIregexp = new RegExp("([A-Za-z][A-Za-z0-9+\\-.]*):(?:(//)(?:((?:[A-Za-z0-9\\-._~!$&'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?((?:\\[(?:(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)|[Vv][0-9A-Fa-f]+\\.[A-Za-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[A-Za-z0-9\\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*))(?::([0-9]*))?((?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|/((?:(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)?)|((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|)(?:\\?((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?(?:\#((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?"); + if (validURIregexp.test(namespace) || overwrite) { + + if (!overwrite) { + // first create a new service template via AJAX call + var dataToSend = "name=" + name + "&namespace=" + namespace; + var url = "<%=repositoryURL%>" + "/servicetemplates/"; + $.ajax( + { + type: "POST", + async: false, + url: url, + "data": dataToSend, + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add Service Template."); + } + }); + } + + // now save the topology template + $.post("jsp/topologyCompletion/topologySaver.jsp", {topology: document.getElementById(IDs[i]).value, templateURL: "<%=templateURL%>", repositoryURL: "<%=repositoryURL%>", topologyName: name, topologyNamespace: namespace, overwriteTopology: overwrite}, + function(data){ + if (openInNewWindow) { + // a new topology has been created, open it in a new window + var win=window.open('?repositoryURL=' + "<%=repositoryURL%>" + '&ns='+ namespace + '&id=' + name, '_blank'); + win.focus(); + } else if (overwrite) { + // refresh page + document.location.reload(true); + } + // close the dialog + chooseTopologyDiag.modal("hide"); + vShowSuccess("Successfully Saved Topologies.") + } + ); + } else { + vShowError("Please enter a valid namespace."); + } + } + } + }); + </script> +</div> + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/idInput.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/idInput.tag new file mode 100644 index 0000000..86dae1c --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/idInput.tag @@ -0,0 +1,43 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="input field for an id unique in the target namespace. Current implementation: Unique in the topology modeler" pageEncoding="UTF-8"%> + +<%@attribute name="inputFieldId" required="true" description="The name and id of the input field"%> + +<div class="form-group" id="${inputFieldId}Group"> + <label for="${inputFieldId}" class="control-label">Id:</label> + <input id="${inputFieldId}" class="form-control" name="${inputFieldId}" type="text" required="required" /> +</div> + +<script> +$("#${inputFieldId}").typing({ + stop: function(evt, elem) { + // check for existinance in the current model + // TODO: global check using the backend + var isSuccess; + try { + var val = elem.val(); + isSuccess = (val != "") && ($("#" + elem.val()).length == 0); + } catch(err) { + // all syntax errors are invalid inputs + isSuccess = false; + } + var newClass = (isSuccess? "has-success" : "has-error"); + var div = elem.parent(); + if (!div.hasClass(newClass)) { + div.removeClass("has-error").removeClass("has-success").addClass(newClass); + } + } +}); +</script>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/namespaceChooser.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/namespaceChooser.tag new file mode 100644 index 0000000..25a19e3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/namespaceChooser.tag @@ -0,0 +1,52 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="places a bootstrap form control to chooose a namespace. A new namespace can be created" pageEncoding="UTF-8"%> + +<!-- + This tag is shared at repository and topologytemplate. + Both versions differ from each other. + In the repository, ns.decoded is used. + In the topology modeler only "ns" is used: + In other words: The topology modeler passes a Collection<String>, whereas repository passes Collection<Namespace> + --> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%@attribute name="allNamespaces" required="true" type="java.util.Collection" description="All known namespaces as strings (because the topology modeler currently doesn't provide that as list of winery namespace objects)"%> +<%@attribute name="idOfInput" required="true" description="The id if the input field storing the namespace. Also used as name"%> +<%@attribute name="nameOfInput" required="false" description="The name if the input field storing the namespace. If not provided, ifOfInput is used"%> +<%@attribute name="selected" description="The currently selected namespace (optional)"%> + +<c:if test="${empty nameOfInput}"><c:set var="nameOfInput" value="${idOfInput}"></c:set></c:if> + +<!-- createArtifactTemplate class is required for artifactcreationdialog --> +<div class="form-group createArtifactTemplate"> + <label for="${idOfInput}" class="control-label">Namespace</label> + <input type="hidden" class="form-control" name="${nameOfInput}" id="${idOfInput}"></input> +</div> + +<script> +// we have to use data as select2 does not allow "createSearchChoice" when using <select> as underlying html element +$("#${idOfInput}").select2({ + createSearchChoice: function(term) { + // enables creation of new namespaces + return {id:term, text:term}; + }, + data:[ + <c:forEach var="ns" items="${allNamespaces}" varStatus="loop"> + {id:"${ns}",text:"${ns}"}<c:if test="${!loop.last}">,</c:if> + </c:forEach> + ] +}).select2("val", "${selected}"); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/palette.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/palette.tag new file mode 100644 index 0000000..e6363f6 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/palette.tag @@ -0,0 +1,207 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ +--%> +<%@tag language="java" pageEncoding="UTF-8" description="Renders the palette on the left"%> + +<%@attribute name="repositoryURL" required="true" type="java.lang.String"%> +<%@attribute name="client" required="true" description="IWineryRepository" type="org.eclipse.winery.common.interfaces.IWineryRepository"%> +<%@attribute name="relationshipTypes" description="the known relationship types" required="true" type="java.util.Collection"%> + +<%@tag import="javax.xml.namespace.QName" %> +<%@tag import="java.util.Collection"%> +<%@tag import="java.util.UUID"%> +<%@tag import="java.util.List"%> +<%@tag import="org.eclipse.winery.common.interfaces.IWineryRepository" %> +<%@tag import="org.eclipse.winery.model.tosca.TNodeType"%> +<%@tag import="org.eclipse.winery.common.Util" %> + +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> + +<link rel="stylesheet" href="css/palette.css" /> + +<div id="palette"> + +<div id="paletteLabel"> +Palette +</div> + +<% + Collection<TNodeType> allNodeTypes = client.getAllTypes(TNodeType.class); + if (allNodeTypes.isEmpty()) { +%> + <script> + vShowError("No node types exist. Please add node types in the repository."); + </script> + <% + } + for (TNodeType nodeType: allNodeTypes) { + if (nodeType.getName() == null) { + System.err.println("Invalid nodetype in ns " + nodeType.getTargetNamespace()); + continue; + } +%> + <div class="paletteEntry"> + <div class="iconContainer"> + <img class="icon" onerror="var that=this; require(['winery-common-topologyrendering'], function(wct){wct.imageError(that);});" src="<%= repositoryURL %>/nodetypes/<%= Util.DoubleURLencode(nodeType.getTargetNamespace()) %>/<%=Util.DoubleURLencode(nodeType.getName())%>/visualappearance/50x50" /> + </div> + <div class="typeContainer"> + <div class="typeContainerMiddle"> + <div class="typeContainerInner"> + <%= nodeType.getName() %> + </div> + </div> + </div> + + <div class="hidden"> + <nt:nodeTemplateRenderer + repositoryURL="${repositoryURL}" + client="${client}" + relationshipTypes="${relationshipTypes}" + nodeTypeQName="<%=new QName(nodeType.getTargetNamespace(), nodeType.getName())%>" + nodeType="<%=nodeType%>" /> + </div> + </div> + +<% + } +%> + +</div> + + +<script> + + //$("#palette").css("width","20px"); + //$("div.paletteEntry").hide(); + + $("#palette").click (function() { + showPalette(); + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + }); + + function showPalette() { + // reset width to original CSS width + $("#palette").removeClass("shrunk"); + // show all palette entries + $("div.paletteEntry").show(); + $("#paletteLabel").hide(); + } + + function hidePalette() { + $("#palette").addClass("shrunk"); + // hide all palette entries + $("div.paletteEntry").hide(); + $("#paletteLabel").show(); + } + + $(function() { + $( "div.paletteEntry" ).draggable({ + cursor: "move", + cursorAt: { top: 40, left: 112 }, + helper: function( event ) { + var newObj = $(this).find("div.NodeTemplateShape").clone(); + newObj.removeClass("hidden"); + newObj.css("z-index", "2000"); + newObj.find ("div.endpointContainer").remove(); + + // Ensure that obj is appended to drawingarea and not to palette + // Consequence: the dragged object is always under the cursor and not paintet with an offset equal to the scrollheight + $("#drawingarea").append(newObj); + + return newObj; + }, + start: function( event, ui ) { + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + // The palette is kept visible after a drag start, + // therefore no action + // hidePalette(); + }, + appendTo: '#drawingarea' + }); + + + $( "div#drawingarea" ).droppable({ + accept: function(d) { + if (d.hasClass("paletteEntry")) { + return true; + } + }, + drop: function( event, ui ) { + + var palEntry = ui.draggable; + var templateCode = palEntry.find("div.NodeTemplateShape").clone().wrap("<div></div>").parent().html(); + + var newObj = $(templateCode); + + newObj.removeClass("ui-draggable"); + newObj.removeClass("ui-droppable"); + newObj.removeClass("hidden"); + + // generate and set id + var type = newObj.find("div.type.nodetemplate").text(); + var id = type; + // we cannot use the id as the initial name, because we want to preserve special characters in the name, but not in the id. + var name = type; + + // quick hack to make id valid + // currently, only spaces and dots cause problems + id = id.replace(" ", "_"); + id = id.replace(".", "_"); + + if ($("#" + id).length != 0) { + var count = 2; + var idprefix = id + "_"; + do { + id = idprefix + count; + count++; + } while ($("#" + id).length != 0); + // also adjust name + name = name + "_" + count; + } + newObj.attr("id", id); + newObj.children("div.headerContainer").children("div.id").text(id); + + // initial name has been generated based on the id + newObj.children("div.headerContainer").children("div.name").text(name); + + // fix main.css -> #editorArea -> margin-top: 45px; + var top = Math.max(event.pageY-45, 0); + + // drag cursor is at 112/40 + // fix that + top = Math.max(top-40, 0); + var left = Math.max(event.pageX-112, 0); + + newObj.css("top", top); + newObj.css("left", left); + + newObj.addClass("selected"); + + // insert into sheet + newObj.appendTo( $( "div#drawingarea" ) ); + + // initialization works only for displayed objects + require(["winery-common-topologyrendering"], function(wct) { + wct.initNodeTemplate(newObj, true); + + // handle menus + winery.events.fire(winery.events.name.SELECTION_CHANGED); + }); + } + }) + + +}); + +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/nodetemplates/propertiesOfOneNodeTemplate.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/nodetemplates/propertiesOfOneNodeTemplate.tag new file mode 100644 index 0000000..238e34a --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/nodetemplates/propertiesOfOneNodeTemplate.tag @@ -0,0 +1,147 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements to fit updated index.jsp + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> + +<%@tag language="java" pageEncoding="UTF-8" description="Renders the properies of one node tempate on the right"%> + +<%@attribute name="repositoryURL" required="true" type="java.lang.String" description="The repository URL"%> + +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> + + +<link rel="stylesheet" href="css/propertiesview.css" /> + +<div id="NTPropertiesView" class="propertiesView" style="display: none;"> + + <div id="nodeTemplateInformationSection"> + <%-- + If this is layouted strangely, maybe a <form> wrapper has to be added + Be aware that nested buttons then trigger a submission of the form (-> ct:spinnerwithinphty) + --%> + <fieldset> + <div class="form-group"> + <label for="nodetemplateid">Id</label> + <input id="nodetemplateid" disabled="disabled" class="form-control"></input> + </div> + <div class="form-group"> + <label for="nodetemplatename" class="control-label">Name</label> + <input id="nodetemplatename" name="name" class="form-control"/> + </div> + <div class="form-group"> + <label for="nodetemplateType">Type</label> + <%-- filled by fillInformationSection --%> + <a id="nodetemplateType" target="_blank" href="#" class="form-control"></a> + </div> + <ct:spinnerwithinphty min="0" width="10" changedfunction="minInstancesChanged" label="min" id="minInstances" /> + <ct:spinnerwithinphty min="1" width="10" changedfunction="maxInstancesChanged" label="max" id="maxInstances" withinphty="true" /> + </fieldset> + </div> + +</div> + +<script> + function minInstancesChanged(event, ui) { + var val; + if (ui === undefined) { + val = $("#minInstances").val(); + } else { + val = ui.value; + } + ntMin.html(val); + } + + function maxInstancesChanged(event, ui) { + var val; + if (ui === undefined) { + val = $("#maxInstances").val(); + } else { + val = ui.value; + } + ntMax.html(val); + } + + // the name input field of the properties section + var nameInput = $("#nodetemplatename"); + + // the min/max fields of the currently selected node template + var ntMin; + var ntMax; + + function fillInformationSection(nodeTemplate) { + require(["winery-support-common"], function(wsc) { + // currently doesn't help for a delayed update + //informationSection.slideDown(); + + $("#nodetemplateid").val(nodeTemplate.attr("id")); + + var headerContainer = nodeTemplate.children("div.headerContainer"); + + // copy name + var nameField = headerContainer.children("div.name"); + var name = nameField.text(); + nameInput.val(name); + + // copy type + var typeQName = headerContainer.children("span.typeQName").text(); + var href = wsc.makeNodeTypeURLFromQName("${repositoryURL}", typeQName); + var type = headerContainer.children("div.type").text(); + $("#nodetemplateType").attr("href", href).text(type); + + // we could use jQuery-typing, but it is not possible to replace key events there + nameInput.off("keyup"); + nameInput.on("keyup", function() { + nameField.text($(this).val()); + }); + + // handling of min and max + ntMin = nodeTemplate.children(".headerContainer").children(".minMaxInstances").children(".minInstances"); + $("#minInstances").val(ntMin.text()); + ntMax = nodeTemplate.children(".headerContainer").children(".minMaxInstances").children(".maxInstances"); + $("#maxInstances").val(ntMax.text()); + }); + } + + function showViewOnTheRight() { + $("#NTPropertiesView").fadeIn(); + } + + function hideViewOnTheRight() { + $("#NTPropertiesView").fadeOut(); + } + +$(function() { + winery.events.register( + winery.events.name.SELECTION_CHANGED, + function() { + // min/max instances do not lost focus if other shape is clicked + // workaround + if ($("#minInstances").is(":focus")) { + minInstancesChanged(); + } + if ($("#maxInstances").is(":focus")) { + maxInstancesChanged(); + } + var nodeTemplate = $("div.NodeTemplateShape.selected"); + var numSelected = nodeTemplate.length; + if (numSelected == 1) { + fillInformationSection(nodeTemplate); + showViewOnTheRight(); + } else { + hideViewOnTheRight(); + } + } + ); +}); +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/nodetemplates/reqscaps/addorupdatereqorcap.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/nodetemplates/reqscaps/addorupdatereqorcap.tag new file mode 100644 index 0000000..0ec6f5d --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/nodetemplates/reqscaps/addorupdatereqorcap.tag @@ -0,0 +1,248 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag description="Dialog to change a req or cap. Offers function showEditDiagFor${shortName}(id)" pageEncoding="UTF-8"%> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> +<%@taglib prefix="o" tagdir="/WEB-INF/tags/common/orioneditor"%> +<%@taglib prefix="w" tagdir="/WEB-INF/tags"%> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions"%> + +<%@attribute name="headerLabel" required="true"%> +<%@attribute name="shortName" required="true" description="Used for diag id, function name suffix, Req|Cap"%> +<%@attribute name="requirementOrCapability" required="true" description="requirement|capability"%> +<%@attribute name="cssClassPrefix" required="true"%> +<%@attribute name="allTypes" required="true" type="java.util.Collection" description="Collection<QName> of all available types" %> +<%@attribute name="clazz" required="true" type="java.lang.Class" description="TRequirement.class or TCapability.class" %> +<%@attribute name="repositoryURL" required="true" %> + +<div class="modal fade" id="AddOrUpdate${shortName}Diag"> + <div class="modal-dialog"> + <div class="modal-content" style="width:660px;"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title"><span id="headerAddOrUpdate"></span> ${headerLabel}</h4> + </div> + <div class="modal-body"> + <form id="add${shortName}Form" enctype="multipart/form-data"> + <fieldset> + <w:idInput inputFieldId="${shortName}Id"/> + + <div class="form-group"> + <label for="${shortName}NameChooser" class="control-label">Definition Name:</label> + <input id="${shortName}NameChooser" class="form-control" type="text" required="required" /> + </div> + + <div class="form-group"> + <label for="${shortName}TypeDisplay" class="control-label">${shortName} Type:</label> + <input id="${shortName}TypeDisplay" class="form-control" type="text" required="required" disabled="disabled"/> + </div> + + <div id="${shortName}PropertiesContainer"> + </div> + </fieldset> + </form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" id="add${shortName}btn" class="btn btn-primary" onclick="addOrUpdate${shortName}(false);">Add</button> + <button type="button" id="delete${shortName}btn" class="btn btn-danger" onclick="deleteCurrent${shortName}();">Delete</button> + <button type="button" id="update${shortName}btn" class="btn btn-primary" onclick="addOrUpdate${shortName}(true);">Change</button> + </div> + </div> + </div> +</div> + +<script> + +/* + * The following variables are declared twice due to double inclusion of this .tag flie + * Due to JavaScript magic, it works nevertheless + */ +var selectedNodeTemplateForReqCapAddition; + +//global variable set by editPropertiesXML and read by save${shortName}Edits +var nodeTemplateEditedReqOrCap; + + +function deleteCurrent${shortName}() { + nodeTemplateEditedReqOrCap.remove(); + $("#AddOrUpdate${shortName}Diag").modal("hide"); +} + +function update${shortName}PropertiesContainerWithClone(propertiesContainerToClone) { + var clone = propertiesContainerToClone.clone(); + $("#${shortName}PropertiesContainer").empty().append(clone); + clone.find(".KVPropertyValue").editable({mode: "inline"}); +} + +function update${shortName}PropertiesFromSelectedType() { + var data = $("#${shortName}NameChooser").select2("data"); + var name = data.text; + var type = data.id; + + // fill in type + // TODO: use qname2href and store QName in data-qname for later consumption -- possibly qname2href should always store the qname in data-qname + $("#${shortName}TypeDisplay").val(type); + + // fill in properties (derived from type) + var propertiesContainer= $(".skelettonPropertyEditorFor${shortName} > span:contains('" + type + "')").parent().children("div"); + update${shortName}PropertiesContainerWithClone(propertiesContainer); +} + +$("#${shortName}NameChooser").on("change", function(e) { + update${shortName}PropertiesFromSelectedType(); +}); + +/** + * Called when a req/cap should be added or updated + * Update mode is triggered if reqOrCapIdtoUpdate is given + * + * @param nodeTemplateId the node template id to add a req/cap to. undefined in update mode + * @param reqOrCapIdtoUpdate + */ +function showAddOrUpdateDiagFor${shortName}(nodeTemplateId, reqOrCapIdToUpdate) { + var update = (typeof reqOrCapIdToUpdate !== "undefined"); + + if (update) { + nodeTemplateEditedReqOrCap = $("#" + reqOrCapIdToUpdate); + // in update mode, nodeTemplateId is not provided, we have to search for the right shape + selectedNodeTemplateForReqCapAddition = nodeTemplateEditedReqOrCap.closest(".NodeTemplateShape"); + } else { + selectedNodeTemplateForReqCapAddition = $("#" + nodeTemplateId); + } + + require(["winery-support-common"], function(wsc) { + var typeQName = selectedNodeTemplateForReqCapAddition.children("div.headerContainer").children("span.typeQName").text(); + var urlFragment = wsc.getURLFragmentOutOfFullQName(typeQName); + var url = "${repositoryURL}/nodetypes/" + urlFragment + "/${requirementOrCapability}definitions/"; + $.ajax({ + url: url, + dataType: "json" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch ${requirementOrCapability} definitions", jqXHR, errorThrown); + }).done(function(data) { + // now, we have all available requirement definitions + // we have to ask each of it for the type + // we use the type as key for the option and the name as displayed text + // select2 perfectly handles duplicate keys + + var select2Data = []; + + $.each(data, function(i,e) { + var rqDefURL = url + e + "/type"; + $.ajax({ + url: rqDefURL, + async: false, + dataType: "text" + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch type for " + e, jqXHR, errorThrown); + }).done(function(data) { + var item = { + id: data, + text: e + }; + select2Data.push(item); + }); + }); + + $("#${shortName}NameChooser").select2({ + placeholder: "Select name", + data: select2Data + }); + + if (update) { + $("#add${shortName}btn").hide(); + $("#update${shortName}btn").show(); + $("#delete${shortName}btn").show(); + $("#headerAddOrUpdate").text("Change"); + + // collect existing data in variables + var id = nodeTemplateEditedReqOrCap.children(".id").text(); + var name = nodeTemplateEditedReqOrCap.children(".name").text(); + var type = nodeTemplateEditedReqOrCap.children(".type").children("a").data("qname"); + var propertiesContainer = nodeTemplateEditedReqOrCap.children(".propertiesContainer"); + + // update displays + + // id + $("#${shortName}Id").val(id); + + // name + // we use the type as key at NameChooser. We hope that there are no duplicates. Otherwise, update won't work. + $("#${shortName}NameChooser").select2("val", type); + // make consistency check + var data = $("#${shortName}NameChooser").select2("data"); + if (data == null) { + vShowError("type " + type + " could not be selected.") + } else if (name != (data.text)) { + vShowError("There are two names for different types. That case is not handled in the UI."); + } + + // type + $("#${shortName}TypeDisplay").val(type); + + // properties + update${shortName}PropertiesContainerWithClone(propertiesContainer); + } else { + $("#add${shortName}btn").show(); + $("#update${shortName}btn").hide(); + $("#delete${shortName}btn").hide(); + $("#headerAddOrUpdate").text("Add"); + + // QUICK HACK if dialog has been shown before -> show properties of selected type + if ($("#${shortName}NameChooser").select2("data") != null) { + update${shortName}PropertiesFromSelectedType(); + } + } + + $("#AddOrUpdate${shortName}Diag").modal("show"); + }); + }); +} + +/** + * Called at click on button "Add" or "Change" + */ +function addOrUpdate${shortName}(update) { + if (highlightRequiredFields()) { + vShowError("Please fill in all required fields"); + return; + } + require(["tmpl"], function(tmpl) { + // Generate skeletton div + var sel2data = $("#${shortName}NameChooser").select2("data"); + var data = { + id: $("#${shortName}Id").val(), + name: sel2data.text, + type: sel2data.id + } + // tmpl-${shortName} is defined in reqsorcaps.tag + var div = tmpl("tmpl-${shortName}", data); + + // Add the div to the node template + if (update) { + nodeTemplateEditedReqOrCap.replaceWith(div); + } else { + selectedNodeTemplateForReqCapAddition.children(".${cssClassPrefix}Container").children(".content").children(".addnewreqorcap").before(div); + } + + // Put properties at the right place + $("#toBeReplacedByProperties").replaceWith($("#${shortName}PropertiesContainer").children()); + + $("#AddOrUpdate${shortName}Diag").modal("hide"); + }); +} + +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/relationshiptemplates/propertiesOfOneRelationshipTemplate.tag b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/relationshiptemplates/propertiesOfOneRelationshipTemplate.tag new file mode 100644 index 0000000..8c63dca --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/tags/templates/relationshiptemplates/propertiesOfOneRelationshipTemplate.tag @@ -0,0 +1,179 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--%> +<%@tag language="java" pageEncoding="UTF-8" description="Renders the properies of one relationship tempate on the right"%> + +<%@attribute name="relationshipTypes" required="true" type="java.util.Collection" %> +<%@attribute name="repositoryURL" required="true" type="java.lang.String" description="The repository URL"%> + +<link rel="stylesheet" href="css/propertiesview.css" /> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="props" tagdir="/WEB-INF/tags/common/templates" %> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> + +<div id="RTPropertiesView" class="propertiesView" style="display: none;"> + + <div id="relationshipTemplateInformationSection"> + <fieldset> + <div class="form-group"> + <label for="relationshiptemplateid">Id</label> + <input id="relationshiptemplateid" disabled="disabled" class="form-control"></input> + </div> + <div class="form-group"> + <label for="relationshiptemplatename" class="control-label">Name</label> + <a href="#" id="relationshiptemplatename" data-title="Name" data-type="text" class="form-control"></a> + </div> + <div class="form-group"> + <label for="relationshipType">Type</label> + <%-- filled by showRTViewOnTheRight --%> + <a id="relationshipType" target="_blank" href="#" class="form-control"></a> + </div> + <div class="form-group"> + <label for="RTreq" class="control-label">Requirement</label> + <select id="RTreq" class="form-control"> + </select> + </div> + <div class="form-group"> + <label for="RTcap" class="control-label">Capability</label> + <select id="RTcap" class="form-control"> + </select> + </div> + </fieldset> + </div> + +</div> + +<script> + + var currentlySelectedConn = null; + + /** + * Fills the requirement and capabilities dropdowns with the available reqs and caps (which are defined at the source/target node template) + * + * @param conn the connection itself + * @param dataField = "req"|"cap" + * @param sourceDivClass = requirementsContainer | capabilitiesContainer + */ + function fillReqOrCap(conn, dataField, nodetemplateId, sourceDivClass, targetSelect) { + var nt = $("#" + nodetemplateId); + var reqsOrCaps = nt.children("." + sourceDivClass).children(".content").children(".reqorcap"); + var connReqCap = winery.connections[conn.id][dataField]; + + targetSelect.empty(); + + var optData = { + value: "__NONE__", + text: "(none)" + }; + if (!connReqCap) { + selected: true + } + require(["tmpl"], function(tmpl) { + var newOption = tmpl("tmpl-option", optData); + targetSelect.append(newOption); + + reqsOrCaps.each(function(i,e) { + optData.value = $(e).children(".id").children("span.id").text(); + optData.text = $(e).children(".name").children("span.name").text(); + optData.selected = (optData.value == connReqCap); + newOption = tmpl("tmpl-option", optData); + targetSelect.append(newOption); + }); + }); + + targetSelect.off("change"); + targetSelect.on("change", function(e) { + var val = targetSelect.val(); + if (val == "__NONE__") { + delete(winery.connections[conn.id][dataField]); + } else { + winery.connections[conn.id][dataField] = val; + } + }); + } + + function fillType(nsAndLocalName) { + require(["winery-support-common"], function(wsc) { + var href = wsc.makeRelationshipTypeURLFromNSAndLocalName("${repositoryURL}", nsAndLocalName); + // localname is always the name of the relationship type because the specification requires a "name" attribute only and does not foresee an "id" attribute + $("#relationshipType").attr("href", href).text(nsAndLocalName.localname); + }) + } + + function displayProperties(connData) { + $("#RTPropertiesView").append(connData.propertiesContainer); + } + + /** + * @param conn the jsPlumb connection + */ + function showRTViewOnTheRight(conn) { + currentlySelectedConn = conn; + + $("#RTPropertiesView").fadeIn(); + + $("#relationshiptemplateid").val(winery.connections[conn.id].id); + $("#relationshiptemplatename").editable('setValue', winery.connections[conn.id].name); + fillReqOrCap(conn, "req", conn.sourceId, "requirementsContainer", $("#RTreq")); + fillReqOrCap(conn, "cap", conn.targetId, "capabilitiesContainer", $("#RTcap")); + fillType(winery.connections[conn.id].nsAndLocalName); + displayProperties(winery.connections[conn.id]); + } + + function hideRTViewOnTheRight() { + if (currentlySelectedConn == null) { + // nothing to do if no relationship template is selected + return; + } + + $("#RTPropertiesView").fadeOut(); + + // user will see some flickering here, but we don't want to set timers -> could lead to race conditions + $("#skelettonContainerForRelationshipTemplates").append(winery.connections[currentlySelectedConn.id].propertiesContainer); + currentlySelectedConn = null; + } + + function storeUpdatedName(newName) { + currentlySelectedConn.name = newName; + } + + $(function() { + $("#relationshiptemplatename").editable({ + success: function(response, newValue) { + currentlySelectedConn.name = newValue; + } + }); + }); + + function unselectAllConnections() { + jsPlumb.select().each(function(connection) { + connection.removeType("selected"); + }); + } + + winery.events.register( + winery.events.name.SELECTION_CHANGED, + function() { + var nodeTemplate = $("div.NodeTemplateShape.selected"); + var numSelected = nodeTemplate.length; + if (numSelected != 0) { + // if node templates are selected, no RT properties should be shown + hideRTViewOnTheRight(); + + unselectAllConnections(); + } + } + ); + +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/web.xml b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..37b6dc9 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +--> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + id="winery-topologymodeler" + version="3.0"> + <display-name>Winery Topology Modeler</display-name> +</web-app> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/palette.css b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/palette.css new file mode 100644 index 0000000..e67a715 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/palette.css @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ + +#palette { + min-height: 180px; + background: rgb(248, 248, 248); + width: 230px; + box-shadow: 2px 2px 7px rgb(156, 156, 156); + padding: 10px; + border: 1px solid #aeaeae; + position: fixed; + top: 50px; + left: 0px; + z-index: 100; + cursor: default; + border-radius: 0px 9px 9px 0px; + background-image: -ms-linear-gradient(left, #FFFFFF 0%, rgb(237, 242, 247) 100%); + background-image: -moz-linear-gradient(left, #FFFFFF 0%, rgb(237, 242, 247) 100%); + background-image: -o-linear-gradient(left, #FFFFFF 0%, rgb(237, 242, 247) 100%); + background-image: -webkit-gradient(linear, left, right, color-stop(0, #FFFFFF), color-stop(1, rgb(237, 242, 247))); + background-image: -webkit-linear-gradient(left, #FFFFFF 0%, rgb(237, 242, 247) 100%); + background-image: linear-gradient(to right, #FFFFFF 0%, rgb(237, 242, 247) 100%); + + overflow-x: hidden; + overflow-y: visible; + max-height: 90%; + + /* fix for bootstrap.css, which sets that to "border-box" */ + box-sizing: content-box; + -webkit-box-sizing: content-box; +} + +#palette.shrunk { + width: 35px; + padding: 0px; + padding-left: 9px; +} + +#paletteLabel { + width: 0px; + background-color: blue; + top: 95px; + position: relative; + transform: rotate(270deg); + -o-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -webkit-transform: rotate(270deg); + display: none; + left: 8px; + font-size: 12px; + color: rgb(143, 151, 170); +} + +div.iconContainer { + width: 45px; + margin-left: 5px; + float: left; + height: 20px; + margin-top: 4px; +} + + +div.paletteEntry { + height: 28px; + border-bottom: 1px solid rgb(200, 214, 228); + margin: 0px; + float: left; + width: 230px; +} + +div.paletteEntry:hover { + background: rgb(237, 242, 247); +} + + +div.paletteEntry > div.iconContainer > img.icon { + height: 20px; + vertical-align: top; +} + + +div.paletteEntry > div.typeContainer { + margin: 4px 0px; + height: 20px; + display: table; + width: 180px; + font-size: 11px; + line-height: 20px; +} + +div.paletteEntry > div.typeContainer > div.typeContainerMiddle { + display: table-cell; + vertical-align: middle; + width: 100%; + position: static; +} + +div.paletteEntry > div.typeContainer > div.typeContainerMiddle > div.typeContainerInner { +} + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/propertiesview.css b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/propertiesview.css new file mode 100644 index 0000000..3ff0d3b --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/propertiesview.css @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ + +div.propertiesView { + width: 200px; + position: fixed; + top: 57px; + right: -1px; + background: #eaeaea; + z-index: 600; + background-image: linear-gradient(to left, #FFFFFF 0%, rgb(237, 243, 247) 100%); + border-radius: 9px 0px 0px 9px; + border: 1px solid #aeaeae; + padding: 14px; + box-shadow: -1px 2px 7px rgb(156, 156, 156); + font-size: 80%; +} + +#propertiesSection { + padding: 10px; +} + +#propertiesSection div.content { + background: rgb(244, 247, 250); +} + +#daSection { + background: #eaeaea; + padding: 10px; +} + +#daSection div.content { + background: rgb(244, 247, 250); +} + +#nodeTemplateInformationSection > div.control-group > label.control-label { + width: 37px; +} + +#nodeTemplateInformationSection > div.control-group > input { + width: 100px; +} + + +/* relationship templates only; adapted from topologytemplatecontent.css */ + +#RTPropertiesView > div.propertiesContainer > div.header { + font-weight: bold +} + +#RTPropertiesView > div.propertiesContainer > div.header > a { + float: right; + height: 6px; +} + +#RTPropertiesView > div.propertiesContainer > div.content > span.namespace { + display: none; +} + +#RTPropertiesView > div.propertiesContainer > div.content > span.elementName { + display: none; +} + +#RTPropertiesView > div.propertiesContainer > div.content table { + float: left; +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/topologymodeler.css b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/topologymodeler.css new file mode 100644 index 0000000..18f83ea --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/topologymodeler.css @@ -0,0 +1,286 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ + +/* used if elements should be hidden forever. Cannot be undone with $(...).show() */ +.hidden { + display: none; +} + +.fileupload { + display: none; +} + +.overflowhidden { + overflow: hidden; + text-overflow: ellipsis; +} + + +body { + background-color: white; + margin: 0px; +} + +#loading { + position: absolute; + top: 0px; + left: 0px; + height: 100%; + width: 100%; z-index: 200; + background-color: white; + z-index: 2000; +} + +#topbar { + padding: 5px; + width: 100%; + position: fixed; + top: 0px; + z-index: 600; + background-color: white; +} + +/* override jquery-ui.css */ +.ui-widget { + font-size: 1.0em; + font-family: Arial, Helvetica, sans-serif; +} + +a:hover { + color:#1b911b; + background-color:#f0f0f0; +} + +#drawingarea { + height: 80em; + position: relative; +} + +#drawingarea.editview { + background: rgb(240, 246, 255); + background-image: -ms-linear-gradient(top, #FFFFFF 0%, rgb(243, 243, 243) 100%); + background-image: -moz-linear-gradient(top, #FFFFFF 0%, rgb(243, 243, 243) 100%); + background-image: -o-linear-gradient(top, #FFFFFF 0%, rgb(243, 243, 243) 100%); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #FFFFFF), color-stop(1, rgb(243, 243, 243))); + background-image: -webkit-linear-gradient(top, #FFFFFF 0%, rgb(243, 243, 243) 100%); + background-image: linear-gradient(to bottom, #FFFFFF 0%, rgb(243, 243, 243) 100%); +} + +#drawingarea.printview { +} + +/* currently not used */ +div.focusedElement { + border: 3px dotted rgb(0, 152, 255); + + /* IE10 Consumer Preview */ + background-image: -ms-linear-gradient(top, #FFFFFF 0%, rgb(153, 243, 255) 100%); + + /* Mozilla Firefox */ + background-image: -moz-linear-gradient(top, #FFFFFF 0%, rgb(153, 243, 255) 100%); + + /* Opera */ + background-image: -o-linear-gradient(top, #FFFFFF 0%, rgb(153, 243, 255) 100%); + + /* Webkit (Safari/Chrome 10) */ + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #FFFFFF), color-stop(1, rgb(153, 243, 255))); + + /* Webkit (Chrome 11+) */ + background-image: -webkit-linear-gradient(top, #FFFFFF 0%, rgb(153, 243, 255) 100%); + + /* W3C Markup, IE10 Release Preview */ + background-image: linear-gradient(to bottom, #FFFFFF 0%, rgb(153, 243, 255) 100%); +} + + +div.NodeTemplateShape.selected { + background: rgb(216, 238, 255); + border: 2px solid rgb(255, 127, 26); + + + /* IE10 Consumer Preview */ + background-image: -ms-linear-gradient(top, #FFFFFF 0%, #FFD391 100%); + + /* Mozilla Firefox */ + background-image: -moz-linear-gradient(top, #FFFFFF 0%, #FFD391 100%); + + /* Opera */ + background-image: -o-linear-gradient(top, #FFFFFF 0%, #FFD391 100%); + + /* Webkit (Safari/Chrome 10) */ + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #FFFFFF), color-stop(1, #FFD391)); + + /* Webkit (Chrome 11+) */ + background-image: -webkit-linear-gradient(top, #FFFFFF 0%, #FFD391 100%); + + /* W3C Markup, IE10 Release Preview */ + background-image: linear-gradient(to bottom, #FFFFFF 0%, #FFD391 100%); +} + +div.content { + overflow: hidden; + width: 100%; +} + +.renderMode.ui-draggable { + display:none; +} + +div.menu { + display:none; +} + +._jsPlumb_overlay { + z-index: 5000; +} + +/* overriding dimensions.css to overcome problems with non-standard fonts and breaking cells */ +.u-size3of5, +.u-size6of10 { + width: 59%; +} +.u-size4of5 { + width: 79%; +} + +.breakword { + overflow-wrap: break-word; +} + +a.topbutton { + margin-right: 10px; +} + +#selectionbox { + position: absolute; + border-style: dashed; + border-width: 3px; + border-color: black; + background-color: cyan; + opacity: 0.15; + z-index: 30; + display: none; +} + +#editorArea { + width: 100%; + height: 100%; + margin-top: 45px; +} + +#nodeTemplateInformationSection > label { + display: inline-block; + width: 47px; +} + +.form-horizontal .controls > span { + margin-top: 5px; + display: inline-block; +} + +/* reset editable style */ +.editable-click { + border-bottom: none; +} + +a.editable-click { + border-bottom: none; +} + +a.editable-click:hover { + border-bottom: none; +} + + +/* adding a req/cap */ + +div.modal-body > form.addReqForm > div.propertiesContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.modal-body > form.addReqForm > div.propertiesContainer > div.header { + background: rgb(241, 241, 241); + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; +} + +div.modal-body > form.addReqForm > div.propertiesContainer > div.header > a { + float: right; + height: 6px; +} + +div.modal-body > form.addReqForm > div.propertiesContainer > div.content > span.namespace { + display: none; +} + +div.modal-body > form.addReqForm > div.propertiesContainer > div.content > span.elementName { + display: none; +} + +div.modal-body > form.addReqForm > div.propertiesContainer > div.content table { + float: left; +} + +div.modal-body > form.addCapForm > div.propertiesContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.modal-body > form.addCapForm > div.propertiesContainer > div.header { + background: rgb(241, 241, 241); + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; +} + +div.modal-body > form.addCapForm > div.propertiesContainer > div.header > a { + float: right; + height: 6px; +} + +div.modal-body > form.addCapForm > div.propertiesContainer > div.content > span.namespace { + display: none; +} + +div.modal-body > form.addCapForm > div.propertiesContainer > div.content > span.elementName { + display: none; +} + +div.modal-body > form.addCapForm > div.propertiesContainer > div.content table { + float: left; +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/topologytemplatecontent.css b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/topologytemplatecontent.css new file mode 100644 index 0000000..0c7eea4 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/topologytemplatecontent.css @@ -0,0 +1,421 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + *******************************************************************************/ + +/** This CSS is shared between the Winery Repository and the Winery Topology Modeler **/ + +div.NodeTemplateShape { + font-family: arial, verdana; + font-size: 12px; + + border: 1px solid black; + border: 2px solid rgb(112, 152, 179); + border-radius: 12px; + width: 225px; + z-index:20; + position:absolute; + box-shadow: 5px 5px 17px #aaa; + background: #ffffff; + cursor: move; + + /* IE10 Consumer Preview */ + background-image: -ms-linear-gradient(top, #FFFFFF 0%, #EBF2F7 100%); + + /* Mozilla Firefox */ + background-image: -moz-linear-gradient(top, #FFFFFF 0%, #EBF2F7 100%); + + /* Opera */ + background-image: -o-linear-gradient(top, #FFFFFF 0%, #EBF2F7 100%); + + /* Webkit (Safari/Chrome 10) */ + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #FFFFFF), color-stop(1, #EBF2F7)); + + /* Webkit (Chrome 11+) */ + background-image: -webkit-linear-gradient(top, #FFFFFF 0%, #EBF2F7 100%); + + /* W3C Markup, IE10 Release Preview */ + background-image: linear-gradient(to bottom, #FFFFFF 0%, #EBF2F7 100%); +} + +div.NodeTemplateShape > div.headerContainer { + height: 65px; +} + +div.NodeTemplateShape div.minMaxInstances { +} + +div.NodeTemplateShape div.minMaxInstances span.minInstances { + +} + +div.NodeTemplateShape div.minMaxInstances span.maxInstances { + +} + +div.NodeTemplateShape > .headerContainer > img.icon { + float: left; + height: 55px; + margin: 10px 0px 10px 10px; +} +div.NodeTemplateShape > .headerContainer > div.id { + position: absolute; + left: 90px; + top: 0px; + height: 16px; + width: 130px; + text-overflow: ellipsis; + overflow: hidden; + text-decoration: underline; + display: none; +} +div.NodeTemplateShape > .headerContainer > div.name { + position: absolute; + left: 90px; + top: 20px; + height: 16px; + width: 130px; + text-overflow: ellipsis; + overflow: hidden; +} +div.NodeTemplateShape > .headerContainer > div.type { + position: absolute; + left: 90px; + top: 40px; + height: 16px; + width: 130px; + text-overflow: ellipsis; + overflow: hidden; +} +div.NodeTemplateShape > .headerContainer > div.type:before { + content: "("; +} +div.NodeTemplateShape > .headerContainer > div.type:after { + content: ")"; +} + +img.createAnnotation { + width: 20px; + position: absolute; + top: 5px; + right: 5px; +} + +a.KVPropertyValue { + overflow: hidden; + text-overflow: ellipsis; +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.header { + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; + background-image: -ms-linear-gradient(top, #FFFFFF 0%, rgb(209, 209, 209) 100%); + background-image: -moz-linear-gradient(top, #FFFFFF 0%, rgb(209, 209, 209) 100%); + background-image: -o-linear-gradient(top, #FFFFFF 0%, rgb(209, 209, 209) 100%); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #FFFFFF), color-stop(1, rgb(209, 209, 209))); + background-image: -webkit-linear-gradient(top, #FFFFFF 0%, rgb(209, 209, 209) 100%); + background-image: linear-gradient(to bottom, #FFFFFF 0%, rgb(209, 209, 209) 100%); +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.content > div.deploymentArtifact { + background-color: #FFDADA; + height: 20px; +} + +/* indicates editing possibility */ +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.content > div.deploymentArtifact:hover { + background-color: lightblue; + cursor: pointer; +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.content > div.deploymentArtifact > div { + height: 20px; +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.content > div.deploymentArtifact:first-child { + border-top: 0px; +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.content > div.addDA { + display: none; +} + +div.NodeTemplateShape > div.deploymentArtifactsContainer > div.content > div.addnewartifacttemplate { + display: none; + background-color: Silver; + text-align: center; +} + +div.NodeTemplateShape > div.propertiesContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.NodeTemplateShape > div.propertiesContainer > div.header { + background: rgb(241, 241, 241); + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; +} + +div.NodeTemplateShape > div.propertiesContainer > div.header > a { + float: right; + height: 6px; +} + +div.NodeTemplateShape > div.propertiesContainer > div.content > span.namespace { + display: none; +} + +div.NodeTemplateShape > div.propertiesContainer > div.content > span.elementName { + display: none; +} + +div.NodeTemplateShape > div.propertiesContainer > div.content table { + float: left; +} + +div.NodeTemplateShape div.reqorcap { + cursor: pointer; +} + +div.NodeTemplateShape div.reqorcap.id { +} + +div.NodeTemplateShape div.reqorcap.name { + overflow: hidden; + text-overflow: ellipsis; +} + +div.NodeTemplateShape div.reqorcap.type { + overflow: hidden; + text-overflow: ellipsis; +} + +/* indicates editing possibility */ +div.NodeTemplateShape div.reqorcap:hover { + background-color: lightgray; +} + +div.NodeTemplateShape > div.requirementsContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.NodeTemplateShape > div.requirementsContainer > div.header { + background: rgb(241, 241, 241); + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; +} + +div.NodeTemplateShape > div.requirementsContainer > div.content > div.reqorcap > div.propertiesContainer { + display: none; +} + + +div.NodeTemplateShape > div.capabilitiesContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.NodeTemplateShape > div.capabilitiesContainer > div.header { + background: rgb(241, 241, 241); + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; +} + +div.NodeTemplateShape > div.capabilitiesContainer > div.content > div.reqorcap > div.propertiesContainer { + display: none; +} + + +/** Policies **/ + +div.NodeTemplateShape > div.policiesContainer { + border: 1px solid #aeaeae; + background: #ffffff; + margin: 7px; + width: 198px; + border-radius: 7px; + padding: 5px; + float: left; + overflow-x: hidden; + display: none; +} + +div.NodeTemplateShape > div.policiesContainer > div.header { + background: rgb(241, 241, 241); + border-bottom: 1px solid #aeaeae; + float: left; + width: 198px; + padding: 5px; + margin-top: -5px; + margin-left: -5px; + margin-bottom: 6px; +} + +/* indicates editing possibility */ +div.NodeTemplateShape > div.policiesContainer > div.content > div.policy:hover { + background-color: lightgray; +} + +div.NodeTemplateShape > div.policiesContainer > div.content > div.policy > div { + overflow: hidden; + text-overflow: ellipsis; +} + +div.NodeTemplateShape > div.policiesContainer > div.content > div.policy > span { + display: none; +} + +div.NodeTemplateShape > div.policiesContainer > div.content > div.policy > textarea.policy_xml { + display: none; +} + + + +div.connectorBox { + height: 15px; + width: 15px; + float: left; +} + +div.connectorLabel { + height: 15px; + width: 125px; + overflow: hidden; + margin-left: 20px; + white-space: nowrap; + line-height: 16px; + overflow: hidden; + text-overflow: ellipsis; +} + +div.connectorEndpoint { + width: 140px; + cursor: pointer; +} + +div.connectorEndpoint:hover { + background: rgb(237, 242, 247); +} + +div.endpointContainer { + background: #ffffff; + box-shadow: 2px 2px 19px #aaa; + border: 1px solid #aeaeae; + width: 150px; + position: absolute; + left: 212px; + padding: 5px; + z-index: 20; + display: none; +} + +._jsPlumb_connector { + z-index: 15; +} + +div#patternArea { + position: absolute; + z-index: 10000; + right: 0px; + top: 0px; + height: 100%; + width: 500px; + background: rgb(250, 250, 250); + padding: 5px; +} + +div.patternSuggestionContainer { + border: 2px solid #aeaeae; + padding: 5px 3px; + margin-bottom: 5px; +} + +div.patternSuggestionContainer.focusedElement { + +} + +.pointer { + cursor: pointer; +} + +div.relationshipTypeLabel { + /* z-index of arrow is 14, therefore we use 15 */ + z-index: 15; + + cursor: default; + font-family: arial, verdana; + font-size: 12px; +} + +.unselectable { + /* disable text selection - source: http://stackoverflow.com/a/4407335/873282 */ + user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -webkit-touch-callout: none; + -webkit-user-select: none; +} diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/winery-common.css b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/winery-common.css new file mode 100644 index 0000000..b6d2251 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/css/winery-common.css @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - improvements + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ + +/** This CSS is shared between the Winery Repository and the Winery Topology Modeler **/ + +.informationbox { + position: absolute; + text-align: center; + top: 0; + left: 0; + width: 100%; + height: 0; + z-index: 99; +} + +.informationbox > .alert { + background: #fff1a8; + border: 1px solid #999; + border-top: 0; + border-radius: 0 0 3px 3px; + display: inline-block; + line-height: 21px; + padding: 0 12px; +} + +/* when hovering over the text, the cursor should stay as is */ +.ui-pnotify { + cursor: default; +} + +/* change pnotify's container to be always at the top of the window */ +div.ui-pnotify-history-container { + position: fixed; +} + +/* enable pnotify notifications to wrap correctly */ +.ui-pnotify-text { + overflow: hidden; + overflow-wrap: break-word; +} + +.button { + cursor: pointer; +} + +td.editable { + cursor: text; +} + +td { + cursor: default; +} + +.input-xxlarge { + width: 510px; +} + +.spinner { + text-align: right; +} + +/* enables stacked modal dialogs */ +div.z1051 { + z-index: 1051; +} + +/* used for showing the full notification at PNotify */ +div.z1060 { + z-index: 1060; +} + + +/* fixes bootstrap margin problem at horizontal form */ +.form-horizontal > div.control-group > label.control-label { + margin-right: 10px; +} + +/* used by artifactcreationdialog.tag */ +div.unknown { + color: gray; +} + +div.unknown:before { + content: '?'; +} + +div.invalid { + color: red; +} + +div#artifactTemplateNameIsValid { + height: 19px; +} + +div.valid { + color: green; +} + +#diagmessagemsg { + text-overflow: ellipsis; + overflow: hidden; +} + +textarea.properties_xml { + display: none +} + +/** properties **/ + +span.properties_element { + display: none; +} + +span.properties_type { + display: none +} + +div.form-group-grouping { + background: #F0F0F0; + padding: 15px; + margin-top: 10px; + margin-bottom: 10px; +} + +div.orionxmleditordiv { + height: 300px; +}
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/favicon.png b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/favicon.png Binary files differnew file mode 100644 index 0000000..25484fe --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/favicon.png diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/images/xml.png b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/images/xml.png Binary files differnew file mode 100644 index 0000000..eb46323 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/images/xml.png diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp new file mode 100644 index 0000000..2a582ba --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp @@ -0,0 +1,1490 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - integration with the repository, adapted to TOSCA v1.0 + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> + +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@page buffer="none" %> +<%@page import="java.util.Collection"%> +<%@page import="java.util.List"%> +<%@page import="java.util.LinkedList"%> +<%@page import="java.util.Map"%> +<%@page import="java.util.SortedSet"%> +<%@page import="javax.xml.namespace.QName"%> +<%@page import="org.apache.commons.lang3.StringUtils"%> +<%@page import="org.eclipse.winery.model.tosca.TArtifactTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TArtifactType"%> +<%@page import="org.eclipse.winery.model.tosca.TCapability"%> +<%@page import="org.eclipse.winery.model.tosca.TCapabilityType"%> +<%@page import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TTopologyTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TNodeType"%> +<%@page import="org.eclipse.winery.model.tosca.TPolicyType"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipTemplate.TargetElement"%> +<%@page import="org.eclipse.winery.model.tosca.TRequirement"%> +<%@page import="org.eclipse.winery.model.tosca.TRequirementType"%> +<%@page import="org.eclipse.winery.common.constants.Namespaces" %> +<%@page import="org.eclipse.winery.common.ids.definitions.ArtifactTemplateId"%> +<%@page import="org.eclipse.winery.common.ids.definitions.ServiceTemplateId" %> +<%@page import="org.eclipse.winery.common.interfaces.QNameWithName"%> +<%@page import="org.eclipse.winery.common.constants.QNames" %> +<%@page import="org.eclipse.winery.common.ModelUtilities"%> +<%@page import="org.eclipse.winery.common.Util"%> +<%@page import="org.eclipse.winery.repository.client.WineryRepositoryClientFactory"%> +<%@page import="org.eclipse.winery.repository.client.IWineryRepositoryClient"%> +<%@page import="org.eclipse.winery.repository.client.WineryRepositoryClient"%> +<%@page import="org.eclipse.winery.topologymodeler.WineryUtil"%> +<%@page import="com.sun.jersey.api.client.WebResource"%> +<%@page import="com.sun.jersey.api.client.Client"%> +<%@page import="com.sun.jersey.api.client.ClientResponse"%> +<%@page import="com.sun.jersey.api.client.config.ClientConfig"%> +<%@page import="com.sun.jersey.api.client.config.DefaultClientConfig"%> + +<%-- nc.. = non-common .. --%> +<%@taglib prefix="ncnt" tagdir="/WEB-INF/tags/templates/nodetemplates" %> +<%@taglib prefix="ncrt" tagdir="/WEB-INF/tags/templates/relationshiptemplates" %> +<%@taglib prefix="tntrq" tagdir="/WEB-INF/tags/templates/nodetemplates/reqscaps" %> + +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> +<%@taglib prefix="tmpl" tagdir="/WEB-INF/tags/common/templates" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> +<%@taglib prefix="ntrq" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="pol" tagdir="/WEB-INF/tags/common/policies" %> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> + +<%@taglib prefix="tc" tagdir="/WEB-INF/tags/common/topologycompletion"%> + +<% + String repositoryURL = request.getParameter("repositoryURL"); + if (StringUtils.isEmpty(repositoryURL)) { + repositoryURL = "http://localhost:8080/winery"; + } else if (repositoryURL.endsWith("/")) { + repositoryURL = repositoryURL.substring(0, repositoryURL.length()-1); + } + + String ns = request.getParameter("ns"); + if (StringUtils.isEmpty(ns)) { +%> + A namespace has to be provided by using the query parameter “ns.” Please start the modeler using the <a href="<%=repositoryURL%>">repository</a>. +<% + return; + } + + String id = request.getParameter("id"); + if (StringUtils.isEmpty(id)) { +%> + An id has to be provided by using the query parameter “id.” Please start the modeler using the <a href="<%=repositoryURL%>">repository</a>. +<% + return; + } + + // initialize client dependend on useproxy URL parameter + IWineryRepositoryClient client; + if (request.getParameterMap().containsKey("useproxy")) { + // debugging - using fiddler: + client = new WineryRepositoryClient(true); + System.out.println("Using a proxy..."); + } else { + // production: + client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + } + + client.addRepository(repositoryURL); + + if (!client.primaryRepositoryAvailable()) { +%> + The repository is not available. +<% + return; + } + + QName serviceTemplateQName = new QName(ns, id); + TTopologyTemplate topologyTemplate = client.getTopologyTemplate(serviceTemplateQName); + if (topologyTemplate == null) { +%> + Something went wrong in the repository: topology template not found. +<% + return; + } + + String topologyTemplateURL = repositoryURL + "/servicetemplates/" + Util.DoubleURLencode(serviceTemplateQName) + "/topologytemplate/"; + + String serviceTemplateName = client.getName(new ServiceTemplateId(serviceTemplateQName)); + + Collection<TRelationshipType> relationshipTypes = client.getAllTypes(TRelationshipType.class); +%> +<!DOCTYPE html> +<html> +<head> + <title>Winery Topologymodeler – <%= serviceTemplateName %></title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + + <link rel="icon" href="favicon.png" type="image/png"> + + <link rel="stylesheet" href="components/bootstrap/dist/css/bootstrap.css" /> + <link rel="stylesheet" href="components/bootstrap/dist/css/bootstrap-theme.css" /> + <link rel="stylesheet" href="components/bootstrap-spinedit/css/bootstrap-spinedit.css" /> + + <link rel="stylesheet" href="components/blueimp-file-upload/css/jquery.fileupload.css" /> + <link rel="stylesheet" href="components/blueimp-file-upload/css/jquery.fileupload-ui.css" /> + + <link type="text/css" href="components/pnotify/jquery.pnotify.default.css" media="all" rel="stylesheet" /> + <link type="text/css" href="components/pnotify/jquery.pnotify.default.icons.css" media="all" rel="stylesheet" /> + + <!-- select2 --> + <link type="text/css" href="components/select2/select2.css" media="all" rel="stylesheet" /> + <link type="text/css" href="components/select2/select2-bootstrap.css" media="all" rel="stylesheet" /> + + <!-- x-editable --> + <link type="text/css" href="components/x-editable/dist/bootstrap3-editable/css/bootstrap-editable.css" media="all" rel="stylesheet" /> + + <link rel="stylesheet" type="text/css" href="http://eclipse.org/orion/editor/releases/6.0/built-editor.css"/> + + <!-- Winery as last: Winrey also overwrites some definitions from above --> + <link rel="stylesheet" href="css/winery-common.css" /> + <link rel="stylesheet" href="css/topologytemplatecontent.css" /> + <link rel="stylesheet" href="css/topologymodeler.css" /> +</head> + +<body data-demo-id="drawingarea" data-library="jquery"> + +<div id="loading">loading...</div> + +<script type='text/javascript' src='${pageContext.request.contextPath}/components/requirejs/require.js'></script> +<script> + require.config({ + baseUrl: "${pageContext.request.contextPath}/js", + paths: { + "datatables": "../components/datatables/media/js/jquery.dataTables", + "jquery": "../components/jquery/jquery", + + "jquery.fileupload": "../components/blueimp-file-upload/js/jquery.fileupload", + "jquery.fileupload-ui": "../components/blueimp-file-upload/js/jquery.fileupload-ui", + "jquery.fileupload-process": "../components/blueimp-file-upload/js/jquery.fileupload-process", + "jquery.ui.widget": "../components/blueimp-file-upload/js/vendor/jquery.ui.widget", + + // required for jsplumb + "jquery.ui": "../3rdparty/jquery-ui/js/jquery-ui", + + "jsplumb": "../components/jsPlumb/dist/js/jquery.jsPlumb-1.5.4", + + "keyboardjs": "../components/KeyboardJS/keyboard", + "orioneditor": "http://eclipse.org/orion/editor/releases/6.0/built-editor-amd", + "pnotify": "../components/pnotify/jquery.pnotify", + "select2": "../components/select2/select2", + "tmpl": "../components/blueimp-tmpl/js/tmpl", + "XMLWriter": "../components/XMLWriter/XMLWriter" + } + }); +</script> + +<script type='text/javascript' src='components/jquery/jquery.js'></script> + +<script type='text/javascript' src='3rdparty/jquery-ui/js/jquery-ui.js'></script> + +<script type='text/javascript' src='components/bootstrap/dist/js/bootstrap.js'></script> + +<script type='text/javascript' src='components/bootstrap-spinedit/js/bootstrap-spinedit.js'></script> + +<!-- udpate of jquery widget by jQuery-File-Upload, which requires jQuery UI 1.9 at least --> +<!-- <script type="text/javascript" src="components/jQuery-File-Upload/js/vendor/jquery.ui.widget.js"></script> --> + +<script type='text/javascript' src='components/jsPlumb/dist/js/jquery.jsPlumb-1.5.4.js'></script> + +<script type="text/javascript" src="components/jquery-typing/plugin/jquery.typing-0.3.2.js"></script> + +<script type="text/javascript" src="components/select2/select2.js"></script> + +<script type="text/javascript" src="components/x-editable/dist/bootstrap3-editable/js/bootstrap-editable.js"></script> + +<script type="text/javascript" src="js/winery-common.js"></script> +<script type="text/javascript" src="js/winery-topologymodeler.js"></script> + +<jsp:include page="/jsp/shared/dialogs.jsp" /> + +<% + // only required for generating the CSS for each node type + Collection<TNodeType> allNodeTypes = client.getAllTypes(TNodeType.class); +%> + +<tmpl:CSSForTypes nodeTypes="<%=allNodeTypes%>" relationshipTypes="<%=relationshipTypes%>"/> + +<tmpl:propertiesBasic /> + +<t:about /> + +<script> +// global variable hodling data for relationship templates +if (!winery) winery = {}; + +// winery.connections is a hashmap from jsPlumb id to a data structure with +// .id = winery id; // The two ids DO NOT match. Explanation is at winery-common-topologyrendering.js +// ... +winery.connections = {}; + +// all x-editable popups should be placed in a way to fit "perfectly" on the screen +$.fn.editable.defaults.placement = "auto"; + +//configuration for pnotify +require(["jquery", "pnotify"], function() { + $.pnotify.defaults.styling = "bootstrap3"; +}); +</script> + +<%-- Begin: Add&Edit Req/Cap --%> + +<%List<QName> allTypes = client.getQNameListOfAllTypes(TRequirementType.class);%> +<tntrq:addorupdatereqorcap requirementOrCapability="requirement" shortName="Req" cssClassPrefix="requirements" headerLabel="Requirement" allTypes="<%=allTypes%>" clazz="<%=TRequirement.class%>" repositoryURL="<%=repositoryURL%>" /> + +<%allTypes = client.getQNameListOfAllTypes(TCapabilityType.class);%> +<tntrq:addorupdatereqorcap requirementOrCapability="capability" shortName="Cap" cssClassPrefix="capabilities" headerLabel="Capability" allTypes="<%=allTypes%>" clazz="<%=TCapability.class%>" repositoryURL="<%=repositoryURL%>" /> + +<%-- End: Add&Edit Req/Cap --%> + +<%allTypes = client.getQNameListOfAllTypes(TPolicyType.class);%> +<pol:policydiag allPolicyTypes="<%=allTypes%>" repositoryURL="<%=repositoryURL%>" /> + +<script> +"use strict"; + +// for debugging +//$.pnotify.defaults.remove = false; + +// global data structure +// .repositoryURL - the URL of the repository +// DOES NOT end with / +winery.repositoryURL = "<%=repositoryURL%>"; + +</script> + +<script> +/** + * Uses global variables currentlySelectedNodeTemplate and currentlySelectedDeploymentArtifactDiv + * + * @param atDelete (optional). Function to be called if the DA has been successfully deleted + */ +function askForDeploymentArtifactDeletion(atDelete) { + // we have to remove it on both the node template locally and on the server + // reason: if the user does NOT save after deletion, the repository would present him + // the DA again. Possibly with a dangeling reference to the artifact template, + // which might have been deleted if this DA was the last reference to it + + var daName = currentlySelectedDeploymentArtifactDiv.children("div.name").text(); + var url = "<%=topologyTemplateURL%>nodetemplates/" + encodeID(currentlySelectedNodeTemplate) + "/deploymentartifacts/" + daName; + deleteResource("this deployment artifact", url, function() { + currentlySelectedDeploymentArtifactDiv.remove(); + $("#DeploymentArtifactInfo").modal("hide"); + if (atDelete) { + atDelete(); + } + }); +} + +/** + * Queries the user for deletion of the currently selected DA. + * If the associated artifact template points to the current DA only, he is also ask if he wants to delete that template, too. + */ +function deleteDeploymentArtifact() { + var templateURL = $("#DAArtifactTemplate").attr("href"); + // an artifact template exists + // we have to ask the user if the wants to delete is as well + // IF this deployment artifact is the only reference to it + // The user has to be first asked for DA deletion and then for artifact template deletion + // Therefore, we pass a function to be executed AFTER deletion of the deployment artifact. + if (templateURL) { + // check for count + $.ajax({ + type: "GET", + async: false, + url: templateURL + "?referenceCount", + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not get count of artifact template usage", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + if (resData == "1") { + var atDelete = function() { + deleteResource("the associated artifact template", templateURL, function() {}); + }; + askForDeploymentArtifactDeletion(atDelete); + } else { + // more than one reference to the artifact template + // just ask for deletion of the DA and not of the AT + askForDeploymentArtifactDeletion(); + } + } + }); + } else { + askForDeploymentArtifactDeletion(); + } +} + +/** + * The user might have updated the XML information + * This has to be copied into the "storage" of the currently selected node template + * + * Uses global variable currentlySelectedDeploymentArtifactDiv + */ +function updateDeploymentArtifact() { + require(["winery-support-common"], function(wsc) { + var newVal = $("#DAXML").val(); + if (wsc.checkXMLValidityAndShowErrorIfInvalid(newVal)) { + currentlySelectedDeploymentArtifactDiv.children("textarea").val(newVal); + $("#DeploymentArtifactInfo").modal("hide"); + } + }); +} +</script> +<div class="modal fade" id="DeploymentArtifactInfo"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Artifact Information</h4> + </div> + <div class="modal-body"> + <form><fieldset> + <div class="form-group"> + <label for="DADname" class="control-label">Name</label> + <div id="DAname" class="form-control"></div> + </div> + + <div class="form-group"> + <label for="DAArtifactType" class="control-label">Artifact Type</label> + <a id="DAArtifactType" class="form-control" target="_blank"></a> + </div> + <div class="form-group"> + <label for="DAArtifactTemplate" class="control-label">Artifact Template</label> + <a id="DAArtifactTemplate" class="form-control" target="_blank"></a> + </div> + <div class="form-group"> + <label for=DAXML" class="control-label">XML</label> + <textarea id="DAXML" cols=50 rows=7 class="form-control"></textarea> + </div> + </fieldset></form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-danger" onclick="deleteDeploymentArtifact();">Delete</button> + <button type="button" class="btn btn-primary" onclick="updateDeploymentArtifact();">Ok</button> + </div> + </div> + </div> +</div> + +<!-- BEGIN TOPOLOGY COMPLETION --> +<tc:selectionDialogs repositoryURL='<%=repositoryURL%>' serviceTemplateName='<%=serviceTemplateName%>' topologyTemplateURL='<%=topologyTemplateURL%>'/> +<!-- END TOPOLOGY COMPLETION --> + +<ct:artifactcreationdialog + URL="getURLForDeploymanetArtifactGeneration()" + repositoryURL="<%=repositoryURL%>" + name="Deployment" + onSuccessfulArtifactCreationFunction="artifactAddedSuccessfully" + allNamespaces="<%=client.getNamespaces()%>" + isDeploymentArtifact="true" + allArtifactTypes="<%=client.getQNameListOfAllTypes(TArtifactType.class)%>" + defaultNSForArtifactTemplate="<%=ns%>" + > +</ct:artifactcreationdialog> + +<script> +function getURLForDeploymanetArtifactGeneration() { + return "<%=topologyTemplateURL%>nodetemplates/" + encodeID(currentlySelectedNodeTemplate) + "/deploymentartifacts/" +} +</script> + +<% +// we want to display the name of the artifact template, not the id +Collection<QNameWithName> artifactTemplateList = client.getListOfAllInstances(ArtifactTemplateId.class); +%> + +<div id="winery"> + <ncnt:propertiesOfOneNodeTemplate repositoryURL="<%=repositoryURL%>"/> + <ncrt:propertiesOfOneRelationshipTemplate relationshipTypes="<%=relationshipTypes%>" repositoryURL="<%=repositoryURL%>"/> + + <div id="topbar"> + + <button class="btn btn-success topbutton" onclick="winery.events.fire(winery.events.name.command.SAVE);" id="saveBtn" data-loading-text="Saving...">Save</button> + <div class="btn-group"> + <button class="btn btn-default" onclick="doLayout();">Layout</button> + <button class="btn btn-default" onclick="horizontalAlignment();">Align-h (|)</button> + <button class="btn btn-default" onclick="verticalAlignment();">Align-v (-)</button> + </div> + + <tmpl:toggleButtons /> + + <%-- confusing, because DELETE at this place in the management part deletes the whole entity, not just the selected one + <button class="btn btn-danger selectionOnly" onclick="winery.events.fire(winery.events.name.command.DELETE_SELECTION);">Delete</button> + --%> + + <button data-toggle="button" class="btn btn-default" onclick="togglePrintView(!$(this).hasClass('active'));">Print View</button> + + <div class="btn-group"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Other <span class="caret"></span></button> + + <ul class="dropdown-menu" role="menu"> + <li><a href="#" onclick="completeTopology();">Complete Topology</a></li> + <li><a id="exportCSARbtn" href="<%=topologyTemplateURL%>../?csar" target="_blank">Export CSAR</a></li> + <li><a href="#" onclick="showAbout();">about</a></li> + </ul> + </div> + + + <script> + $("#exportCSARbtn").tooltip({ + placement: 'bottom', + html: false, + title: "Hold CTRL key to export XML only." + }); + $("#exportCSARbtn").on("click", function(evt) { + var url = $(this).attr("href"); + if (evt.ctrlKey) { + url = url.replace(/csar$/, "definitions"); + } + window.open(url); + return false; + }); + </script> + + <script> + function togglePrintView(showPrintView) { + if (showPrintView) { + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + if (hidePalette) hidePalette(); + // showTypes(true); + $("#drawingarea").addClass("printview"); + $("#drawingarea").removeClass("editview"); + + // move labels 10 px up + // we have to do it here as jsPlumb currently paints the label on the line instead of above of it + // See https://groups.google.com/d/msg/jsplumb/zdyAdWcRta0/K6F2MrHBH1AJ + $(".relationshipTypeLabel").each(function(i, e) { + var pos = $(e).offset(); + pos.top = pos.top - 10; + $(e).offset(pos); + }); + } else { + $("#drawingarea").removeClass("printview"); + $("#drawingarea").addClass("editview"); + + // move labels 10 px down + // we have to do it here as jsPlumb currently paints the label on the line instead of above of it + $(".relationshipTypeLabel").each(function(i, e) { + var pos = $(e).offset(); + pos.top = pos.top + 10; + $(e).offset(pos); + }); + } + } + </script> + </div> + + <tmpl:defineCreateConnectorEndpointsFunction relationshipTypes="<%=relationshipTypes%>"/> + <t:palette client="<%=client%>" relationshipTypes="<%=relationshipTypes%>" repositoryURL="<%=repositoryURL%>"/> + + <div id="selectionbox"> + </div> + + <div class="unselectable" id="editorArea"> + <div id="drawingarea" class="unselectable editview"> + +<% + List<TEntityTemplate> templateList = topologyTemplate.getNodeTemplateOrRelationshipTemplate(); + List<TRelationshipTemplate> relationshipTemplates = new LinkedList<TRelationshipTemplate>(); + for (TEntityTemplate template: templateList) { + if (template instanceof TRelationshipTemplate) { + relationshipTemplates.add((TRelationshipTemplate) template); + } else { + TNodeTemplate nodeTemplate = (TNodeTemplate) template; + + // Get saved position + // x and y are stored as attributes of other namespaces + String left = ModelUtilities.getLeft(nodeTemplate); + String top = ModelUtilities.getTop(nodeTemplate); + %> + <nt:nodeTemplateRenderer client="<%=client%>" relationshipTypes="<%=relationshipTypes%>" repositoryURL="<%=repositoryURL%>" nodeTemplate="<%=nodeTemplate%>" top="<%=top%>" left="<%=left%>"/> + <% + } + } + %> + </div> + </div> + + <script> + var multiDNDmode = false; + var multiDNDdata = {}; + + $(document).on("dragstart", "div.NodeTemplateShape", function(e) { + var nodeTemplateShape = $(this); + hideNodeTemplateShapeChangeBoxes(nodeTemplateShape); + if (nodeTemplateShape.hasClass("selected")) { + var allSelectedShapes = $("div.NodeTemplateShape.selected"); + if (allSelectedShapes.length > 1) { + // console.log("start: multiDNDmode"); + multiDNDdata.x = e.clientX; + multiDNDdata.y = e.clientY; + multiDNDdata.shapes = $("div.NodeTemplateShape.selected").not("#" + e.currentTarget.id); + multiDNDmode = true; + } + } else { + // "mousedown" event handling already took care about + // deselect everything else + // select shape + } + }); +</script> +<script> + $(document).on("drag", "div.NodeTemplateShape", function(e) { + if (multiDNDmode) { + // TODO possibly, this has to be put in a queue to avoid racing events? + var dx = e.clientX - multiDNDdata.x; + var dy = e.clientY - multiDNDdata.y; + multiDNDdata.x = e.clientX; + multiDNDdata.y = e.clientY; + multiDNDdata.shapes.each(function(i, n) { + n = $(n); + var offset = n.offset(); + offset.left += dx; + offset.top += dy; + n.offset(offset); + }); + jsPlumb.repaintEverything(); + } + }); + +</script> +<script> + + function doLayout() { + var editor = $("#editorArea"); + var nodeTemplates = editor.find(".NodeTemplateShape"); + require(["winery-sugiyamaLayouter"], function(layouter) { + layouter.layout(nodeTemplates); + }); + } + +</script> +<script> + + function horizontalAlignment() { + + var counter = 0; + var aggregatedLeft = 0; + + $("div.NodeTemplateShape.selected").each(function() { + aggregatedLeft = aggregatedLeft + $(this).position().left; + counter = counter + 1; + }); + + var newLeft = aggregatedLeft / counter; + + $("div.NodeTemplateShape.selected").each(function() { + jsPlumb.animate($(this).attr("id"), { + left : newLeft + }, { + duration : 500, + easing : 'easeOutBack' + }); + }); + + } + +</script> +<script> + + function verticalAlignment() { + + var counter = 0; + var aggregatedTop = 0; + + $("div.NodeTemplateShape.selected").each(function() { + aggregatedTop = aggregatedTop + $(this).position().top; + counter = counter + 1; + }); + + var newTop = aggregatedTop / counter; + + $("div.NodeTemplateShape.selected").each(function() { + jsPlumb.animate($(this).attr("id"), { + top : newTop + }, { + duration : 500, + easing : 'easeOutBack' + }); + }); + + } + +</script> +<script> +require(["winery-topologymodeler-AMD"], function(wt) { + winery.events.register(winery.events.name.command.SAVE, wt.save); + wt.setTopologyTemplateURL("<%=topologyTemplateURL%>"); +}); +</script> +<script> + + // "mousedown" instead of "click" enables a more Visio-like behavior + $(document).on("mousedown", "div.NodeTemplateShape", function(e) { + var target = $(e.target); + + // no special handling if x-editable popover is clicked + if (target.parents().hasClass("popover")) { + return false; + } + + // no special handling if connectors are clicked + if (target.hasClass("connectorEndpoint") || target.hasClass("connectorBox") || target.hasClass("connectorLabel")) { + return false; + } + + if (target.is("a") && !target.hasClass("editable")) { + // Link clicked + // Open in new tab + // Delay opening for 300ms to disalbe a dragstart + window.setTimeout(function() { + var href = target.attr("href"); + window.open(href); + }, 300); + return false; + } + + // if the deployment artifact "buttons" are clicked, handle that functionality + // class addOrLinkDA is also present + if (target.hasClass("addDA")) { + var nodeTemplate = $(this); + hideNodeTemplateShapeChangeBoxes(nodeTemplate); + var id = nodeTemplate.attr('id'); + + // adding DAs only works for existing resources + // Reason: the POST is directed to the "deploymentartifacts" sub resource, + // which does all the artifact template autocreation magic + $.ajax({ + type: "HEAD", + async: false, + url: "<%=topologyTemplateURL%>nodetemplates/" + encodeID(id) + "/", + error: function(jqXHR, textStatus, errorThrown) { + vShowError("Node template does not exist on the server. Please save the topology before adding deployment artifacts"); + }, + success: function(resData, textStatus, jqXHR) { + // setting this global variable is required for getURLForDeploymanetArtifactGeneration(), with which the dialog has been initalized. + currentlySelectedNodeTemplate = id; + openAddDeploymentArtifactDiag(); + } + }); + + return false; + } + + if (target.is("button")) { + // "Edit XML" or "Add deployment artifact" clicked + return false; + } + + // if the custom KV properties are clicked, handle them + if (target.hasClass("KVPropertyValue")) { + return false; + } + // OK or Cancel clicked at editable + if ((target.hasClass("icon-ok")) || (target.hasClass("icon-remove"))) { + return false; + } + + if (target.hasClass("reqorcap")) { + var reqOrCapId = undefined; // set to undefined to avoid compiler warnings + // check if req or cap should be edited + var parentReqOrCapDiv = undefined; // used to determine whether a req or cap is edited, set to undefined to avoid compiler warnings + if (target.is("div")) { + reqOrCapId = target.parent().attr("id"); + parentReqOrCapDiv = target.parent(); + } else { + vShowError("Wrong branch. UI is not consistent with code"); + } + var isReq = parentReqOrCapDiv.hasClass("requirements"); + if (isReq) { + showAddOrUpdateDiagForReq(undefined, reqOrCapId); + } else { + //console.log(parentReqOrCapDiv.hasClass("capabilities")); + showAddOrUpdateDiagForCap(undefined, reqOrCapId); + } + return false; + } + + if (target.hasClass("policy")) { + // click is always on the seen policy content (name, template, ...) + // the complete element is the parent element + var policy = $(target).parent(); + showUpdateDiagForPolicy(policy); + return false; + } + + if ( (e.shiftKey) || (e.ctrlKey) ) { + // SHIFT or CTRL indicates multi select + // toggle containment in the multi select + $(this).toggleClass("selected"); + } else { + // no explicit multi select + var numSelected = $("div.NodeTemplateShape.selected").length; + if ($(this).hasClass("selected")) { + // selection if already exists + + // Below, we raise the selection change even in that case to provoke an update of properties etc. + // When dragging and dropping a single node, the menu of the node is not shown any more + // a click on the (still selected) node should reveal the menu entries. + } else { + // curent shape not selected + + if (numSelected > 0) { + // other shapes are selected + // the clicked shape is clicked + // that means, all other shapes should be unselected + $("div.NodeTemplateShape.selected").removeClass("selected"); + } + + // no multi select trigger + // shape is unselected + // finally, select the shape + $(this).addClass("selected"); + } + } + + winery.events.fire(winery.events.name.SELECTION_CHANGED); + return false; + }); + +</script> +<script> + + // we cannot use "$("#editorArea").on("click") as this is *always* triggered before $(document).on("click", ...) + $(document).on("mousedown", "#editorArea", function(e) { + hidePalette(); + + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + + hideRTViewOnTheRight(); + unselectAllConnections(); + + // true because jsPlumb COULD treat this event, currently unclear + return true; + }); + + /** marquee tool **/ + + var selectionBoxMode = false; + var selectionBox = {}; + + /** + * This function is called when selectionBoxMode = true and the mouse gets moved + */ + var selectionBoxModeMouseMoveFunction = function(e) { + selectionBox.endX = e.pageX; + selectionBox.endY = e.pageY; + + // fix selectionbox coordinates if they are out of the window + if (selectionBox.endX < selectionBox.minx) selectionBox.endX = selectionBox.minx; + if (selectionBox.endX > selectionBox.maxx) selectionBox.endX = selectionBox.maxx; + if (selectionBox.endY < selectionBox.miny) selectionBox.endY = selectionBox.miny; + if (selectionBox.endY > selectionBox.maxy) selectionBox.endY = selectionBox.maxy; + + // we cannot show the selection box at mousedown as this conflicts somehow with jsPlumb + // if the .offset of the selectionbox is set, jsPlumb events are not fired any more + $("#selectionbox").show(); + // setSelectionBoxCoordinates() only works if selectionbox is shown + setSelectionBoxCoordinates(); + } + + function setSelectionBoxCoordinates() { + var x; + var y; + var height; + var width; + + // adjust parameters for html, where top/left have to be smaller than lower right + if (selectionBox.startX < selectionBox.endX) { + x = selectionBox.startX; + width = selectionBox.endX - selectionBox.startX; + } else { + x = selectionBox.endX; + width = selectionBox.startX - selectionBox.endX; + } + if (selectionBox.startY < selectionBox.endY) { + y = selectionBox.startY; + height = selectionBox.endY - selectionBox.startY; + } else { + y = selectionBox.endY; + height = selectionBox.startY - selectionBox.endY; + } + + $("#selectionbox").offset({ + left : x, + top : y + }); + $("#selectionbox").width(width); + $("#selectionbox").height(height); + + // console.log("realx: " + $("#selectionbox").offset().left); + // console.log("realy: " + $("#selectionbox").offset().top); + + selectionBox.x = x; + selectionBox.y = y; + selectionBox.height = height; + selectionBox.width = width; + + var area = {}; + if (lastSelectionBox == undefined) { + // nothing selected at last, check whole new box + area = selectionBox; + } else { + // TODO + // calculate area to check + } + + // console.log("sel: " + x + "/" + y + " --X dim: " + width + "/" + height); + + // quick hack: we just go through all node templates and check them for selection + $("div.NodeTemplateShape:not('.hidden')").each(function(index, nodeTemplate) { + nodeTemplate = $(nodeTemplate); + var nx = nodeTemplate.offset().left; + var ny = nodeTemplate.offset().top; + var nw = nodeTemplate.width(); + var nh = nodeTemplate.height(); + /* console.log(nx + "/" + ny + " --> dim: " + nw + "/" + nh); */ + if (nx >= x && + ny >= y && + nx + nw <= x + width && + ny + nh <= y + height) { + nodeTemplate.addClass("selected"); + } else { + nodeTemplate.removeClass("selected"); + } + }); + + lastSelectionBox = selectionBox; + } + + // register selection box handling events + $(document).on("mousedown", "#editorArea", function(e) { + selectionBoxMode = true; + selectionBox.startX = e.pageX; + selectionBox.startY = e.pageY; + selectionBox.endX = selectionBox.startX; + selectionBox.endY = selectionBox.startY; + // console.log("Start: " + selectionBox.startX + "/" + selectionBox.startY) + selectionBox.minx = document.body.scrollLeft; + selectionBox.miny = document.body.scrollTop; + selectionBox.maxx = selectionBox.minx + $(window).width(); + selectionBox.maxy = selectionBox.miny + $(window).height(); + lastSelectionBox = undefined; + $(document).on("mousemove", selectionBoxModeMouseMoveFunction); + return true; + }); + $(document).on("mouseup", function(e) { + // TODO: possibly, dragend could be used. With the recent libraries, it also works in Chrome + if (selectionBoxMode) { + $(document).off("mousemove", selectionBoxModeMouseMoveFunction); + selectionBoxMode = false; + $("#selectionbox").hide(); + } else if (multiDNDmode) { + multiDNDmode = false; + // console.log("end: multiDNDmode"); + } + }); + +</script> +<script> + + /** + * register events / event registering / eventing + */ + $(function() { + winery.events.register( + winery.events.name.SELECTION_CHANGED, + function() { + var numSelected = $("div.NodeTemplateShape.selected").length; + + if (numSelected == 1) { + + var selectedNodeTemplate = $("div.NodeTemplateShape.selected"); + if (isShownNodeTemplateShapeChangeBoxes(selectedNodeTemplate)) { + // shape change boxes are already shown. Hide them + hideNodeTemplateShapeChangeBoxes($("div.NodeTemplateShape")); + } else { + // fired if + // * a single node template is selected, + // * no menu is shown + + // bring that shape to the front + $("div.NodeTemplateShape").css("z-index", "20"); + selectedNodeTemplate.css("z-index", "21"); + + // we show the change boxes + showNodeTemplateShapeChangeBoxes(selectedNodeTemplate); + hideNodeTemplateShapeChangeBoxes($("div.NodeTemplateShape:not(.selected)")); + } + } else { + // hide everywhere + hideNodeTemplateShapeChangeBoxes($("div.NodeTemplateShape")); + } + + updateVisibilityToggleButtons(); + } + ); + winery.events.register( + winery.events.name.command.SELECT_ALL_NODETEMPLATES, + function () { + $("div.NodeTemplateShape").addClass("selected"); + winery.events.fire(winery.events.name.SELECTION_CHANGED); + } + ); + winery.events.register( + winery.events.name.command.UNSELECT_ALL_NODETEMPLATES, + function () { + $("div.NodeTemplateShape").removeClass("selected"); + winery.events.fire(winery.events.name.SELECTION_CHANGED); + } + ); + + winery.events.register( + winery.events.name.command.MOVE_UP, + function () { + wineryMoveSelectedNodeTemplateShapes(0, -10); + return false; + } + ); + winery.events.register( + winery.events.name.command.MOVE_DOWN, + function () { + wineryMoveSelectedNodeTemplateShapes(0, 10); + return false; + } + ); + winery.events.register( + winery.events.name.command.MOVE_LEFT, + function () { + wineryMoveSelectedNodeTemplateShapes(-10, 0); + return false; + } + ); + winery.events.register( + winery.events.name.command.MOVE_RIGHT, + function () { + wineryMoveSelectedNodeTemplateShapes(10, 0); + return false; + } + ); + + winery.events.register(winery.events.name.command.DELETE_SELECTION, function() { + if ($(":focus").length == 0) { + // only delete something if no input field is focused + // otherwise, a deletion of a character leads to a deletion of the selected node + var nodesToDelete = $("div.NodeTemplateShape.selected"); + if (nodesToDelete.size() > 0) { + nodesToDelete.each(function(idx, n) { + var outEdges = jsPlumb.select({source:n.id}); + outEdges.detach(); + var inEdges = jsPlumb.select({target:n.id}); + inEdges.detach(); + }); + nodesToDelete.remove(); + } else { + jsPlumb.select().each(function(connection) { + if (connection.hasType("selected")) { + jsPlumb.detach(connection); + // handleConnectionRemoved is fired by detach, + // this handles the proper data model updates + } + }); + } + }; + }); + }); + +</script> +<script> + + /** + * Initialization code + */ + $(function() { + // We need this variable to avoid adding drop targets multiple times + // The dragenter event is triggered if the current trag leaves a sub element, too + var dragEnterCount = 0; + var firstDrop = true; + + // hack for firefox 19.0.2 publishing the dragenter event twice in some cases (when firebug is not active) + var lastElement = ""; + + var divDemo = $("html"); + divDemo.on("dragenter", function(event) { + if (firstDrop) { + $(".addnewartifacttemplate").show(); + firstDrop = false; + } + if (lastElement != event.target) { + dragEnterCount++; + lastElement = event.target; + } + }); + divDemo.on("dragleave", function(event) { + dragEnterCount--; + lastElement = ""; + if (dragEnterCount==0) { + $(".addnewartifacttemplate").hide(); + lastElement = ""; + firstDrop = true; + } + }); + + // disable dragover to enable drag'n'drop of files + // see https://github.com/blueimp/jQuery-File-Upload/wiki/Multiple-File-Upload-Widgets-on-the-same-page + $(document).on("drop dragover", function(e) { + e.preventDefault(); + e.stopPropagation(); + }); + + $(document).on("drop", function(e) { + if (e.originalEvent.dataTransfer && e.originalEvent.dataTransfer.files) { + e.preventDefault(); + e.stopPropagation(); + } + }); + + // A call is not necessary - the button should have been intialized correctly at the loading by having the right class (active) where appropriate + // updateVisibilityToggleButtons(); + }); +</script> +<script> + // fire KeyboardJS initialization in parallel to loading + require(["keyboardjs"], function(KeyboardJS) { + KeyboardJS.on('del', function(event, keys, keyComboStr) { + if (!keyComboAllowed()) { + return true; + } else { + winery.events.fire(winery.events.name.command.DELETE_SELECTION); + } + }); + + KeyboardJS.on('ctrl + s', function(event, keys, keyComboStr) { + winery.events.fire(winery.events.name.command.SAVE); + + // disable triggering saving by browser + return false; + }); + + KeyboardJS.on('ctrl + a', function(event, keys, keyComboStr) { + if (!keyComboAllowed()) { + // CTRL+a on an input element should trigger selecting all text + return true; + } else { + // otherwise, we select all node templates + winery.events.fire(winery.events.name.command.SELECT_ALL_NODETEMPLATES); + return false; + } + }); + + KeyboardJS.on('up', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + return true; + } else { + winery.events.fire(winery.events.name.command.MOVE_UP); + return false; + } + }); + KeyboardJS.on('down', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + // down on an input, when a dialog is shown or when no nodeTemplate is selected, should trigger the default action + return true; + } else { + // otherwise, we move the selected node templates down + winery.events.fire(winery.events.name.command.MOVE_DOWN); + return false; + } + }); + KeyboardJS.on('left', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + return true; + } else { + winery.events.fire(winery.events.name.command.MOVE_LEFT); + return false; + } + }); + KeyboardJS.on('right', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + return true; + } else { + winery.events.fire(winery.events.name.command.MOVE_RIGHT); + return false; + } + }); + }); +</script> +<script> + + function updateVisibilityToggleButtons() { + + if ($("div.NodeTemplateShape.selected").size() == 0) { + + // show buttons active if all parts are visible + // show buttons inactive if any part is not visible + if ($("div.NodeTemplateShape:visible .deploymentArtifactsContainer:visible").size() == $("div.NodeTemplateShape:visible .deploymentArtifactsContainer").size()) { + $('#toggleDeploymentArtifactsVisibility').addClass('active'); + } else { + $('#toggleDeploymentArtifactsVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape:visible .propertiesContainer:visible").size() == $("div.NodeTemplateShape:visible .propertiesContainer").size()) { + $('#togglePropertiesVisibility').addClass('active'); + } else { + $('#togglePropertiesVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape:visible div.type.nodetemplate:visible").size() == $("div.NodeTemplateShape:visible div.type.nodetemplate").size()) { + $('#toggleTypeVisibility').addClass('active'); + } else { + $('#toggleTypeVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape:visible div.id.nodetemplate:visible").size() == $("div.NodeTemplateShape:visible div.id.nodetemplate").size()) { + $('#toggleIdVisibility').addClass('active'); + } else { + $('#toggleIdVisibility').removeClass('active'); + } + + } else { + if ($("div.NodeTemplateShape.selected .deploymentArtifactsContainer:visible").size() > 0) { + $('#toggleDeploymentArtifactsVisibility').addClass('active'); + } else { + $('#toggleDeploymentArtifactsVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape.selected .propertiesContainer:visible").size() > 0) { + $('#togglePropertiesVisibility').addClass('active'); + } else { + $('#togglePropertiesVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape.selected div.type.nodetemplate:visible").size() > 0) { + $('#toggleTypeVisibility').addClass('active'); + } else { + $('#toggleTypeVisibility').removeClass('active'); + } + if ($("div.toggleIdVisibility.selected div.id.nodetemplate:visible").size() > 0) { + $('#toggleTypeVisibility').addClass('active'); + } else { + $('#toggleIdVisibility').removeClass('active'); + } + } + } + +</script> + +<script> + + function handleConnectionRemoved(data) { + var id = data.connection.id; + + // QUICK HACK: trigger rerouting of arrows + // jsPlumb should do it automatically, but in the winery setup, it does not + window.setTimeout(function() { + jsPlumb.repaint($("#" + data.targetId)); + }, 300); + + + delete winery.connections[id]; + } + + jsPlumb.bind("ready", function() { + jsPlumb.importDefaults({ + DragOptions : { cursor: "pointer", zIndex:2000 }, + HoverClass:"connector-hover" + }); + + jsPlumb.bind("connectionDrag", function(conn) { + isInConnectionMode = true; + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + return true; + }); + + jsPlumb.bind("beforeDrop", function(sourceId, targetId, scope, connection, dropEndpoint) { + isInConnectionMode = false; + return true; + }); + + jsPlumb.bind("connectionDetached", function(connection) { + handleConnectionRemoved(connection); + }); + + jsPlumb.bind("click", function(conn, originalEvent) { + if (!conn.hasType("selected")) { + unselectAllConnections(); + conn.addType("selected"); + showRTViewOnTheRight(conn); + } else { + conn.removeType("selected"); + // we have to go through all connections by ourselves to find out the number of selected ones + var selectedConn = undefined; + var count = 0; + jsPlumb.select().each(function(connection) { + if (connection.hasType("selected")) { + count++; + selectedConn = connection; + } + }); + if (count == 1) { + showRTViewOnTheRight(selectedConn); + } else { + hideRTViewOnTheRight(); + } + } + }); + // jsPlumb.ready + }); + </script> + + +<%-- ===== BEGIN: enable editing properties of requirements and capabilities ===== --%> +<div class="hidden" id="skelettonContainerForRequirements"> + <%-- create property value holders for each requirement type; used for NEWLY created requirements --%> + <c:forEach items="<%=client.getAllTypes(TRequirementType.class)%>" var="type"> + <div class="skelettonPropertyEditorForReq"> + <span class="typeQName">{${type.targetNamespace}}${type.name}</span> + <tmpl:properties + propertiesDefinition="${type.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(type)}" + template="<%=null%>" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> +</div> +<div class="hidden" id="skelettonContainerForCapabilities"> + <%-- create property value holders for each capability type; used for NEWLY created capability --%> + <c:forEach items="<%=client.getAllTypes(TCapabilityType.class)%>" var="type"> + <div class="skelettonPropertyEditorForCap"> + <span class="typeQName">{${type.targetNamespace}}${type.name}</span> + <tmpl:properties + propertiesDefinition="${type.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(type)}" + template="<%=null%>" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> +</div> + +<script> +// Initialize skeletton editor does NOT work with the current clone thing, we have to initialize the editor after the clone add addreqorcap.tag +</script> +<%-- ===== END: enable editing properties of requirements and capabilities ===== --%> + + +<%-- ===== BEGIN: enable editing properties of relationship types ===== --%> +<%-- idea: + * create editor in skelettonContainerForRelationshipTemplates, + * move it to the properties for editing, + * and move it back to skelettonContainerForRelationshipTemplates after editing +--%> + +<div class="hidden" id="skelettonContainerForRelationshipTemplates"> + <%-- create property value holders for each relationship type; used for NEWLY created relationship templates --%> + <c:forEach items="<%=relationshipTypes%>" var="relationshipType"> + <div class="skelettonPropertyEditorForRelationshipTemplate"> + <span class="typeQName">{${relationshipType.targetNamespace}}${relationshipType.name}</span> + <tmpl:properties + propertiesDefinition="${relationshipType.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(relationshipType)}" + template="<%=null%>" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> + + <%-- create property value holders for each existing relationship template; used for existing relationship templates--%> + <c:forEach items="<%=relationshipTemplates%>" var="relationshipTemplate"> + <%-- data-id stores the id of the relationship template --%> + <div class="propertyEditorForRelationshipTemplate" data-id="${relationshipTemplate.id}"> + <c:set var="typeQName" value="${relationshipTemplate.type}" /> + <c:set var="relationshipType" value="<%=client.getType((javax.xml.namespace.QName) pageContext.getAttribute(\"typeQName\"), TRelationshipType.class)%>" /> + <tmpl:properties + propertiesDefinition="${relationshipType.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(relationshipType)}" + template="${relationshipTemplate}" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> +</div> + +<script> +// Initialize skeletton editor +// A clone also clones the editing functionality +$(".skelettonPropertyEditorForRelationshipTemplate").find(".KVPropertyValue").editable(); +</script> + +<script> +var tmpRelationshipTemplateProperties = {}; + +function onDoneRegisterConnectionTypesAndConnectNodeTemplates() { + // as soon as all connection types are registered, + // winery.connections[] is filled + + // winery.connections is a hashmap from jsPlumb ids to a datastructure containing the winery id + // the jsPlumb id is NOT equal to the winery id + // therefore, we have to create a map between winery id and jsplumb id + var mapTOSCAIdToJSPlumbId = {}; + $.each(winery.connections, function(i, e) { + mapTOSCAIdToJSPlumbId[e.id] = i; + }); + + // we have to move PropertyEditorForRelationshipTemplate->*ID* to winery.connections[*ID*].propertiesHTML + // we also init x-editable + $(".propertyEditorForRelationshipTemplate").each(function(i,e) { + var id = $(e).data("id"); + var propertiesContainer = $(e).children("div.propertiesContainer"); + if (propertiesContainer.length != 0) { + // properties exist + // move the properties container + id = mapTOSCAIdToJSPlumbId[id]; + winery.connections[id].propertiesContainer = propertiesContainer; + propertiesContainer.find(".KVPropertyValue").editable(); + } + }); + + // we have to bind here and not in propertiesOfOneRelationshipTemplate.tag as we only want to listen to *usercreated* connections, + // not to existing ones + jsPlumb.bind("connection", function(data) { + // similar to winery-common-topologyrendering -> handleConnectionCreated + var conn; + if (data.connection) { + conn = data.connection; + } else { + conn = data; + } + + var id = conn.id; + var type = conn.getType()[0]; + var propertiesContainer= $(".skelettonPropertyEditorForRelationshipTemplate > span:contains('" + type + "')").parent().children("div"); + winery.connections[id].propertiesContainer = propertiesContainer; + }); + + // finally, we have finished loading + $('#loading').fadeOut(); +} +</script> +<%-- ===== END: enable editing properties of relationship types ===== --%> + +<tmpl:registerConnectionTypesAndConnectNodeTemplates relationshipTemplates="<%=relationshipTemplates%>" relationshipTypes="<%=relationshipTypes %>" ondone="onDoneRegisterConnectionTypesAndConnectNodeTemplates();" repositoryURL="<%=repositoryURL%>"/> + +<!-- The template to display files available for upload --> +<script id="template-upload" type="text/x-tmpl"> +{% for (var i=0, file; file=o.files[i]; i++) { %} + <tr class="template-upload fade"> + <td> + <span class="preview"></span> + </td> + <td> + <p class="name">{%=file.name%}</p> + {% if (file.error) { %} + <div><span class="label label-important">Error</span> {%=file.error%}</div> + {% } %} + </td> + <td> + <p class="size">{%=o.formatFileSize(file.size)%}</p> + {% if (!o.files.error) { %} + <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar" style="width:0%;"></div></div> + {% } %} + </td> + <td> + {% if (!o.files.error && !i && !o.options.autoUpload) { %} + <button class="btn btn-primary start"> + <i class="icon-upload icon-white"></i> + <span>Start</span> + </button> + {% } %} + {% if (!i) { %} + <button class="btn btn-warning cancel"> + <i class="icon-ban-circle icon-white"></i> + <span>Cancel</span> + </button> + {% } %} + </td> + </tr> +{% } %} +</script> +<!-- The template to display files available for download --> +<script id="template-download" type="text/x-tmpl"> +{% for (var i=0, file; file=o.files[i]; i++) { %} + <tr class="template-download fade"> + <td> + <span class="preview"> + {% if (file.thumbnailUrl) { %} + <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a> + {% } %} + </span> + </td> + <td> + <p class="name"> + <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a> + </p> + {% if (file.error) { %} + <div><span class="label label-important">Error</span> {%=file.error%}</div> + {% } %} + </td> + <td> + <span class="size">{%=o.formatFileSize(file.size)%}</span> + </td> + <td> + <button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}> + <i class="icon-trash icon-white"></i> + <span>Delete</span> + </button> + </td> + </tr> +{% } %} +</script> + +</div> + +<script type="text/x-tmpl" id="tmpl-deploymentArtifact"> + <div class="deploymentArtifact row" onclick="showDeploymentArtifactInformation('{%=o.nodeTemplateId%}', '{%=o.name%}');"> + <textarea class="hidden">{%=o.xml%}</textarea> + <div class="col-xs-4 overflowhidden deploymentArtifact name">{%=o.name%}</div> + <div class="col-xs-4 overflowhidden artifactTemplate">{% if (o.artifactTemplateName) { %}{%=o.artifactTemplateName%}{% } %}</div> + <div class="col-xs-4 overflowhidden artifactType">{%=o.artifactTypeName%}</div> + </div> +</script> + +<script type="text/x-tmpl" id="tmpl-deploymentArtifactXML"> + <tosca:DeploymentArtifact + name="{%=o.name%}" + xmlns:ns1="{%=o.artifactTypeNSAndId.namespace%}" + artifactType="ns1:{%=o.artifactTypeNSAndId.localname%}" + {% if (o.artifactTemplateNSAndId) { %} + xmlns:ns2="{%=o.artifactTemplateNSAndId.namespace%}" + artifactRef="ns2:{%=o.artifactTemplateNSAndId.localname%}" + {% } %} + xmlns:tosca="<%=org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE%>" /> +</script> + +<%-- param: value, selected (optional), text --%> +<script type="text/x-tmpl" id="tmpl-option"> +<option value="{%=o.value%}"{% if (o.selected) { %} selected="selected"{% } %}>{%=o.text%}</option> +</script> + + </body> +</html> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/artifacttemplateselection.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/artifacttemplateselection.js new file mode 100644 index 0000000..7b7f20b --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/artifacttemplateselection.js @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + + // also loaded from the repository + +// TODO: winery-common should be required -> encodeID; typing could be required (but that is no AMD module) +define([], function() { + $("#artifactTemplateName").typing({ + start: function(event, $elem) { + flagArtifactTemplateNameAsUpdating(); + }, + stop: function(event, $elem) { + checkArtifactTemplateName(); + } + }); + + $("#artifactTemplateNS").on("blur", checkArtifactTemplateName).on("change", checkArtifactTemplateName).on("focus", flagArtifactTemplateNameAsUpdating); + + var repositoryURL; + + return { + setRepositoryURL: function(url) { + repositoryURL = url; + }, + checkArtifactTemplateName: checkArtifactTemplateName, + flagArtifactTemplateNameAsUpdating: flagArtifactTemplateNameAsUpdating + }; + + function checkArtifactTemplateName() { + var ns = $("#artifactTemplateNS").val(); + var name = $("#artifactTemplateName").val(); + var url = repositoryURL + "/artifacttemplates/" + encodeID(ns) + "/" + encodeID(name) + "/"; + if (name == "") { + var valid = false; + var invalidReason = "No name provided"; + setValidityStatus(valid, invalidReason); + } else { + $.ajax(url, { + type: 'HEAD', + dataType: 'html', + error: function(jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 404) { + // artifact template does not exist: everything is allright + setValidityStatus(true, null); + } else { + setValidityStatus(false, textStatus); + } + }, + success: function(data, textStatus, jqXHR) { + setValidityStatus(false, "artifact template already exists"); + } + }); + } + } + + function flagArtifactTemplateNameAsUpdating() { + $("#artifactTemplateNameIsValid").removeClass("invalid").removeClass("valid").addClass("unknown"); + $("#artifactTemplateNameIsInvalidReason").text(""); + } + + function setValidityStatus(valid, invalidReason) { + $("#artifactTemplateNameIsValid").removeClass("unknown"); + if (valid) { + $("#artifactTemplateNameIsValid").addClass("valid"); + $("#artifactTemplateNameIsInvalidReason").text("Ok"); + } else { + $("#artifactTemplateNameIsValid").addClass("invalid"); + $("#artifactTemplateNameIsInvalidReason").text(invalidReason); + } + } + + +});
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-audio.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-audio.js new file mode 100644 index 0000000..20e2cde --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-audio.js @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-image.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-image.js new file mode 100644 index 0000000..20e2cde --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-image.js @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-validate.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-validate.js new file mode 100644 index 0000000..20e2cde --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-validate.js @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-video.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-video.js new file mode 100644 index 0000000..20e2cde --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/jquery.fileupload-video.js @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +// dummy as we don't need the functionality, but jquery.fileupload-ui.js requires it
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common-topologyrendering.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common-topologyrendering.js new file mode 100644 index 0000000..fa37897 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common-topologyrendering.js @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ +/** + * This file contains supporting functions for the rendering a topology template + */ +define( + ["jsplumb", "winery-support-common"], + function (globdefa, wsc) { + var readOnly = false; + + var module = { + initNodeTemplate: initNodeTemplate, + handleConnectionCreated: handleConnectionCreated, + imageError: imageError, + setReadOnly: setReadOnly + }; + + return module; + + /** + * @param nodeTemplateShape the set of node template shapes to initialize + * @param makeDraggable true if the nodeTemplates should be made draggable + */ + function initNodeTemplate(nodeTemplateShapeSet, makeDraggable) { + if (makeDraggable) { + jsPlumb.draggable(nodeTemplateShapeSet); + } + jsPlumb.makeTarget(nodeTemplateShapeSet, { + anchor:"Continuous", + endpoint:"Blank" + }); + + // this function is defined in index.jsp via jsp functions + // as it depends on the available relationship types + createConnectorEndpoints(nodeTemplateShapeSet); + + nodeTemplateShapeSet.addClass("layoutableComponent"); + + nodeTemplateShapeSet.each(function(idx, s) { + var shape = $(s); + + var id = shape.attr("id"); + + // KV Properties + var props = shape.children(".propertiesContainer") + .children(".content") + .children("table") + .children("tbody"); + if (!readOnly) { + props.find(".KVPropertyValue").editable(); + } + + // Deployment Artifacts + var fu = shape.children(".deploymentArtifactsContainer") + .children(".content") + .children(".addnewartifacttemplate") + .children(".fileupload"); + fu.attr("data-url", "nodetemplates/" + wsc.encodeId(id) + "/deploymentartifacts/"); + }); + + // nodeTemplateShapeSet.children(".deploymentArtifactsContainer").children(".content").children(".deploymentArtifact").each(function(index, e) { + // addnewfileoverlay could be added here + // $(this). + // }); + } + + /** + * Handles the creation of connections by jsPlumb + * + * Also called if connection is created during loading + */ + function handleConnectionCreated(data) { + // might be called directly from here or by the event + // if called by jsPlumb infrastructure, we have to get rid of the surrounding element + var conn; + if (data.connection) { + conn = data.connection; + } else { + conn = data; + } + winery.debugConnData = conn; + + var id = conn.id; + winery.connections[id] = { + // we store the id to have a default for the id + id: id, + // and use it also as starting point of a name + name: id, + // we do NOT copy the plain type here + // type is stored in the connection + // type: .getType()[0] + // BUT: we copy the detailed ns and id + nsAndLocalName: wsc.getNamespaceAndLocalNameFromQName(conn.getType()[0]) + }; + putToolTipInfo(conn); + + // we have to manually show and hide the tooltips as Bootstrap's tooltip plugin does not work after a connection was highlighted. + conn.bind("mouseenter", function(conn,e) { + putToolTipInfo(conn); + }); + conn.bind("mouseexit", function(conn,e) { + $("div.tooltip").remove(); + // we have to replace the tooltip as + putToolTipInfo(conn); + }); + } + + function putToolTipInfo(conn) { + // add tooltip showing the relationship type + var svgElement = $(conn.canvas); + // the title attribute is shown in the tooltip + // set the relationship type as tooltip + // we show the localname only + var nsAndLocalName = winery.connections[conn.id].nsAndLocalName; + // Vino4TOSCA: type in brackets + var title = "(" + nsAndLocalName.localname + ")"; + svgElement.tooltip({title: title}); + } + + /** + * Removes the image from the display. Used at images which could not be loaded + * + * Used via {@code <img onerror="imageError(this);" ... />} + */ + function imageError(image) { + image.onError=""; + image.style.visibility = "hidden"; + } + + function setReadOnly() { + readOnly = true; + } + } +);
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common.js new file mode 100644 index 0000000..434bec3 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-common.js @@ -0,0 +1,265 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +/** +This .js file is shared between the Winery Repository and the Winery Topology Modeler + +This should be rewritten as AMD module. A start is made in winery-support-common.js. + +vConfirmYesNo is defined in jsp/shared/dialogs.jsp +*/ + +/** + * Highlights fields, which are required but not filled out by the user. + * The check for required fields is done via the CSS class "required" + * + * @return true if a required field is not filled with a value + */ +function highlightRequiredFields() { + var requiredFieldMissing = false; + // includes check input field attribute "required" of HTML5: http://www.w3.org/TR/html-markup/input.radio.html#input.radio.attrs.required + $("input.required:visible:enabled, input[required]:visible").each(function(){ + if ($(this).val() == '') { + $(this).parent().addClass('has-warning'); + requiredFieldMissing = true; + } else { + $(this).parent().removeClass('has-warning'); + } + }); + return requiredFieldMissing; +} + +function vPnotify(text, title, type) { + require(["pnotify"], function() { + var notice = $.pnotify({ + title: title, + text: text, + type: type + }); + notice.on("click", function(e) { + var target = $(e.target); + if (target.is(".ui-pnotify-closer *, .ui-pnotify-sticker *, a")) { + // buttons clicked - call their functionality + return true; + } else { + // click on text leads to display of a dialog showing the complete content + + var textDiv; + if (target.is("div.ui-pnotify-text")) { + textDiv = target; + } else { + textDiv = target.closest("div.ui-pnotify-container").find("div.ui-pnotify-text"); + } + + // put text into dialog and show it + $("#diagmessagetitle").text("Full notification"); + $("#diagmessagemsg").html(textDiv.html()); + $("#diagmessage").modal("show"); + + return false; + } + }); + }); +} + +/** + * @param title optional title + */ +function vShowError(text, title) { + vPnotify(text, title, "error"); +} + +function vShowAJAXError(msg, jqXHR, errorThrown) { + vShowError(msg + "<br />" + errorThrown + "<br/>" + jqXHR.responseText); +} + +/** + * @param title optional title + */ +function vShowNotification(text, title) { + vPnotify(text, title, "notification"); +} + + +/** + * @param title optional title + */ +function vShowSuccess(text, title) { + vPnotify(text, title, "success"); +} + +/** + * Deletes the given resource with confirmation. + * if deletion fails, an error message is shown + * + * @param onSuccess: function(data, textStatus, jqXHR) to call if deletion has been successful + * @param onError: function(jqXHR, textStatus, errorThrown) called if deletion lead to an error (optional) + * @param onStart: function() called if user has agreed to delete resource (optional) + * @param withoutConfirmation if given, the resource is deleted without any confirmation + */ +function deleteResource(nameOfResource, url, onSuccess, onError, onStart, withoutConfirmation) { + var f = function() { + $.ajax({ + url: url, + type: 'DELETE', + async: true, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not delete " + nameOfResource, jqXHR, errorThrown); + if (onError) onError(); + }, + success: function(data, textStatus, jqXHR) { + vShowSuccess("Successfully deleted " + nameOfResource); + onSuccess(data, textStatus, jqXHR); + } + }); + }; + if (withoutConfirmation) { + f(); + } else { + vConfirmYesNo("Do you really want to delete " + nameOfResource + "?", f); + } +} + +/** + * Function to create a td with two columns: one for a key and one for a value + * + * Has to be called from a td element: This function uses $(this) to determine the td + * It changes the content of the td to an input field. In case the input was updated, it is POSTed to the given URL + * + * TODO: The editing mode should use x-editable instead of a self-written input handling + * + * @param url the URL to post the key/value pair to + * @param keyName the keyname of the key - used at POST with <keyName>=<newKey> + * @param valueName the keyname of the value - used at POST with <valueName>=<newValue> + * + */ +function vCreateTdClickFunction(url, keyName, valueName) { + var inputId = "thingedit" + Math.floor((Math.random()*100)+1); ; + keyName = keyName || "key"; + valueName = valueName || "value"; + + var f = function(e) { + var input = $("#" + inputId); + if (input.length != 0) { + // input field already there + return; + } + + var td = $(this); + var oldPrefix = td.text(); + var html = "<input id='" + inputId + "' value='" + oldPrefix + "'></input>"; + td.html(html); + + // new field generated, has to be looked up + input = $("#" + inputId); + + input.keydown(function(e) { + if (e.keyCode == 27) { + // ESC key pressed + input.off("blur"); + td.html(oldPrefix); + } else if (e.keyCode == 13) { + // enter key pressed + input.trigger("blur"); + } + }); + + input.focus(); + + input.on("blur", function() { + var newPrefix = input.val(); + if (newPrefix == oldPrefix) { + td.html(newPrefix); + } else { + var namespace = td.next().text(); + newPrefixEscaped = escape(newPrefix); + namespaceEscaped = escape(namespace); + var data = keyName + "=" + newPrefixEscaped + "&" + valueName + "=" + namespaceEscaped; + $.ajax({ + url: url, + type: "POST", + async: false, + data: data, + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not update data", jqXHR, errorThrown); + input.focus(); + }, + success: function(data, textSTatus, jqXHR) { + vShowSuccess("Successfully updated data"); + td.html(newPrefix); + } + }); + } + }); + }; + + return f; +} + +/** + * This function is also availble at winery-support-common.js + * This function here is due to legacy reasons and all callers should move to winery-support-common.js + * + * @param qname a QName in the form {namespace}localname + * @return { namespace: namespace, localname: localname } + */ +function getNamespaceAndLocalNameFromQName(qname) { + var i = qname.indexOf("}"); + var res = { + namespace : qname.substr(1,i-1), + localname : qname.substr(i+1) + }; + return res; +} + +/** + * Converts a QName of the form {namespace}id to the form prefix:id + * with a lookup of the prefix in the element + * + * returns wrong data if prefix wsa not found + */ +function getQNameOutOfFullQName(fullQname, element) { + var nsAndId = getNamespaceAndLocalNameFromQName(fullQname); + var prefix = element.lookupPrefix(nsAndId.namespace); + var qname = prefix + ":" + nsAndId.localname; + return qname; +} + +/** + * Converts a QName of the form prefix:id to the form {namespace}id + * with a lookup of the prefix in the element + * + * Currently not used anywhere + */ +function getFullQNameOutOfQName(qname, element) { + var i = qname.indexOf(":"); + var prefix = qname.substr(0,i-1); + var localname = qname.substr(i+1); + var namespace = element.lookupPrefix(prefix); + return "{" + namespace + "}" + localname; +} + +function encodeID(id) { + // the URL sent to the server should be the encoded id + id = encodeURIComponent(id); + // therefore, we have to encode it twice + id = encodeURIComponent(id); + return id; +} + +// URLs from QName are provided by winery-support-common.js +function makeArtifactTemplateURL(repoURL, namespace, id) { + return repoURL + "/artifacttemplates/" + encodeID(namespace) + "/" + encodeID(id) + "/"; +} + +if (!window.winery) window.winery = {}; +window.winery.BOOTSTRAP_ANIMATION_DURATION = 400; diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-sugiyamaLayouter.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-sugiyamaLayouter.js new file mode 100644 index 0000000..fa63f56 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-sugiyamaLayouter.js @@ -0,0 +1,634 @@ +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Kálmán Képes - initial API and implementation and/or initial documentation + *******************************************************************************/ + +/** + * Implements abstractLayouter#layout and uses the Sugiyama method to apply a + * layered layout for TOSCA Topology Template graphs. The Sugiyama method + * proposes four steps to apply the layout:<br> + * First: Remove the cycles temporarly of the given graph by finding edges that + * are members of a cycle and reverse them<br> + * Second: Layer the nodes by using DFS/BFS and reduce the "height"/"width" of + * the graph<br> + * Third: Reduce the crossings of edges, by applying a suitable heuristic <br> + * Fourth: Assign the coordinates for the nodes/edges + * + * @param {Array} + * nodeTemplates, an array with div-elements of class + * ".NodeTemplateShape" + */ +define(function() { + + var module = { + layout: layout + }; + return module; + + function layout(nodeTemplates) { + + + // Step 1: "Remove" Cycles + var hasCycle = _hasCycle(nodeTemplates); + var complementEdgesOfSubgraph = null; + if (hasCycle){ + var edgesOfAcyclicSubgraph = _computeAcyclicSubgraph(nodeTemplates); + complementEdgesOfSubgraph = _computeEdgeComplement(nodeTemplates, + edgesOfAcyclicSubgraph); + _reverseEdges(complementEdgesOfSubgraph); + } + + // Step 2: Assign Layers + _assignLayers(nodeTemplates); + + // Step 3: reduce crossing of edges + _reduceCrossing(nodeTemplates); + + // Step 4: assign coordinates + _assignCoordinates(nodeTemplates); + + if(hasCycle){ + _reverseEdges(complementEdgesOfSubgraph); + } + + jsPlumb.repaintEverything(); + // if used twice, edges are drawn straight and not random + jsPlumb.repaintEverything(); + + // cleanup -> remote internal data + $(nodeTemplates).removeAttr("layer"); + $(nodeTemplates).removeAttr("layerPos"); + + } + + + function callsOnLayout(nodeTemplates) { + // TODO start sugiyama layout method with special handling of calls-on + // relations + } + + /** + * Returns true if the given graph contains a cycle + * @param nodeTemplates the vertices of the graph, where cycle detection should be performed. The vertices should be an array of NodeTemplates + * @returns {Boolean} true iff a cycle was detected in the graph, else false + */ + function _hasCycle(nodeTemplates) { + for(var i = 0; i < nodeTemplates.length;i++){ + nodeTemplates[i].cycleMark = "notStarted"; + } + + var hasCycle = false; + var sources = _returnSources(nodeTemplates); + + for(var i = 0; i < sources.length; i++){ + _cycleSearch(sources[i],hasCycle); + if(hasCycle){ + // remove marks + $(nodeTemplates).removeAttr("cycleMark"); + return hasCycle; + } + } + + return hasCycle; + } + + var tarjanCounter = 1; + + /** + * Detects cycles which are reachable by the given NodeTemplate of a graph. Algorithm is based on DFS + * @param nodeTemplate the starting NodeTemplate for the DFS + * @param hasCycle boolean variable to propagate if a cycle was found, init value should be 'false' + */ + function _cycleSearch(nodeTemplate,hasCycle){ + if(nodeTemplate.cycleMark = "inWork"){ + hasCycle =true; + } else if(nodeTemplate.cycleMark ="notStarted") { + nodeTemplate.cycleMark ="inWork"; + var successors = _returnSuccessors(nodeTemplate); + for(var i = 0 ; i < successors.length; i++){ + _cycleSearch(successors[i]); + } + nodeTemplate.cycleMark ="finished"; + } + + } + + /** + * Calculates strongly connected components according to Tarjans algorithm + * @param nodeTemplate a NodeTemplate that is used to begin the algorithm on + * @param foundCycle boolean variable to propagate if a cycle was found, init value should be 'false' + */ + function _findComponent(nodeTemplate, foundCycle){ + if(nodeTemplate.cycleMark == "inWork"){ + foundCycle = true; + } else if(nodeTemplate.cycleMark == "notStarted"){ + nodeTemplate.cycleMark = "inWork"; + nodeTemplate.dfsNum = tarjanCounter; + nodeTemplate.compNum = tarjanCounter; + tarjanCounter++; + var successors = _returnSuccessors(nodeTemplate); + for(var i = 0; i < successors.length;i++){ + var successor = successors[i]; + if(successor.cycleMark != "finished"){ + _findComponent(successor,foundCycle); + if(successor.compNum < nodeTemplate.compNum){ + nodeTemplate.compNum = successor.compNum; + } + } + } + nodeTemplate.cycleMark = "finished"; + } + } + + /** + * Assigns x/y-Coordinates to the given NodeTemplates. It is assumed that the + * NodeTemplates are already layered, e.g. nodeTemplate.layer, + * nodeTemplate.layerPos is set. + * + * @param nodeTemplates + * the nodetemplate to set it's x/y coordinates + */ + function _assignCoordinates(nodeTemplates) { + // get the layers out of the graph and the number of layers + var highestLayerNumber = _returnHighestLayerNumber(nodeTemplates); + var layerMap = {}; + for ( var i = 1; i <= highestLayerNumber; i++) { + layerMap[i.toString()] = _returnLayer(nodeTemplates, i); + } + + // determine the layer with the greatest width, width = {max(|U|) : U is + // layer of V} + var widestLayerWidth = -1; + for (layer in layerMap) { + if (layer.length > widestLayerWidth) { + widestLayerWidth = layer.length; + } + } + + // get maximum node width + var maxNodeWidth = _getMaxWidthOfNodeArray(nodeTemplates); + + // get maximum node height + var maxNodeHeight = _getMaxHeightOfNodeArray(nodeTemplates); + + var editorArea = $("#editorArea")[0]; + var height = editorArea.clientHeight; + var width = editorArea.clientWidth; + + // TODO fine tuning or change the algorithm to handle callsOn Relations + // independently, e.g. draw it in an own tree/list/graph + // distance in height between nodes + var prettyHeight = 75; + for ( var i = highestLayerNumber; i > 0; i--) { + var layer = _returnLayer(nodeTemplates, i); + // distance in width between nodes + var prettyWidth = 75; + for ( var nodeIndex = 0; nodeIndex < layer.length; nodeIndex++) { + var layerNumber = i; + var layerPos = layer[nodeIndex].layerPos; + layer[nodeIndex].style.left = ((layerPos) * maxNodeWidth + prettyWidth) + + "px"; + layer[nodeIndex].style.top = ((highestLayerNumber - layerNumber) + * maxNodeHeight + prettyHeight) + + "px" + prettyWidth += 50; + } + prettyHeight += 100; + } + } + + /** + * Returns the height of the nodeTemplate with the highest height + * @param nodeTemplates an array of NodeTemplates + * @returns {Number} the maximum height of the given NodeTemplates + */ + function _getMaxHeightOfNodeArray(nodeTemplates) { + var maxHeight = -1; + for ( var i = 0; i < nodeTemplates.length; i++) { + // TODO clientHeight responds to the complete page, not only the + // nodetemplate + if (maxHeight < nodeTemplates[i].clientHeight) { + maxHeight = nodeTemplates[i].clientHeight; + } + } + return maxHeight; + } + + /** + * Returns the width of the nodeTemplate with the highest width + * @param nodeTemplates an array of NodeTemplates + * @returns {Number} the maximum width of the given NodeTemplates + */ + function _getMaxWidthOfNodeArray(nodeTemplates) { + var maxWidth = -1; + for ( var i = 0; i < nodeTemplates.length; i++) { + // TODO clientWidth responds to the complete page, not only the + // nodetemplate + if (maxWidth < nodeTemplates[i].clientWidth) { + maxWidth = nodeTemplates[i].clientWidth; + } + } + return maxWidth; + } + + /** + * Reduces crossing between the already layered Graph, given as a Array of NodeTemplates + * @param nodeTemplates the vertices of the layered graph, to reduce crossing between the layers + */ + function _reduceCrossing(nodeTemplates) { + // initialize arbitrary orderings inside layers + _initLayerOrder(nodeTemplates); + var maxlayerlevel = _returnHighestLayerNumber(nodeTemplates); + // variable to reduce crossings of layer-pairs one by one + var layerCount = 1; + // variable to check if some change was made + var changed = true; + while (layerCount < maxlayerlevel | changed) { + // the algorithm should run until no position changes are made + if (layerCount == maxlayerlevel) { + layerCount = 1; + } + changed = false; + + var layer = _returnLayer(nodeTemplates, layerCount + 1); + + // INFO: This piece of code reduces the corssing according to the + // barycenter heuristic + for ( var i = 0; i < layer.length; i++) { + // deg(u), where u = layer[i] + var deg_u = _returnIncomingEdges(layer[i]).length + + _returnOutgoingEdges(layer[i]).length; + + // sum of layerpos(v), for ever v where (u,v) exists in the graph + var outgoingEdges = _returnOutgoingEdges(layer[i]); + var sum = 0.0; + for ( var j = 0; j < outgoingEdges.length; j++) { + var node_v = outgoingEdges[j].target; + sum = sum + node_v.layerPos; + } + + // barycenter heuristic + var bary_u = 1 / deg_u * sum; + layer[i].barycenter = bary_u; + } + + // sorting the nodetemplates in the layer accorindg to the barycenter + layer.sort(function(a, b) { + return a.barycenter - b.barycenter + }); + + // rearrange positions in layer + for ( var i = 0; i < layer.length; i++) { + if (layer[i].layerPos != i + 1) { + // checks whether some change of the position is made + changed = true; + } + layer[i].layerPos = i + 1; + } + + // get ready for the next layer + layerCount++; + } + } + + /** + * Returns an array of NodeTemplates which are in the same Layer (nodeTemplate.layer) + */ + function _returnLayer(nodeTemplates, layerNumber) { + var layer = new Array(); + for ( var i = 0; i < nodeTemplates.length; i++) { + if ("layer" in nodeTemplates[i] + && nodeTemplates[i].layer == layerNumber) { + layer.push(nodeTemplates[i]); + } + } + layer.sort(function(a, b) { + return a.layerPos - b.layerPos; + }); + return layer; + } + + /** + * Returns the number of the highest layer of the given layered graph + * @param nodeTemplates the vertices of the layered graph as an array of NodeTemplates + * @returns {Number} the highest layer number + */ + function _returnHighestLayerNumber(nodeTemplates) { + var layerNumber = -1; + for ( var i = 0; i < nodeTemplates.length; i++) { + if (!"layer" in nodeTemplates[i]) { + // some node has no "layer" property defined <=> graph isn't layered + return -1; + } else { + if (nodeTemplates[i].layer > layerNumber) { + layerNumber = nodeTemplates[i].layer; + } + } + } + return layerNumber; + } + + /** + * Initializes a layering order in each layer of the given graph + * @param nodeTemplates the vertices of the graph to layer, as an array of NodeTemplates + */ + function _initLayerOrder(nodeTemplates) { + // "map" := layerNumber : ordernumber + var orderingCount = {}; + // init with 1 : 1 + orderingCount["1"] = 1; + for ( var i = 0; i < nodeTemplates.length; i++) { + // get layer number of the nodetemplate + var layerNumber = nodeTemplates[i].layer; + // is the layer already in the map ? + if (layerNumber.toString() in orderingCount) { + // if yes, set the pos inside layer and increment for next node + nodeTemplates[i].layerPos = orderingCount[layerNumber.toString()]; + orderingCount[layerNumber.toString()] = orderingCount[layerNumber + .toString()] + 1; + } else { + // if not, set the pos to 1 and add layer to map with count 2 + nodeTemplates[i].layerPos = 1; + // init pos for next node + orderingCount[layerNumber.toString()] = 2; + } + } + } + + /** + * Assigns layer numbers to the given graph + * @param nodeTemplates the vertices of the graph to assign layers to, as an array of NodeTemplates + */ + function _assignLayers(nodeTemplates) { + var sinks = {}; + for ( var i = 0; i < nodeTemplates.length; i++) { + if (_returnOutgoingEdges(nodeTemplates[i]).length == 0) { + sinks[i] = nodeTemplates[i]; + } + } + + // array of DIV delements + var nodesToCompute = new Array(); + + for ( var sink in sinks) { + // set layer level for the sinks and add the nodes which are reachable + // from there + sinks[sink].layer = 1; + var inEdges = _returnIncomingEdges(sinks[sink]); + for ( var i = 0; i < inEdges.length; i++) { + nodesToCompute.push(inEdges[i].source); + } + } + + // set other layer levels + while (nodesToCompute.length != 0) { + var node = nodesToCompute.shift(); + var layerNumber = _returnLayerNumber(node); + if (layerNumber == -1) { + nodesToCompute.push(node); + } else { + node.layer = layerNumber; + // add ingoing nodes to compute + var edgesToNodes = _returnIncomingEdges(node); + for ( var i = 0; i < edgesToNodes.length; i++) { + nodesToCompute.push(edgesToNodes[i].source); + } + } + } + } + + /** + * Returns the number of the layer a NodeTemplate belongs to + * @param nodeTemplate a NodeTemplate with already set layer position + * @returns {Number} the number of the layer the NodeTemplate belongs to + */ + function _returnLayerNumber(nodeTemplate) { + var layerNumber = -1; + var outgoingEdges = _returnOutgoingEdges(nodeTemplate); + for ( var i = 0; i < outgoingEdges.length; i++) { + // we will see if it works here + var successorNode = outgoingEdges[i].target; + if ("layer" in successorNode) { + if (successorNode.layer + 1 >= layerNumber) { + layerNumber = successorNode.layer + 1; + } + } else { + layerNumber = -1; + break; + } + } + return layerNumber; + } + + /** + * Returns all jsPlumb#Connection edges of the graph represented by the + * nodeTemplates array of NodeTemplateShape which aren't referenced in the + * subgraphEdges array of type jsPlumb#Connection. + * + * @param {Object} + * nodeTemplates, array of NodeTemplateShape + * @param {Object} + * subgraphEdges, array of jsPlumb#Connection + * @return {Object} array of jsPlumb#Connection which contains edges that aren't + * in the subgraph + */ + function _computeEdgeComplement(nodeTemplates, subgraphEdges) { + var edgeSet = {}; + for ( var i = 0; i < nodeTemplates.length; i++) { + var incomingEdges = _returnIncomingEdges(nodeTemplates[i]); + var outgoingEdges = _returnOutgoingEdges(nodeTemplates[i]); + for ( var incomingEdgeIndex = 0; incomingEdgeIndex < incomingEdges.length; incomingEdgeIndex++) { + var inSubgraph = false; + for ( var subgraphEdgeIndex = 0; subgraphEdgeIndex < subgraphEdges.length; subgraphEdgeIndex++) { + if (incomingEdges[incomingEdgeIndex] === subgraphEdges[subgraphEdgeIndex]) { + inSubgraph = true; + break; + } + } + if (!inSubgraph) { + edgeSet[incomingEdges[incomingEdgeIndex]] = incomingEdges[incomingEdgeIndex]; + } + } + for ( var outgoingEdgeIndex = 0; outgoingEdgeIndex < outgoingEdges.length; outgoingEdgeIndex++) { + var inSubgraph = false; + for ( var subgraphEdgeIndex = 0; subgraphEdgeIndex < subgraphEdges.length; subgraphEdgeIndex++) { + if (outgoingEdges[outgoingEdgeIndex] === subgraphEdges[subgraphEdgeIndex]) { + inSubgraph = true; + break; + } + } + if (!inSubgraph) { + edgeSet[outgoingEdges[outgoingEdgeIndex]] = outgoingEdges[outgoingEdgeIndex]; + } + } + } + // transform edge-set to array + var edgeArray = new Array(); + for (edge in edgeSet) { + edgeArray.push(edgeSet[edge]); + } + return edgeArray; + } + + /** + * Returns a list of edges which represent an acyclic subgraph of the given + * nodes. The graph is at least of size 1/2*|E|, which can be troublesome in + * some situations. This means the graph could be layouted only on the "half" of + * it. + * + * Info: There are more sophisticated methods that guarantee to produce bigger + * subgraphs, see "Drawing Graphs: Methods and Models". But in this state it is + * a huge undertake, cause Oryx doesn't seem to have any basic graph algorithm + * shipped, like DFS etc.(correct me if i'm wrong, please). + * + * @param {Object} + * nodes of a graph, which are NodeTemplatesShapes + * @return [Object] edges of the contained acyclic subgraph, which are + * jsPlumb#Connection Objects + * @see "Drawing Graphs: Methods and Models", p. 91 + */ + function _computeAcyclicSubgraph(nodeTemplates) { + var subgraphEdges = []; + for ( var i = 0; i < nodeTemplates.length; i++) { + if (_returnOutgoingEdges(nodeTemplates[i]).length >= _returnIncomingEdges(nodeTemplates[i]).length) { + for ( var j = 0; j < _returnOutgoingEdges(nodeTemplates[i]).length; j++) { + subgraphEdges.push(_returnOutgoingEdges(nodeTemplates[i])[j]); + } + } else { + for ( var j = 0; j < _returnIncomingEdges(nodeTemplates[i]).length; j++) { + subgraphEdges.push(_returnIncomingEdges(nodeTemplates[i])[j]); + } + } + } + var filteredArray = subgraphEdges.filter(function(elem, pos) { + return subgraphEdges.indexOf(elem) == pos; + }); + return filteredArray; + } + + /** + * Returns relations having the given NodeTemplate as target + * + * @param nodeTemplate + * a nodeTemplateShape + * @returns Returns an array containing jsPlumb#Connection objects representing + * relations + */ + function _returnIncomingEdges(nodeTemplate) { + var edgeArray = new Array(); + jsPlumb.select().each( + function(connection) { + if (connection.targetId === nodeTemplate.id) { + /*if (connection.getType().length != 0) { + for ( var i = 0; i < connection.getType().length; i++) { + if (connection.getType()[i].toLowerCase().indexOf( + "hostedon") !== -1) { + edgeArray.push(connection); + } + } + } else { + edgeArray.push(connection); + }*/ + edgeArray.push(connection); + + } + }); + return edgeArray; + } + + /** + * Returns relations having the given NodeTemplate as source + * + * @param nodeTemplate + * a nodeTemplateShape + * @returns Returns an array containing jsPlumb#Connections objects representing + * relations + */ + function _returnOutgoingEdges(nodeTemplate) { + var edgeArray = new Array(); + jsPlumb.select().each( + function(connection) { + if (connection.sourceId === nodeTemplate.id) { + /*if (connection.getType().length != 0) { + for ( var i = 0; i < connection.getType().length; i++) { + if (connection.getType()[i].toLowerCase().indexOf( + "hostedon") !== -1) { + edgeArray.push(connection); + } + } + } else { + edgeArray.push(connection); + }*/ + edgeArray.push(connection); + } + }); + return edgeArray; + } + + /** + * Returns the NodeTemplates which can be reached by a outgoing edges of the given NodeTemplate + * @param nodeTemplate the NodeTemplate whose Succesors should be calculated + * @returns {Array} an array of NodeTemplates which are successors of the given NodeTemplate, may be empty + */ + function _returnSuccessors(nodeTemplate){ + var nodeArray = new Array(); + var outgoingEdges = _returnOutgoingEdges(nodeTemplate); + for(var i =0; i < outgoingEdges.length; i++){ + nodeArray.push(outgoingEdges[i].target); + } + return nodeArray; + } + + /** + * Returns all sources of the given graph + * @param nodeTemplates vertices of the graph, as an array of NodeTemplates + * @returns {Array} an Array of NodeTemplates + */ + function _returnSources(nodeTemplates){ + var sourceArray = new Array(); + for(var i = 0; i < nodeTemplates.length; i++){ + if(_returnIncomingEdges(nodeTemplates[i]) == 0){ + sourceArray.push(nodeTemplates[i]); + } + } + return sourceArray; + } + + /** + * Reverses a relationshipTemplate + * + * @param relationshipTemplate + * as we don't have relationshiptemplates modelled here we expect + * jsPlumb#Connection objects + */ + function _reverseEdge(relationshipTemplate) { + // this seems to work + var source = relationshipTemplate["source"]; + var sourceId = relationshipTemplate["sourceId"]; + var target = relationshipTemplate["target"]; + var targetId = relationshipTemplate["targetId"]; + + relationshipTemplate["source"] = target; + relationshipTemplate["sourceId"] = targetId; + relationshipTemplate["target"] = source; + relationshipTemplate["targetId"] = sourceId; + } + + /** + * Reverses relationshipTemplates + * + * @param relationshipTemplates + */ + function _reverseEdges(relationshipTemplates) { + for ( var i = 0; i < relationshipTemplates.length; i++) { + _reverseEdge(relationshipTemplates[i]); + } + } +});
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-support-common.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-support-common.js new file mode 100644 index 0000000..4e87f22 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-support-common.js @@ -0,0 +1,330 @@ +/******************************************************************************* + * Copyright (c) 2012-2014 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +/** + * Functions copied from winery-common.js to replace it in the long term + * + * Shared between topology modeler and repository + */ +define([], function() { + var xmlParser = new DOMParser(); + var VALUE_OF_NONE_CHOOSEN = "(none)"; // constant to indicate that nothing is chosen in a select2 + + return { + encodeId: encodeId, + getNamespaceAndLocalNameFromQName: getNamespaceAndLocalNameFromQName, + replaceDialogShownHookForOrionUpdate: replaceDialogShownHookForOrionUpdate, + writeCollectionDefinedByATextArea: writeCollectionDefinedByATextArea, + getDocument: getDocument, + + getURLFragmentOutOfFullQName: getURLFragmentOutOfFullQName, + makeArtifactTypeURLFromQName: makeArtifactTypeURLFromQName, + makeNodeTypeURLFromQName: makeNodeTypeURLFromQName, + makeRelationshipTypeURLFromQName: makeRelationshipTypeURLFromQName, + makeRelationshipTypeURLFromNSAndLocalName: makeRelationshipTypeURLFromNSAndLocalName, + + qname2href: qname2href, + + fetchSelect2DataAndInitSelect2: fetchSelect2DataAndInitSelect2, + removeItemFromSelect2Field: removeItemFromSelect2Field, + + checkXMLValidityAndShowErrorIfInvalid: checkXMLValidityAndShowErrorIfInvalid, + synchronizeNameAndType: synchronizeNameAndType, + + VALUE_OF_NONE_CHOOSEN: VALUE_OF_NONE_CHOOSEN + }; + + /** + * OriginalName: encodeID + */ + function encodeId(id) { + // the URL sent to the server should be the encoded id + id = encodeURIComponent(id); + // therefore, we have to encode it twice + id = encodeURIComponent(id); + return id; + } + + /** + * @param qname a QName in the form {namespace}localname + * @return { namespace: namespace, localname: localname } + */ + function getNamespaceAndLocalNameFromQName(qname) { + var i = qname.indexOf("}"); + var res = { + namespace : qname.substr(1,i-1), + localname : qname.substr(i+1) + }; + return res; + } + + /** + * Orion does not update content if field not fully shown + * therefore, we hook in into the "shown" event + */ + function replaceDialogShownHookForOrionUpdate(diag, orionAreaId, content) { + diag.off("shown.bs.modal"); + diag.on("shown.bs.modal", function() { + var area = window.winery.orionareas[orionAreaId]; + area.editor.setText(content); + area.fixEditorHeight(); + }); + } + + function getURLFragmentOutOfNSAndLocalName(nsAndLocalName) { + var res; + res = encodeID(nsAndLocalName.namespace); + res = res + "/"; + res = res + encodeID(nsAndLocalName.localname); + return res; + } + + /** + * Extracts an URL fragment of the form <encoded namespace>/<encoded id> out of a full QName + * + * @param qname a QName in the form {namespace}localname + */ + function getURLFragmentOutOfFullQName(qname) { + var d = getNamespaceAndLocalNameFromQName(qname); + return getURLFragmentOutOfNSAndLocalName(d); + } + + /** + * @param w the XMLwriter + * @param elementSet the set of HTML elements to write + * @param elementName the name of the wrapper element (e.g., "Requirements", "Policies") + */ + function writeCollectionDefinedByATextArea(w, elementSet, elementName) { + if (elementSet.length !== 0) { + w.writeStartElement(elementName); + elementSet.each(function(i, element) { + // XML contains element completely + // we do not have to parse reqorcap.children("div.id").children("span.id").text() or the span.name + var text = $(element).children("textarea").val(); + w.writeXML(text); + }); + w.writeEndElement(); + } + } + + function makeArtifactTypeURLFromQName(repoURL, qname) { + return repoURL + "/artifacttypes/" + getURLFragmentOutOfFullQName(qname) + "/"; + } + + function makeNodeTypeURLFromQName(repoURL, qname) { + return repoURL + "/nodetypes/" + getURLFragmentOutOfFullQName(qname) + "/"; + } + + function makeRelationshipTypeURLFromQName(repoURL, qname) { + return repoURL + "/relationshiptypes/" + getURLFragmentOutOfFullQName(qname) + "/"; + } + + function makeRelationshipTypeURLFromNSAndLocalName(repoURL, nsAndLocalName) { + return repoURL + "/relationshiptypes/" + getURLFragmentOutOfNSAndLocalName(nsAndLocalName) + "/"; + } + + /** + * functionality similar to org.eclipse.winery.common.Util.qname2href(String, Class<? extends TExtensibleElements>, QName) + */ + function qname2href(repositoryUrl, componentPathFragment, qname) { + var nsAndId = getNamespaceAndLocalNameFromQName(qname); + var absoluteURL = repositoryUrl + "/" + componentPathFragment + "/" + getURLFragmentOutOfNSAndLocalName(nsAndId); + var res = "<a target=\"_blank\" data-qname=\"" + qname + "\" href=\"" + absoluteURL + "\">" + nsAndId.localname + "</a>"; + return res; + } + + /** + * Inspired by + * + * @param field is the jquery field + * @param id_to_remove the id to remove + */ + function removeItemFromSelect2Field(field, id_to_remove) { + // nothing can be done currently + // see https://github.com/ivaynberg/select2/issues/535#issuecomment-30210641 for a disucssion + vShowNotification("The select field shows stale data. Refresh the page to get rid of that.") + } + + /** + * Fetches select2 data from the given URL and initializes the field provided by the fieldId + * + * Calls vShowError if something went wrong + * + * @param onSuccess (optional) + * @param allowAdditions (optional) if set to true, select2 is initalized with the functionality to allow additions during the search + */ + function fetchSelect2DataAndInitSelect2(fieldId, url, onSuccess, allowAdditions) { + $.ajax({ + url: url, + dataType: "json" + }).done(function (result) { + var params = {"data": result}; + if (typeof allowAdditions === "boolean") { + params.createSearchChoice = function(term) { + // enables creation of new namespaces + return {id:term, text:term}; + } + } + + // init select2 and select first item + $("#" + fieldId).select2(params); + if (result.length === 0) { + $("#" + fieldId).select2("val", null); + } else { + $("#" + fieldId).select2("val", result[0].id); + } + + if (typeof onSuccess === "function") { + onSuccess(); + } + }).fail(function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not fetch select2 data from " + url, jqXHR, errorThrown); + }); + + } + + + function getDocument(xmlString) { + var xmlDoc = xmlParser.parseFromString(xmlString, "text/xml"); + return xmlDoc; + } + + /** + * Checks given XML string for validity. If it's invalid, an error message is shown + * Relies on the current browser's XML handling returning a HTML document if something went wrong during parsing + * + * @return XMLdocument if XML is valid, false otherwise + */ + function checkXMLValidityAndShowErrorIfInvalid(xmlString) { + var doc = getDocument(xmlString); + var errorMsg = ""; + if (doc.firstChild.localName == "html") { + errorMsg = new XMLSerializer().serializeToString(doc); + } else { + // at Chrome, the error may be nested in the XML + + // quick hack, only "xhtml" is quered + function nsResolover(x) { + return "http://www.w3.org/1999/xhtml"; + } + + var element = doc.evaluate( '//x:parsererror', doc, nsResolover, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + if (element !== null) { + errorMsg = new XMLSerializer().serializeToString(element); + } + } + + if (errorMsg !== "") { + vShowError(errorMsg); + return false; + } else { + return doc; + } + } + + /** + * Updates the XML in the orion editor based on the values given in the input fields. + * Shows error if XML is invalid + * + * Works only with SELECT2 fields + * + * @param idPrefix: (new|edit)${shortName}, derived names: [idPrefix]Name, [idPrefix]Id, Orion[idPrefix]XML + * @param hasIdField: whether the Id should be read and written + * @param selectFields: array of {attribute, fieldSuffix}, where attribute is a name of an attribute having a QName. + * Each select box is determined by #[idPrefix][fieldSuffix]. + * The select box content is converted to a QName and the result is written to the attribute [name] + * Default: {attribute: "type", fieldSuffix: "Type"} + * + * @return false if XML is invalid, true: an object if id/name/attribute1/attribute2/... (qname + attribute1FullQName: qname object)/xml (to be used in tmpl-${cssClassPrefix}) + * {id:id, name:name, type: "ns5:type", typeFullQName: "{http://www.example.org}type"} + */ + function synchronizeNameAndType(idPrefix, hasIdField, selectFields) { + if (typeof hasIdField === undefined) { + hasIdField = true; + } + if (typeof selectFields === undefined) { + selectFields = [{attribute: "type", fieldSuffix: "Type"}]; + } + + + var val = window.winery.orionareas["Orion" + idPrefix + "XML"].editor.getText(); + var xmlDoc = checkXMLValidityAndShowErrorIfInvalid(val); + if (xmlDoc) { + // handle name + var name = $("#" + idPrefix + "Name").val(); + // initialize result object + var res = { + name: name + }; + xmlDoc.firstChild.setAttribute("name", name); + + // write id and name to XML + if (hasIdField) { + var id = $("#" + idPrefix + "Id").val(); + if (!id) { + // TODO a checking should be done if the id exists + // probably not here, but at caller's side + id = name; + } + xmlDoc.firstChild.setAttribute("id", id); + res.id = id; + } + + // write each selectField to xml + // for that, we have to determine the QName + $(selectFields).each(function(i, m) { + var content = $("#" + idPrefix + m.fieldSuffix).select2("val"); + + if (content == VALUE_OF_NONE_CHOOSEN) { + // if nothing is chosen do not put it into the result + return; + } + + // determine qname of type + //getQNameOutOfFullQName(type, xmlDoc.firstChild) does not always work as xmlDoc.firstChild does not have ALL *available* namespace prefixes + var typeNSAndId = getNamespaceAndLocalNameFromQName(content); + var prefix = xmlDoc.firstChild.lookupPrefix(typeNSAndId.namespace); + if (!prefix) { + // we have to ask the repo for a prefix + $.ajax({ + type: "GET", + async: false, + "url": winery.repositoryURL + "/admin/namespaces/" + encodeID(typeNSAndId.namespace), + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not determine prefix", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + prefix = resData; + } + }); + // new prefix fetched, xmlns attribute has to be written + xmlDoc.firstChild.setAttribute("xmlns:" + prefix, typeNSAndId.namespace); + } + var qname = prefix + ":" + typeNSAndId.localname; + res[m.attribute] = qname; + res[m.attribute + "FullQName"] = typeNSAndId; + xmlDoc.firstChild.setAttribute(m.attribute, qname); + }); + + var xml = new XMLSerializer().serializeToString(xmlDoc); + res.xml = xml; + + return res; + } else { + return false; + } + } + + + } +); diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologycompletion.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologycompletion.js new file mode 100644 index 0000000..6ab66e8 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologycompletion.js @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +define(function() { + + /** + * This module handles a click on "Complete Topology" in the enterTopologyCompletionInformation dialog. + */ + var module = { + complete: complete, + restartCompletion: restartCompletion + }; + return module; + + /** + * This function start the topology completion. With information from the + * PolicyInformationDialog the topologyCompletion.jsp is called which will invoke the + * Topology Completion java component. The parameters determine if the current topology + * will be overwritten or if a new topology is created. + * + * @param (String) overwriteTopology + * determines how to save the topology. If true, the current topology is overwritten. + * @param (Boolean) openInNewWindow + * determines if the result is opened in a new window + * @param (String) topologyName + * the name of the new topology + * @param (String) topologyNamespace + * the namespace of the new topology + * @param (Boolean) stepByStep + * if true, the completion will be processed step by step + * @param (String) repositoryURL + * the URL to the repository the topology is saved to + * @param (String) toscaNamespace + * the namespace URL of TOSCA + * @param (String) wineryNamespace + * the namespace URL of winery + * @param (String) serviceTemplateName + * the name of the service template containing the displayed topology template + * @param (String) topologyTemplateURL + * the URL to the displayed topology template + */ + function complete(overwriteTopology, openInNewWindow, topologyName, topologyNamespace, stepByStep, repositoryURL, serviceTemplateName, topologyTemplateURL) { + + // if the user wants to create a new topology, a post call is sent to the repository adding + // the new ServiceTemplate + if (!overwriteTopology) { + var dataToSend = "name=" + topologyName + "&namespace=" + topologyNamespace; + var url = repositoryURL + "/servicetemplates/"; + $.ajax( + { + type: "POST", + async: false, + url: url, + "data": dataToSend, + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not add Service Template."); + } + } + ); + } + + var topology; + require(["winery-topologymodeler-AMD"], function(wt) { + topology = wt.getTopologyTemplateAsXML(true); + + // call to the completion JSP which will call the java component + $.post("jsp/topologyCompletion/topologyCompletion.jsp", {topology: topology, stName: serviceTemplateName, templateURL: topologyTemplateURL, overwriteTopology: overwriteTopology, topologyName: topologyName, topologyNamespace: topologyNamespace, repositoryURL: repositoryURL, stepByStep: stepByStep, openInNewWindow: openInNewWindow, restarted: "false"}, + /** + * Callback function which will either open a new window if a new topology was created or + * refresh the current browser window + * + * @param (String) data + * the answer of the post call + */ + function(data){ + // checks the message returned by the CompletionInterface + if (data.indexOf("topologyComplete") != -1) { + vShowSuccess('The topology is already complete.'); + } else if (data.indexOf("failure") != -1) { + vShowError(data); + } else if (data.indexOf("userTopologySelection") != -1) { + $(chooseTopologyDiag[0].children[0].children[0].children[1]).html(data); + window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); + chooseTopologyDiag.modal("show"); + } else if (data.indexOf("topologyComplete") == -1 && data.indexOf("userTopologySelection") == -1 && data.indexOf("userInteraction") != -1) { + $(chooseRelationshipTemplateDiag[0].children[0].children[0].children[1]).html(data); + window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); + chooseRelationshipTemplateDiag.modal("show"); + } else if (data.indexOf("topologyComplete") == -1 && data.indexOf("stepByStep") != -1) { + $(chooseNodeTemplateDiag[0].children[0].children[0].children[1]).html(data); + window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); + chooseNodeTemplateDiag.modal("show"); + } else { + if (openInNewWindow) { + // a new topology has been created, open it in a new window + var win=window.open('?repositoryURL=' + repositoryURL + '&ns='+ topologyNamespace + '&id=' + topologyName, '_blank'); + win.focus(); + } else if (overwriteTopology) { + // refresh page + document.location.reload(true); + } + } + } + ); + }); + } + + /** + * This function restarts the topology completion when it has been stopped to get a + * user decision. + * + * @param (String) topology + * the topology as XML string + * @param (String) overwriteTopology + * determines how to save the topology. Can contain the values "createNew" or "overwrite" + * @param (Boolean) openInNewWindow + * determines if the result is opened in a new window + * @param (String) topologyName + * the name of the new topology + * @param (String) topologyNamespace + * the namespace of the new topology + * @param (Boolean) stepByStep + * if true, the completion will be processed step by step + * @param (String) serviceTemplateName + * the name of the service template containing the displayed topology template + * @param (String) topologyTemplateURL + * the URL to the displayed topology template + * @param (String) repositoryURL + * the URL to the repository the topology is saved to + */ + function restartCompletion(topology, overwriteTopology, openInNewWindow, topologyName, topologyNamespace, stepByStep, serviceTemplateName, topologyTemplateURL, repositoryURL) { + + // remove whitespaces in the topology XML string + topology = topology.replace(/\s+/g, ' '); + topology = topology.substr(1); + + // call to the completion JSP which will call the java component + $.post("jsp/topologyCompletion/topologyCompletion.jsp", { topology: topology, stName: serviceTemplateName, templateURL: topologyTemplateURL, overwriteTopology: overwriteTopology, topologyName: topologyName, topologyNamespace: topologyNamespace, repositoryURL: repositoryURL, stepByStep: stepByStep, restarted: "true"}, + /** + * Callback function which will either open a new window if a new topology was created or + * refresh the current browser window + * + * @param (String) data + * the answer of the post call + */ + function(data){ + if (data.indexOf("Successful") == -1 && data.indexOf("stepByStep") == -1) { + $(chooseRelationshipTemplateDiag[0].children[0].children[0].children[1]).html(data); + window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); + chooseRelationshipTemplateDiag.modal("show"); + } else if (data.indexOf("Successful") == -1 && data.indexOf("stepByStep") != -1) { + $(chooseNodeTemplateDiag[0].children[0].children[0].children[1]).html(data); + window.setTimeout(jsPlumb.repaintEverything, JQUERY_ANIMATION_DURATION); + chooseNodeTemplateDiag.modal("show"); + } else { + if (openInNewWindow) { + // a new topology has been created, open it in a new window + var win = window.open('?repositoryURL=' + "<%=repositoryURL%>" + '&ns='+ topologyNamespace + '&id=' + topologyName, '_blank'); + win.focus(); + } else if (overwriteTopology) { + // refresh page + document.location.reload(true); + } + } + } + ); + } +});
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologymodeler-AMD.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologymodeler-AMD.js new file mode 100644 index 0000000..a292f43 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologymodeler-AMD.js @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2012-2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + *******************************************************************************/ + +/** + * This file contains supporting functions for the topoplogy modeler + */ +define( + // although XMLWriter ist not an AMD module, requirejs does not complain when loading it + ["winery-support-common", "XMLWriter"], + function (w) { + // has to be consistent with {@link org.eclipse.winery.common.constants.Namespaces} + var TOSCA_NAMESPACE = "http://docs.oasis-open.org/tosca/ns/2011/12"; + var TOSCA_WINERY_EXTENSIONS_NAMESPACE ="http://www.opentosca.org/winery/extensions/tosca/2013/02/12"; + + var topologyTemplateURL; + + var module = { + save: save, + setTopologyTemplateURL: function(url) { + topologyTemplateURL = url; + }, + getTopologyTemplateAsXML: getTopologyTemplateAsXML, + + TOSCA_NAMESPACE: TOSCA_NAMESPACE, + TOSCA_WINERY_EXTENSIONS_NAMESPACE: TOSCA_WINERY_EXTENSIONS_NAMESPACE + }; + return module; + + function writeReqOrCaps(elements, xmlw, globalWrapperElementName, singleElementWrapperName) { + if (elements.length != 0) { + xmlw.writeStartElement(globalWrapperElementName); + + $.each(elements, function(i,e) { + xmlw.writeStartElement(singleElementWrapperName); + e = $(e); + xmlw.writeAttributeString("id", e.children(".id").text()); + xmlw.writeAttributeString("name", e.children(".name").text()); + writeType(xmlw, e.children(".type").children("a").data("qname")); + savePropertiesFromDivToXMLWriter(e.children("div.propertiesContainer"), xmlw); + xmlw.writeEndElement(); + }); + + xmlw.writeEndElement(); + } + + } + + /** + * "doSave" + */ + function save() { + $("#saveBtn").button('loading'); + + $.ajax({ + url: topologyTemplateURL, + type: "PUT", + contentType: 'text/xml', + data: getTopologyTemplateAsXML(false), + success: function(data, textStatus, jqXHR) { + $("#saveBtn").button('reset'); + vShowSuccess("successfully saved."); + }, + error: function(jqXHR, textStatus, errorThrown) { + $("#saveBtn").button('reset'); + vShowAJAXError("Could not save", jqXHR, errorThrown); + } + }); + } + + /** + * Creates an XML String of the modelled topology template. + */ + function getTopologyTemplateAsXML(needsDefinitionsTag) { + + var xmlw = new XMLWriter("utf-8"); + xmlw.writeStartDocument(); + + if (needsDefinitionsTag) { + xmlw.writeStartElement("Definitions"); + xmlw.writeAttributeString("xmlns", TOSCA_NAMESPACE); + xmlw.writeAttributeString("xmlns:winery", TOSCA_WINERY_EXTENSIONS_NAMESPACE); + + xmlw.writeStartElement("ServiceTemplate"); + xmlw.writeAttributeString("xmlns", TOSCA_NAMESPACE); + xmlw.writeAttributeString("xmlns:winery", TOSCA_WINERY_EXTENSIONS_NAMESPACE); + } + xmlw.writeStartElement("TopologyTemplate"); + xmlw.writeAttributeString("xmlns", TOSCA_NAMESPACE); + xmlw.writeAttributeString("xmlns:winery", TOSCA_WINERY_EXTENSIONS_NAMESPACE); + $("div.NodeTemplateShape").not(".hidden").each (function() { + xmlw.writeStartElement("NodeTemplate"); + + var id = $(this).attr("id"); + + var headerContainer = $(this).children("div.headerContainer"); + var name = headerContainer.children("div.name").text(); + var typeQNameStr = headerContainer.children("span.typeQName").text(); + var minmaxdiv = headerContainer.children("div.minMaxInstances"); + var min = minmaxdiv.children("span.minInstances").text(); + var max = minmaxdiv.children("span.maxInstances").text(); + if (max == "∞") { + max = "unbounded"; + } + var x = $(this).css("left"); + x = x.substring(0, x.indexOf("px")); + var y = $(this).css("top"); + y = y.substring(0, y.indexOf("px")); + + xmlw.writeAttributeString("id", id); + if (name != "") { + xmlw.writeAttributeString("name", name); + } + writeType(xmlw, typeQNameStr); + if (min != "") { + xmlw.writeAttributeString("minInstances", min); + } + if (max != "") { + xmlw.writeAttributeString("maxInstances", max); + } + xmlw.writeAttributeString("winery:x", x); + xmlw.writeAttributeString("winery:y", y); + + /** Properties **/ + savePropertiesFromDivToXMLWriter($(this).children("div.propertiesContainer"), xmlw); + + /** Requirements **/ + writeReqOrCaps( + $(this).children("div.requirementsContainer").children("div.content").children("div.reqorcap"), + xmlw, + "Requirements", + "Requirement"); + + /** Capabilities **/ + writeReqOrCaps( + $(this).children("div.capabilitiesContainer").children("div.content").children("div.reqorcap"), + xmlw, + "Capabilities", + "Capability"); + + /** Policies **/ + w.writeCollectionDefinedByATextArea(xmlw, + $(this).children("div.policiesContainer").children("div.content").children("div.policy"), + "Policies"); + + /** Deployment Artifacts **/ + var das = $(this).children("div.deploymentArtifactsContainer").children("div.content").children("div.deploymentArtifact"); + if (das.length != 0) { + xmlw.writeStartElement("DeploymentArtifacts"); + das.each(function(i,e) { + // the textarea contains a valid deployment artifact xml + var xml = $(e).children("textarea").val(); + xmlw.writeXML(xml); + }); + xmlw.writeEndElement(); + } + + // End: Nodetemplate + xmlw.writeEndElement(); + }); + jsPlumb.select().each(function(connection) { + xmlw.writeStartElement("RelationshipTemplate"); + var id = connection.id; + var typeQNameStr = connection.getType()[0]; + + var connData = winery.connections[id]; + if (!connData) { + vShowError("Error in the internal data structure: Id " + id + " not found"); + return; + } + + xmlw.writeAttributeString("id", connData.id); + if (connData.name != "") { + xmlw.writeAttributeString("name", connData.name); + } + writeType(xmlw, typeQNameStr); + + if (typeof connData.propertiesContainer !== "undefined") { + savePropertiesFromDivToXMLWriter(connData.propertiesContainer, xmlw); + } + + xmlw.writeStartElement("SourceElement"); + if (connData.req) { + // conn starts at a requirement + xmlw.writeAttributeString("ref", connData.req); + } else { + // conn starts at a node template + xmlw.writeAttributeString("ref", connection.sourceId); + } + xmlw.writeEndElement(); + xmlw.writeStartElement("TargetElement"); + if (connData.cap) { + // conn ends at a capability + xmlw.writeAttributeString("ref", connData.cap); + } else { + // conn ends at a node template + xmlw.writeAttributeString("ref", connection.targetId); + } + xmlw.writeEndElement(); + + xmlw.writeEndElement(); + }); + + if (needsDefinitionsTag) { + xmlw.writeEndElement(); + xmlw.writeEndElement(); + } + + xmlw.writeEndDocument(); + + return xmlw.flush(); + } + + function writeQNameAttribute(w, nsPrefix, qnameStr) { + var qname = getQName(qnameStr); + w.writeAttributeString("xmlns:" + nsPrefix, qname.namespace); + w.writeAttributeString("type", nsPrefix + ":" + qname.localName); + } + + function writeType(w, typeQNameStr) { + writeQNameAttribute(w, "ty", typeQNameStr); + } + + } +); + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologymodeler.js b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologymodeler.js new file mode 100644 index 0000000..cc5c564 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/js/winery-topologymodeler.js @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2012-2013,2015 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ + +function getQName(qnameStr) { + var pos = qnameStr.indexOf("}"); + var namespace = qnameStr.substring(1, pos); + var localName = qnameStr.substring(pos+1); + var res = { + "namespace": namespace, + "localName": localName + }; + return res; +} + +/** + * @param attributeName an attribute with a value in the form prefix:localname + * @param xmlElement a DOM element (offering the method lookupNamespaceURI) + * @return { ns: namespace, id: id } + */ +function getNSAndId(attributeName, xmlElement) { + var attributeValue = xmlElement.getAttribute(attributeName); + var i = attributeValue.indexOf(":"); + var prefix = attributeValue.substring(0, i); + var localName = attributeValue.substring(i+1); + var ns = xmlElement.lookupNamespaceURI(prefix); + var res = { + ns : ns, + id: localName + }; + return res; +} + +/** + * @param el a href element + * @param pathComponent the path element "artifacttemplates" or "artifacttypes" + * @param attributeName the name of the attribute to read from the given xmlElement + * @param xmlElement used to resolve a namespace prefix to a full namespace URI + */ +function addHref(el, pathComponent, attributeName, xmlElement) { + var nsAndId = getNSAndId(attributeName, xmlElement); + var loc = winery.repositoryURL + "/" + pathComponent + "/" + encodeID(nsAndId.ns) + "/" + encodeID(nsAndId.id); + el.attr("href", loc); +} + +var currentlySelectedDeploymentArtifactDiv; + +/** + * Sets global variables currentlySelectedNodeTemplate and currentlySelectedDeploymentArtifactDiv + */ +function showDeploymentArtifactInformation(nodeTemplateId, deploymentArtifactName) { + currentlySelectedNodeTemplate = nodeTemplateId; + var daDiv = $("#" + nodeTemplateId).children("div.deploymentArtifactsContainer").children("div.content").children("div.deploymentArtifact").children("div.name:contains(" + deploymentArtifactName + ")").parent(); + currentlySelectedDeploymentArtifactDiv = daDiv; + var xml = daDiv.children("textarea").val(); + + // get values to display directly from the "UI" instead of parsing the XML and asking the server for appropriate names + var daArtifactTemplateName = daDiv.children("div.artifactTemplate").text(); + var daArtifactTypeName = daDiv.children("div.artifactType").text(); + + // determine URLs + require(["winery-support-common"], function(wsc) { + xmlDoc = wsc.getDocument(xml); + da = xmlDoc.firstChild; + + $("#DAname").text(deploymentArtifactName); + + $("#DAArtifactType").text(daArtifactTypeName); + addHref($("#DAArtifactType"), "artifacttypes", "artifactType", da); + + var at = $("#DAArtifactTemplate"); + if (daArtifactTemplateName != "") { + at.text(daArtifactTemplateName); + addHref(at, "artifacttemplates", "artifactRef", da); + } else { + at.text("No template associated"); + at.removeAttr("href"); + } + + $("#DAXML").val(xml); + + $("#DeploymentArtifactInfo").modal("show"); + }); +} + +/** + * Adds the given data to the deployment artifacts table of the currently active node template + * + * @param xmlAsDOM XML DOM document, TDeploymentArtifact. Produced by org.eclipse.winery.resources.artifacts.GenericArtifactsResource.onPost(String, String, String, String, String, String, String, String) + * @param xmlAsString + */ +function addDeploymentArtifact(xmlAsDOM, xmlAsString) { + var da = xmlAsDOM.firstChild; + var daName = da.getAttribute("name"); + + // we do NOT extract artifactType / artifactTemplate from the XML, but use the user input + // showDeploymentArtifactInformation will extract its data directly from the XML without querying some input at the other HTML elements + var daArtifactTemplateName = $("#artifactTemplateName").val(); + var daArtifactTypeName = $("#artifactType option:selected").text(); + + // add information to node template shape + var daData = { + nodeTemplateId : currentlySelectedNodeTemplate, + name : daName, + xml : xmlAsString, + artifactTypeName: daArtifactTypeName + }; + if (daArtifactTemplateName != "") { + daData.artifactTemplateName = daArtifactTemplateName; + } + addDeploymentArtifactInfoToNodeTemplate(daData); +} + +function addDeploymentArtifactInfoToNodeTemplate(daData) { + require(["tmpl"], function(tmpl){ + var data = tmpl("tmpl-deploymentArtifact", daData); + var element = $("#" + currentlySelectedNodeTemplate).children(".deploymentArtifactsContainer").children(".content").children(".addDA:first"); + element.before(data); + }); +} + +/** + * This function directly accesses the fields of the dialog, because the return value of the server is XML and we do not want to parse XML + * + * @param artifactInfo = {name, interfaceName (may be undefined), operationName (may be undefined), artifactTemplate (QName, may be undefined), artifactType} + */ +function artifactAddedSuccessfully(artifactInfo) { + var typeNsAndId = getNamespaceAndLocalNameFromQName(artifactInfo.artifactType); + var artifactTemplateNSAndId; + if (artifactInfo.artifactTemplate) { + artifactTemplateNSAndId = getNamespaceAndLocalNameFromQName(artifactInfo.artifactTemplate); + } else { + artifactTemplateNSAndId = undefined; + } + + var daData = { + nodeTemplateId : currentlySelectedNodeTemplate, + name : artifactInfo.name, + artifactTypeName: typeNsAndId.localname, + artifactTypeNSAndId: typeNsAndId, + artifactTemplateName: artifactInfo.artifactTemplateName, + artifactTemplateNSAndId: artifactTemplateNSAndId + }; + require(["tmpl"], function(tmpl){ + daData.xml = tmpl("tmpl-deploymentArtifactXML", daData); + addDeploymentArtifactInfoToNodeTemplate(daData); + }); +} + +// variables used for creation of deployment artifacts +var artifactTemplateAutoCreationEnabled = true; +var syncDAnameWithATname; + +// introduced by the handling of deployment and implementation artifacts +// holds the ID only (!) +var currentlySelectedNodeTemplate; + +/** + * FIXME: this function is not updated to the the new dialog design and not included any more + * + * It should be used if the checkbox for at creation changes its checked status or if the at name is not valid + * + */ +function updateArtifactTemplateCreationEnablement(value) { + // remove field highlights + // (currently, no intelligent removal and addition is made) + $("#artifactName").removeClass("highlight"); + $("#artifactTemplateName").removeClass("highlight"); + + if (value) { + // enable it + artifactTemplateAutoCreationEnabled = true; + $("#artifactTemplateName").removeAttr("disabled"); + $("#artifactTemplateNS").removeAttr("disabled"); + $("#createWithoutFilesBtn").attr("disabled", "disabled"); + $("#createWithFilesBtn").removeAttr("disabled"); + } else { + // disable it + artifactTemplateAutoCreationEnabled = false; + $("#artifactTemplateName").attr("disabled", "disabled"); + $("#artifactTemplateNS").attr("disabled", "disabled"); + $("#createWithoutFilesBtn").removeAttr("disabled"); + $("#createWithFilesBtn").attr("disabled", "disabled"); + } +} + +function isShownNodeTemplateShapeChangeBoxes(shape) { + return (shape.find(".endpointContainer").is(":visible")); +} + +/** + * @param shape jQuery object + */ +function showNodeTemplateShapeChangeBoxes(shape) { + shape.find(".addDA").show(); + shape.children(".endpointContainer").show(); + shape.find(".addnewreqorcap").show(); + shape.find(".addnewpolicy").show(); +} + +/** + * @param shape jQuery object + */ +function hideNodeTemplateShapeChangeBoxes(shape) { + shape.find(".addDA").hide(); + shape.children(".endpointContainer").hide(); + shape.find(".addnewreqorcap").hide(); + shape.find(".addnewpolicy").hide(); +} + +// indicates if a connection is currently drawn +// used to decide whether the node template boxes should be displayed +var isInConnectionMode = false; + +function wineryMoveSelectedNodeTemplateShapes(dX, dY) { + var shapes = $("div.NodeTemplateShape.selected"); + hideNodeTemplateShapeChangeBoxes(shapes); + shapes.each(function(i, nodeTemplate) { + nodeTemplate = $(nodeTemplate); + var offset = nodeTemplate.offset(); + offset.left += dX; + offset.top += dY; + nodeTemplate.offset(offset); + }); + jsPlumb.repaint(shapes); +} + + +/** + * Simple eventing framework + * + * use + * winery.events.register(name, function) to register on an event + * and + * winery.events.fire(name) to fire all registered functions + */ + +winery = {}; +winery.events = { + _events : {}, + + /** + * Registers a function + * + * @return the registered function + */ + register : function(eventName, f) { + if (!winery.events._events[eventName]) { + winery.events._events[eventName] = {}; + } + winery.events._events[eventName][f] = f; + return f; + }, + + /** + * Fires all functions associated with the given event name + */ + fire : function(eventName) { + if (winery.events._events[eventName]) { + $.each(winery.events._events[eventName], function(index, value) { + value(); + }); + } + return true; + } +}; + +/** + * Determines whether a key combo is allowed. + * + * For instance, when a modal dialog is opened or a input is selected, DEL should not delete node template shapes + */ +function keyComboAllowed() { + return ((!$(document.activeElement).is("input")) && ($("div.modal:visible").size() == 0)); +} + +function keyComboAllowedAndNodeTemplatesSelected() { + return (keyComboAllowed() && ($("div.NodeTemplateShape.selected").size() != 0)); +} + + + + +/* list of event names */ +winery.events.name = {}; +winery.events.name.command = {}; + +winery.events.name.SELECTION_CHANGED = "selectionchanged"; +winery.events.name.command.SELECT_ALL_NODETEMPLATES = "selectAllNodeTemplates"; +winery.events.name.command.UNSELECT_ALL_NODETEMPLATES = "unselectAllNodeTemplates"; +winery.events.name.command.DELETE_SELECTION = "deleteSelection"; + +winery.events.name.command.MOVE_DOWN = "moveDown"; +winery.events.name.command.MOVE_UP = "moveUp"; +winery.events.name.command.MOVE_LEFT = "moveLeft"; +winery.events.name.command.MOVE_RIGHT = "moveRight"; + +winery.events.name.command.SAVE = "save"; + diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared/README.md b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared/README.md new file mode 100644 index 0000000..4cb255e --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared/README.md @@ -0,0 +1 @@ +This folder is shared between repository and topology modeler
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared/dialogs.jsp b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared/dialogs.jsp new file mode 100644 index 0000000..21a7fec --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/shared/dialogs.jsp @@ -0,0 +1,83 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Oliver Kopp - initial API and implementation and/or initial documentation + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> + +<script> +/** + * Displays a nice message box with "yes" and "no" + * + * TODO: currently cannot be recursively called + * + * @param msg Message to display + * @param fnOnYes function to be called if user presses "yes" + * @param title (optional) title of the dialog + */ +function vConfirmYesNo(msg, fnOnYes, title) { + title = title || "Please confirm"; + $("#diagyesnotitle").text(title); + $("#diagyesnomsg").text(msg); + $("#diagyesnoyesbtn").off("click"); + $("#diagyesnoyesbtn").on("click", function() { + var diag = $("#diagyesno"); + // quick hack to get fnOnYes() working -> use the hidden.bs.modal event + diag.on("hidden.bs.modal", function() { + fnOnYes(); + diag.off("hidden.bs.modal"); + }); + diag.modal("hide"); + }); + $("#diagyesno").modal("show"); +} + +$(function() { + $("#diagyesno").on("shown.bs.modal", function() { + $("#diagyesnoyesbtn").focus(); + }); +}); +</script> + +<div class="modal fade z1051" id="diagyesno"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title" id="diagyesnotitle"></h4> + </div> + <div class="modal-body"> + <p id="diagyesnomsg"></p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">No</button> + <button id="diagyesnoyesbtn" type="button" class="btn btn-primary">Yes</button> + </div> + </div> + </div> +</div> + +<div class="modal fade z1060" id="diagmessage"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title" id="diagmessagetitle"></h4> + </div> + <div class="modal-body" id="diagmessagemsg"> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button> + </div> + </div> + </div> +</div> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/selectionHandler.jsp b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/selectionHandler.jsp new file mode 100644 index 0000000..81758a4 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/selectionHandler.jsp @@ -0,0 +1,25 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This JSP file adds Node and RelationshipTemplates to a topology XML String using the JAXBHelper class. + * After the java method has finished, the completed topology XML String is returned. + */ +%> +<%@page import="org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.JAXBHelper"%> + +<% + String topologyXML = JAXBHelper.addTemplatesToTopology(request.getParameter("topology"), request.getParameter("allChoices"), request.getParameter("selectedNodeTemplates"), request.getParameter("selectedRelationshipTemplates")); +%> + +<%=topologyXML%>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/topologyCompletion.jsp b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/topologyCompletion.jsp new file mode 100644 index 0000000..6e7f006 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/topologyCompletion.jsp @@ -0,0 +1,175 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This JSP calls the topology completion and handles the response. + * It is called the event handler when "Complete Topology" is selected in the EnterCompletionInformationDiag. + * There are several possible responses from the completion: + * - the topology is complete: display a success message + * - the topology is complete, several solutions exist: display dialog to choose topology solution + * - topology completion interrupted: the user has to chose inserted Node or Relationship Templates + */ +%> + +<%@page import="java.io.StringWriter"%> +<%@page import="java.util.List"%> +<%@page import="java.util.Map"%> +<%@page import="javax.xml.bind.Marshaller"%> +<%@page import="javax.xml.bind.JAXBContext"%> +<%@page import="javax.xml.bind.JAXBException"%> +<%@page import="org.eclipse.winery.model.tosca.Definitions"%> +<%@page import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TServiceTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TTopologyTemplate"%> +<%@page import="org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.CompletionInterface"%> + +<%@taglib prefix="tc" tagdir="/WEB-INF/tags/common/topologycompletion"%> + +<% + // parse Strings from the request to Boolean values + boolean stepByStep = Boolean.parseBoolean(request.getParameter("stepByStep")); + boolean restarted = Boolean.parseBoolean(request.getParameter("restarted")); + boolean overwriteTopology = Boolean.parseBoolean(request.getParameter("overwriteTopology")); + + // call the topology completion component which will return a message if it was successful. + CompletionInterface completionInterface = new CompletionInterface(); + String message = completionInterface.complete(request.getParameter("topology"), request.getParameter("stName"), request.getParameter("templateURL"), overwriteTopology, request.getParameter("topologyName"), request.getParameter("topologyNamespace"), request.getParameter("repositoryURL"), stepByStep, restarted); + + if (message.equals("success")) { %> + <script> vShowSuccess('Completion Successful!'); </script> + <% + } else if (message.equals("topologyComplete") && !restarted) { %> + <script> + vShowSuccess('The topology is already complete.'); + </script> + <% + } else if (message.equals("failure")) { + %> + <p> <%=completionInterface.getErrorMessage()%> </p> + <%} else if (message.equals("userInteraction")) { + + // a user interaction is necessary to choose RelationshipTemplates, receive + // the current topology and the choices from the CompletionInterface + // and display them via relationshipTemplateSelector.jsp + + TTopologyTemplate currentTopology = completionInterface.getCurrentTopology(); + List<TEntityTemplate> relationshipTemplateSelection = completionInterface.getRelationshipTemplateChoices(); + + ///////////////////////////////////////////////////// + // Convert JAXB objects of the topology and the + // Relationship Templates to be chosen to XML Strings + ///////////////////////////////////////////////////// + + Definitions definitions = new Definitions(); + TServiceTemplate serviceTemplate = new TServiceTemplate(); + + serviceTemplate.setTopologyTemplate(currentTopology); + definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(serviceTemplate); + JAXBContext context = JAXBContext.newInstance(Definitions.class); + Marshaller marshaller = context.createMarshaller(); + StringWriter currentTopologyString = new StringWriter(); + + marshaller.marshal(definitions, currentTopologyString); + + TTopologyTemplate topologyTemplate = new TTopologyTemplate(); + + // add all choices to a TopologyTemplate + for (TEntityTemplate entityTemplate: relationshipTemplateSelection) { + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(entityTemplate); + } + + // get the choices as XML + definitions = new Definitions(); + serviceTemplate = new TServiceTemplate(); + serviceTemplate.setTopologyTemplate(topologyTemplate); + definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(serviceTemplate); + context = JAXBContext.newInstance(Definitions.class); + StringWriter choicesAsXMLString = new StringWriter(); + + marshaller.marshal(definitions, choicesAsXMLString); + %> + <script> + var topology = "<%=currentTopologyString.toString()%>"; + var choices = "<%=choicesAsXMLString.toString()%>"; + </script> + <!-- call the relationshipTemplateSelector tag to render the selection to graphic objects --> + <tc:relationshipTemplateSelector choices='<%=relationshipTemplateSelection%>' templateURL='<%=request.getParameter("templateURL")%>' topologyName='<%=request.getParameter("topologyName")%>' + topologyNamespace='<%=request.getParameter("topologyNamespace")%>' repositoryURL='<%=request.getParameter("repositoryURL")%>' stName='<%=request.getParameter("stName")%>' /> + <%} else if (message.equals("userTopologySelection")) { + // there are several topology solutions. Receive the choices from the CompletionInterface + // and display them via topologyTemplateSelector.tag + List<TTopologyTemplate> topologyTemplateSelection = completionInterface.getTopologyTemplateChoices(); + %> + <!-- call the topologyTemplateSelector tag to render the selection to graphic objects --> + <tc:topologyTemplateSelector solutionTopologies='<%=topologyTemplateSelection%>' templateURL='<%=request.getParameter("templateURL")%>' topologyName='<%=request.getParameter("topologyName")%>' + topologyNamespace='<%=request.getParameter("topologyNamespace")%>' repositoryURL='<%=request.getParameter("repositoryURL")%>' /> + <% + } else if (message.equals("stepByStep")) { + + // the topology completion is processed step-by-step. The user has to choose inserted Node and RelationshipTemplates + TTopologyTemplate currentTopology = completionInterface.getCurrentTopology(); + Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> nodeTemplateSelection = completionInterface.getNodeTemplateChoices(); + + /////////////////////////////////////////////// + // Convert JAXB objects of the topology and the + // Templates to be chosen to XML Strings + /////////////////////////////////////////////// + + Definitions definitions = new Definitions(); + TServiceTemplate serviceTemplate = new TServiceTemplate(); + serviceTemplate.setTopologyTemplate(currentTopology); + definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(serviceTemplate); + JAXBContext context = JAXBContext.newInstance(Definitions.class); + Marshaller marshaller = context.createMarshaller(); + StringWriter currentTopologyString = new StringWriter(); + + marshaller.marshal(definitions, currentTopologyString); + + // add all choices to a TopologyTemplate + TTopologyTemplate topologyTemplate = new TTopologyTemplate(); + + for (TNodeTemplate nodeTemplate: nodeTemplateSelection.keySet()) { + Map<TNodeTemplate, List<TEntityTemplate>> entityTemplates = nodeTemplateSelection.get(nodeTemplate); + + for (TNodeTemplate entity: entityTemplates.keySet()) { + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(entity); + topologyTemplate.getNodeTemplateOrRelationshipTemplate().addAll(entityTemplates.get(entity)); + } + topologyTemplate.getNodeTemplateOrRelationshipTemplate().add(nodeTemplate); + } + + // get the choices as XML + definitions = new Definitions(); + serviceTemplate = new TServiceTemplate(); + serviceTemplate.setTopologyTemplate(topologyTemplate); + definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(serviceTemplate); + + StringWriter choicesAsXMLString = new StringWriter(); + + marshaller.marshal(definitions, choicesAsXMLString); + + %> + <script> + var topology = '<%=currentTopologyString.toString()%>'; + var choices = '<%=choicesAsXMLString.toString()%>'; + </script> + <!-- call the tc:nodeTemplateSelector tag to render the selection to graphic objects --> + <tc:nodeTemplateSelector choices='<%=nodeTemplateSelection%>' templateURL='<%=request.getParameter("templateURL")%>' topologyName='<%=request.getParameter("topologyName")%>' + topologyNamespace='<%=request.getParameter("topologyNamespace")%>' repositoryURL='<%=request.getParameter("repositoryURL")%>' stName='<%=request.getParameter("stName")%>' /> + <%} +%> + +<script> + var message = "<%=message%>"; +</script> diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/topologySaver.jsp b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/topologySaver.jsp new file mode 100644 index 0000000..671baee --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/jsp/topologyCompletion/topologySaver.jsp @@ -0,0 +1,50 @@ +<% +/******************************************************************************* + * Copyright (c) 2013 Pascal Hirmer. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Pascal Hirmer - initial API and implementation + *******************************************************************************/ + +/** + * This JSP saves a topology template to the repository using the RESTHelper class. + * It is called when there are several topology solutions which shall be saved in different locations. + */ +%> +<%@page import="org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.RESTHelper"%> +<%@page import="java.io.StringReader"%> +<%@page import="javax.xml.bind.JAXBContext"%> +<%@page import="javax.xml.bind.JAXBException"%> +<%@page import="javax.xml.bind.Unmarshaller"%> +<%@page import="org.eclipse.winery.model.tosca.Definitions"%> +<%@page import="org.eclipse.winery.model.tosca.TServiceTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TTopologyTemplate"%> + +<% + String xmlString = request.getParameter("topology"); + String templateURL = request.getParameter("templateURL"); + String repositoryURL = request.getParameter("repositoryURL"); + + // initiate JaxB context + JAXBContext context; + context = JAXBContext.newInstance(Definitions.class); + StringReader reader = new StringReader(xmlString); + + // unmarshall the topology XML string + Unmarshaller um = context.createUnmarshaller(); + Definitions jaxBDefinitions = (Definitions) um.unmarshal(reader); + TServiceTemplate st = (TServiceTemplate) jaxBDefinitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0); + TTopologyTemplate toBeSaved = st.getTopologyTemplate(); + + // depending on the selected save method (overwrite or create new) the save method is called + if (request.getParameter("overwriteTopology").equals("true")) { + RESTHelper.saveCompleteTopology(toBeSaved, templateURL, true, "", "", repositoryURL); + } else { + RESTHelper.saveCompleteTopology(toBeSaved, templateURL, false, request.getParameter("topologyName"), request.getParameter("topologyNamespace"), repositoryURL); + } +%>
\ No newline at end of file diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/logback.xml b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/logback.xml new file mode 100644 index 0000000..6602380 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/logback.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line %method - %msg%n</pattern> + </encoder> + </appender> + + <logger name="org.eclipse.winery" level="DEBUG"/> + + <root level="info"> + <appender-ref ref="STDOUT" /> + </root> +</configuration> diff --git a/winery/org.eclipse.winery.topologymodeler/src/test/java/.gitkeep b/winery/org.eclipse.winery.topologymodeler/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/test/java/.gitkeep diff --git a/winery/pom.xml b/winery/pom.xml new file mode 100644 index 0000000..c6a5859 --- /dev/null +++ b/winery/pom.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/******************************************************************************* + * Copyright (c) 2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Tobias Unger - initial API and implementation and/or initial documentation + * Oliver Kopp - refinements + * Tobias Binz - Adds support for building fatJars (including all dependencies) and profile for fatJars + *******************************************************************************/ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.winery</groupId> + <artifactId>winery</artifactId> + <version>0.1.37-SNAPSHOT</version> + <packaging>pom</packaging> + <name>Winery</name> + <description>Winery is a Web-based environment to graphically model TOSCA topologies and plans managing these topologies.</description> + <url>http://www.eclipse.org/winery</url> + <organization> + <name>Eclipse.org - Winery Project</name> + <url>http://www.eclipse.org/winery</url> + </organization> + <issueManagement> + <system>bugzilla</system> + <url>https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Winery</url> + </issueManagement> + <inceptionYear>2012</inceptionYear> + <mailingLists> + <mailingList> + <name>Winery Developer List</name> + <post>winery-dev@eclipse.org</post> + <archive>http://dev.eclipse.org/mhonarc/lists/winery-dev</archive> + </mailingList> + </mailingLists> + <licenses> + <license> + <name>Eclipse Public License v1.0</name> + <url>http://www.eclipse.org/legal/epl-v10.html</url> + <distribution>repo</distribution> + <comments>Standard Eclipse Licence</comments> + </license> + <license> + <name>Apache License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0</url> + <distribution>repo</distribution> + </license> + </licenses> + <scm> + <developerConnection>scm:git:http://git.eclipse.org/gitroot/winery/org.eclipse.winery.winery.git/</developerConnection> + <tag>HEAD</tag> + </scm> + <prerequisites> + <maven>3.0.3</maven> + </prerequisites> + <modules> + <module>org.eclipse.winery.model.tosca</module> + <module>org.eclipse.winery.model.csar.toscametafile</module> + <module>org.eclipse.winery.model.selfservice</module> + <module>org.eclipse.winery.generators.ia</module> + <module>org.eclipse.winery.common</module> + <module>org.eclipse.winery.repository</module> + <module>org.eclipse.winery.repository.client</module> + <module>org.eclipse.winery.topologymodeler</module> + </modules> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>versions-maven-plugin</artifactId> + <version>2.1</version> + </plugin> + </plugins> + </build> +</project> |