├── public ├── images │ └── newapp-icon.png ├── javascript │ ├── ie10-viewport-bug-workaround.js │ ├── asTest.js │ ├── utils.js │ └── bootstrap.min.js └── stylesheets │ ├── starter-template.css │ ├── style.css │ └── cyborg-bootstrap.min.css ├── w3c.json ├── manifest.yml ├── README.txt ├── CODE_OF_CONDUCT.md ├── README.md ├── package.json ├── config ├── config.js └── msgs.js ├── server.js ├── views ├── response.ejs └── index.ejs ├── LICENSE └── routes └── routes.js /public/images/newapp-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/activitystreams-testing/HEAD/public/images/newapp-icon.png -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": 72531, 3 | "contacts": [ 4 | "plehegar" 5 | ], 6 | "policy": "open", 7 | "repo-type": "tests" 8 | } -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - disk_quota: 1024M 3 | host: as-test-harness 4 | name: as-test-harness 5 | path: . 6 | domain: mybluemix.net 7 | instances: 1 8 | memory: 256M 9 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | # W3C Social Web Working Group - Activity Streams 2.0 Test Harness 2 | 3 | This is a work-in-progress test harness for the Activity Streams 2.0 4 | specification. 5 | 6 | Additional detail to be added. -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # W3C Social Web Working Group - Activity Streams 2.0 Test Harness 2 | 3 | This is a work-in-progress test harness for the Activity Streams 2.0 4 | specification. 5 | 6 | Demo: https://as-test-harness.mybluemix.net/ 7 | 8 | Additional detail to be added. 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "as-test-harness", 3 | "version": "0.0.1", 4 | "description": "Test harness for ActivityStreams 2.0", 5 | "scripts": { 6 | "start": "node server.js" 7 | }, 8 | "dependencies": { 9 | "activitystrea.ms": "^0.1.0", 10 | "body-parser": "~1.0.0", 11 | "date-time-string": "0.0.8", 12 | "ejs": "^2.2.4", 13 | "express": "~4.0.0", 14 | "jsonld": "^0.3.22", 15 | "jsonlint": "^1.6.2", 16 | "method-override": "~1.0.0", 17 | "morgan": "~1.0.0", 18 | "request": "^2.53.0", 19 | "util": "^0.10.3" 20 | }, 21 | "engines": { 22 | "node": "0.10.*" 23 | }, 24 | "repository": {} 25 | } 26 | -------------------------------------------------------------------------------- /public/javascript/ie10-viewport-bug-workaround.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * IE10 viewport hack for Surface/desktop Windows 8 bug 3 | * Copyright 2014 Twitter, Inc. 4 | * Licensed under the Creative Commons Attribution 3.0 Unported License. For 5 | * details, see http://creativecommons.org/licenses/by/3.0/. 6 | */ 7 | // See the Getting Started docs for more information: 8 | // http://getbootstrap.com/getting-started/#support-ie10-width 9 | (function () { 10 | 'use strict'; 11 | if (navigator.userAgent.match(/IEMobile\/10\.0/)) { 12 | var msViewportStyle = document.createElement('style') 13 | msViewportStyle.appendChild( 14 | document.createTextNode( 15 | '@-ms-viewport{width:auto!important}' 16 | ) 17 | ) 18 | document.querySelector('head').appendChild(msViewportStyle) 19 | } 20 | })(); -------------------------------------------------------------------------------- /public/stylesheets/starter-template.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | } 4 | .starter-template { 5 | padding: 40px 15px; 6 | text-align: center; 7 | } 8 | 9 | /* Sticky footer styles 10 | -------------------------------------------------- */ 11 | html { 12 | position: relative; 13 | min-height: 100%; 14 | } 15 | body { 16 | /* Margin bottom by footer height */ 17 | margin-bottom: 60px; 18 | } 19 | .footer { 20 | position: absolute; 21 | bottom: 0; 22 | width: 100%; 23 | /* Set the fixed height of the footer here */ 24 | height: 60px; 25 | /* background-color: #f5f5f5;*/ 26 | } 27 | 28 | 29 | /* Custom page CSS 30 | -------------------------------------------------- */ 31 | /* Not required for template or sticky footer method. */ 32 | 33 | .container { 34 | width: auto; 35 | max-width: 680px; 36 | padding: 0 15px; 37 | } 38 | .container .text-muted { 39 | margin: 20px 0; 40 | } -------------------------------------------------------------------------------- /config/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 International Business Machines Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Configuration library for working with Activity Streams Test Harness 17 | * 18 | * @author Jacques Perrault (jacques_perrault@us.ibm.com) 19 | */ 20 | module.exports = { 21 | 'env' : { 22 | 'session' : 'GtNAokU8M5oN8Thj' 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /public/javascript/asTest.js: -------------------------------------------------------------------------------- 1 | var msgs = require('../../config/msgs'); 2 | 3 | // ===================================== 4 | // displayName 5 | // http://www.w3.org/ns/activitystreams#displayName 6 | // http://www.w3.org/TR/activitystreams-vocabulary/#dfn-displayname 7 | // ===================================== 8 | exports.asDisplayName = function(compactedDoc, callback) { 9 | if (typeof compactedDoc['displayName'] !== 'undefined') { 10 | var re = new RegExp("<|>"); 11 | if (typeof compactedDoc['displayName'] !== 'string') { 12 | callback.call(this, 500, msgs.as.displayName_mustBeString ); 13 | } 14 | 15 | if (re.test(compactedDoc['displayName'])) { 16 | callback.call(this, 500, msgs.as.displayName_noHtml ); 17 | } 18 | 19 | if (compactedDoc['displayNameMap'] !== undefined) { 20 | callback.call(this, 300, msgs.as.displayName_useNaturalLanguageForm ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | /* style.css 2 | * This file provides css styles. 3 | */ 4 | 5 | body,html { 6 | background-color: #3b4b54; width : 100%; 7 | height: 100%; 8 | margin: 0 auto; 9 | font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; 10 | color: #ffffff; 11 | } 12 | 13 | a { 14 | text-decoration: none; 15 | color: #00aed1; 16 | } 17 | 18 | a:hover { 19 | text-decoration: underline; 20 | } 21 | 22 | img { 23 | padding-top: 10%; 24 | display: block; 25 | margin: 0 auto; 26 | padding-bottom: 2em; 27 | max-width:200px; 28 | } 29 | 30 | h1 { 31 | font-weight: bold; 32 | font-size: 2em; 33 | } 34 | 35 | .leftHalf { 36 | float: left; 37 | background-color: #26343f; 38 | width: 45%; 39 | height: 100%; 40 | } 41 | 42 | .rightHalf { 43 | float: right; 44 | width: 55%; 45 | background-color: #313f4a; 46 | height: 100%; 47 | overflow:auto; 48 | } 49 | 50 | .blue { 51 | color: #00aed1; 52 | } 53 | 54 | 55 | table { 56 | table-layout: fixed; 57 | width: 800px; 58 | margin: 0 auto; 59 | word-wrap: break-word; 60 | padding-top:10%; 61 | } 62 | 63 | th { 64 | border-bottom: 1px solid #000; 65 | } 66 | 67 | th, td { 68 | text-align: left; 69 | padding: 2px 20px; 70 | } 71 | 72 | .env-var { 73 | text-align: right; 74 | border-right: 1px solid #000; 75 | width: 30%; 76 | } 77 | 78 | pre { 79 | padding: 0; 80 | margin: 0; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /config/msgs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 International Business Machines Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Messages library for working with Activity Streams Test Harness 17 | * 18 | * @author Jacques Perrault (jacques_perrault@us.ibm.com) 19 | */ 20 | module.exports = { 21 | 'json': { 22 | 'invalid': 'JSON is invalid.' 23 | }, 24 | 'jsonld' : { 25 | 'invalid': 'JSON-LD is invalid.' 26 | }, 27 | 'as': { 28 | 'results': 'Validation results', 29 | 'nodefs': 'Could not retieve Activity Stream definitions', 30 | 'valid': 'ActivityStream is valid', 31 | 'import': 'ActivityStream import failed', 32 | 'displayName_noHtml': 'HTML markup MUST NOT be included in displayName', 33 | 'displayName_mustBeString': 'displayName must be a string', 34 | 'displayName_useNaturalLanguageForm': 'ActivityStream contains displayName and displayNameMap vocabulary terms. Consider collapsing the JSON string form (displayName) into the natural language form (displayNameMap)' 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /public/javascript/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 International Business Machines Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Utility library for working with Activity Streams Test Harness 17 | * 18 | * @author Jacques Perrault (jacques_perrault@us.ibm.com) 19 | */ 20 | $(function() { 21 | 22 | $("#validate").on("click", function(event){ 23 | var $form = $("#activitystreamForm"); 24 | var postData = $form.serialize(); 25 | var jqxhr = $.post("/validate", postData, function() { 26 | // wait for the promise to be filled before populating result field 27 | }) 28 | .done(function(data) { 29 | var obj = JSON.parse(data); 30 | if (obj.result[0].code === 200) { 31 | $("#alerts").removeClass().addClass('alert alert-success').html(decodeURI(obj.result[0].message)); 32 | return false; 33 | } 34 | 35 | if (obj.result[0].code === 300) { 36 | $("#alerts").removeClass().addClass('alert alert-warning').html(decodeURI(obj.result[0].message)); 37 | return false; 38 | } 39 | 40 | else { 41 | $("#alerts").removeClass().addClass('alert alert-danger').html(decodeURI(obj.result[0].message)); 42 | return false; 43 | } 44 | }) 45 | .fail(function() { 46 | var message = 'Error communicating with validator.'; 47 | $("#alerts").removeClass().addClass('alert alert-danger').html(message); 48 | return false; 49 | }) 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | 3 | // app.js 4 | // This file contains the server side JavaScript code for your application. 5 | // This sample application uses express as web application framework (http://expressjs.com/), 6 | // and jade as template engine (http://jade-lang.com/). 7 | 8 | var express = require('express'); 9 | var morgan = require('morgan'); 10 | var bodyParser = require('body-parser'); 11 | var methodOverride = require('method-override'); 12 | var app = express(); 13 | var config = require('./config/config'); 14 | 15 | app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users 16 | app.use(morgan('dev')); // log every request to the console 17 | app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded 18 | app.use(bodyParser.json()) // parse application/json 19 | app.use(methodOverride()); // simulate DELETE and PUT 20 | 21 | app.engine('html', require('ejs').renderFile); 22 | app.set('views', __dirname + '/views'); 23 | app.set('host', process.env.VCAP_APP_HOST || 'localhost'); // The IP address of the Cloud Foundry DEA (Droplet Execution Agent) that hosts this application 24 | app.set('port', process.env.VCAP_APP_PORT || '3000'); // The port on the DEA for communication with the application 25 | 26 | var appInfo = JSON.parse(process.env.VCAP_APPLICATION || "{}"); // VCAP_APPLICATION contains useful information about a deployed application. 27 | // TODO: Get application information and use it in your app. 28 | 29 | // VCAP_SERVICES contains all the credentials of services bound to 30 | // this application. For details of its content, please refer to 31 | // the document or sample of each service. 32 | var services = JSON.parse(process.env.VCAP_SERVICES || "{}"); 33 | // TODO: Get service credentials and communicate with bluemix services. 34 | app.set('view engine', 'ejs'); 35 | 36 | 37 | 38 | 39 | // routes ====================================================================== 40 | require('./routes/routes.js')(app, config); // load our routes and pass in our app, config 41 | 42 | 43 | // Start server 44 | app.listen(app.get('port'), app.get('host')); 45 | console.log('App started on ' + app.get('host') + ':' + app.get('port')); 46 | 47 | 48 | process.on( 'SIGINT', function() { 49 | console.log( "\nGracefully shutting down from SIGINT (Ctrl-C)" ); 50 | process.exit( ); 51 | }) -------------------------------------------------------------------------------- /views/response.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ActivityStreams 2.0 Test Harness 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | 47 | 48 |
49 |
50 |
51 | 52 |
><%= alert %>
53 |
><%- data %>
54 |
55 |
56 |
57 | 58 | 63 | 64 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ActivityStreams 2.0 Test Harness 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | 47 | 48 |
49 |
50 |
51 |
52 |
53 | 54 |
55 | URL 56 | 57 |
58 |
59 |
60 |
61 |
Copy/paste the URLs below into the field above, or provide your own URL to an ActivityStream:
62 |
as:Activity (invalid)
63 | 64 |
65 |
66 |
67 | 68 | 73 | 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2013 OpenSocial Foundation 190 | Copyright 2013 International Business Machines Corporation 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | -------------------------------------------------------------------------------- /routes/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 International Business Machines Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Node routes for working with Activity Streams Test Harness 17 | * 18 | * @author Jacques Perrault (jacques_perrault@us.ibm.com) 19 | */ 20 | module.exports = function(app, config) { 21 | 22 | var request = require('request'); // Simplified HTTP client 23 | var DateTime = require('date-time-string'); // data/time formatting 24 | var jsonlint = require('jsonlint'); // nicer err msgs than JSON.parse 25 | var as = require('activitystrea.ms'); 26 | var jsonld = require('jsonld'); 27 | var msgs = require('../config/msgs'); 28 | var asTest = require('../public/javascript/asTest') 29 | 30 | // ===================================== 31 | // LOG ALL REQUESTS ==================== 32 | // ===================================== 33 | app.all('*', function(req, res, next) { 34 | console.log(Date.now() + " - remote ip: " + req.connection.remoteAddress + " received request to " + req.url); 35 | next(); 36 | }); 37 | 38 | // ===================================== 39 | // HOME PAGE =========================== 40 | // ===================================== 41 | app.get('/', function(req, res) { 42 | res.render('index.ejs'); 43 | }); 44 | 45 | // ===================================== 46 | // VALIDATE ============================ 47 | // ===================================== 48 | app.post('/validate', function(req, res) { 49 | // FETCH THE ACTIVITYSTREAM SPEC 50 | var asVocab = {}; 51 | var importedDoc = {}; 52 | var expandedDoc = {}; 53 | var flattenedDoc = {}; 54 | var jsonDoc = {}; 55 | var baseURI = 'http://www.w3.org/ns/activitystreams#'; 56 | 57 | request.get(baseURI, function (error, response, body) { 58 | if (!error && response.statusCode == 200) { 59 | asVocab = JSON.parse(body); 60 | 61 | // FETCH DATA FROM THE ENDPOINT 62 | request.get(req.body.activitystreamIRI, function (error, response, body) { 63 | if (!error && response.statusCode == 200) { 64 | var content = body; 65 | console.log('RAW DATA from ' + req.body.activitystreamIRI); 66 | console.log(content); 67 | 68 | // VALIDATE JSON 69 | try { 70 | var jsonDoc = jsonlint.parse(content); 71 | } catch (error) { 72 | sendResult(500, msgs.json.invalid, error.message.replace(/\n/g,'
'), res); 73 | // TODO return(next) handling to cease validation 74 | } 75 | 76 | // VALIDATE JSON-LD 77 | as.import(jsonDoc, function(err,imported) { 78 | if (err !== null) { 79 | sendResult(500, msgs.as.import, err.message.replace(/\n/g,'
'), res); 80 | // TODO return(next) handling to cease validation 81 | } else { 82 | importedDoc = imported; 83 | 84 | // VALIDATE ACTIVITYSTREAM DEFAULT MAPPINGS 85 | expandedDoc = importedDoc._expanded; 86 | console.log('EXPANDED: ' + JSON.stringify(expandedDoc)); 87 | var result = ''; 88 | result = getTypes(jsonDoc, expandedDoc, baseURI); 89 | console.log(result); 90 | 91 | // ===================================== 92 | // VALIDATE Core Vocabulary Terms ====== 93 | // ===================================== 94 | /* asTest.asDisplayName(compacted, function(code, alert){ 95 | sendResult(code, alert, content, res); 96 | }); 97 | */ 98 | // All tests passed, send a friendly message 99 | sendResult(200, msgs.as.results, result.replace(/\n/g,'
'), res); 100 | } 101 | }) 102 | } 103 | }) 104 | // unable to retrieve ActivityStream vocabulary specification 105 | } else { 106 | if (error === null) { 107 | sendResult(500, msgs.as.nodefs, '', res); 108 | } else { 109 | sendResult(500, msgs.as.nodefs, error.message.replace(/\n/g,'
'), res); 110 | } 111 | } 112 | }) 113 | }); 114 | 115 | 116 | function getTypes(jsonObject, expandedObject, baseURI) { 117 | var result = ''; 118 | for (property in jsonObject) { 119 | if (property !== '@context' ) { 120 | if (property === '@type') { 121 | // VALIDATE ACTIVITY TYPE MAPPING 122 | //console.log('VALIDATE @TYPE: ' + jsonObject[property]); 123 | result += validateActivityType(jsonObject[property], expandedObject, baseURI) 124 | } else if (property === '@id') { 125 | // ignore @id 126 | } else { 127 | if (typeof jsonObject[property] === 'object') { 128 | // VALIDATE OBJECT TYPE MAPPING 129 | //console.log('VALIDATE OBJECT: ' + property); 130 | result += validateObjectOrPropertyType(property, expandedObject, baseURI) 131 | //console.log('ENTERING NESTED OBJECT: ' + property); 132 | // then iterate through the object 133 | result += getTypes(jsonObject[property], expandedObject[baseURI + property][0], baseURI); 134 | } else { 135 | // VALIDATE PROPERTY MAPPING 136 | //console.log('VALIDATE PROPERTY: ' + property); 137 | result += validateObjectOrPropertyType(property, expandedObject, baseURI) 138 | } 139 | } 140 | } 141 | } 142 | return result; 143 | }; 144 | 145 | function validateActivityType(activityType, expandedObject, baseURI) { 146 | var result = ''; 147 | var shouldMatch = baseURI + activityType; 148 | var beingMatched = expandedObject["@type"][0] 149 | if (beingMatched === shouldMatch) { 150 | result = '"' + activityType + '" matches the ActivityStream Activity Type: ' + shouldMatch + '\n'; 151 | } else { 152 | result = '-----------------' + '\n'; 153 | result += 'Implementers are not permitted to change the default mappings of the core properties and types' + '\n'; 154 | result += 'Raw activity type: ' + activityType + '\n'; 155 | result += 'Expanded value: ' + expandedObject["@type"][0] + '\n'; 156 | result += 'Normative value: ' + shouldMatch + '\n'; 157 | result += '-----------------' + '\n'; 158 | } 159 | console.log(result); 160 | return result; 161 | } 162 | 163 | 164 | function validateObjectOrPropertyType(activityType, expandedObject, baseURI) { 165 | var result = ''; 166 | var shouldMatch = baseURI + activityType; 167 | if (expandedObject.hasOwnProperty(shouldMatch)) { 168 | result = '"' + activityType + '" matches the ActivityStream Object Type: ' + shouldMatch + '\n'; 169 | } else { 170 | result = '-----------------' + '\n'; 171 | result += 'Implementers are not permitted to change the default mappings of the core properties and types' + '\n'; 172 | result += 'Raw activity type: ' + activityType + '\n'; 173 | result += 'Expanded value: ' + expandedObject["@type"][0] + '\n'; 174 | result += 'Normative value: ' + shouldMatch + '\n'; 175 | result += '-----------------' + '\n'; 176 | } 177 | //console.log(result); 178 | return result; 179 | } 180 | 181 | 182 | // ===================================== 183 | // RESULTS ============================= 184 | // ===================================== 185 | function sendResult(code, alert, data, res) { 186 | var bsclass = ''; 187 | switch (code) { 188 | case 200: 189 | bsclass = 'class="alert alert-success"'; 190 | break; 191 | case 300: 192 | bsclass = 'class="alert alert-warning"'; 193 | break; 194 | case 500: 195 | bsclass = 'class="alert alert-danger"'; 196 | break; 197 | default: 198 | bsclass = 'class="alert alert-success"'; 199 | break; 200 | } 201 | res.status(200).render('response.ejs', { bsclass: bsclass, alert: alert, data: data }); 202 | } 203 | 204 | // ===================================== 205 | // JSON (INVALID) ====================== 206 | // ===================================== 207 | app.get('/json/0001', function(req, res) { 208 | res.status(200).send('{test: "false"}'); 209 | }); 210 | // ===================================== 211 | // JSON-LD (INVALID) =================== 212 | // ===================================== 213 | app.get('/jsonld/0001', function(req, res) { 214 | var obj = '{"@context": "http://asjsonld.mybluemix.net","object": {"@id": "http://example.org","@reverse": "http://example.com"}}'; 215 | res.status(200).send(obj); 216 | }); 217 | // ===================================== 218 | // as:Activity ========================= 219 | // ===================================== 220 | app.get('/asActivity/0001', function(req, res) { 221 | var obj = '{"@context": "http://www.w3.org/ns/activitystreams#Like","@type": "Like","actor": {"@type": "Person","displayName": "Sally"},"object": {"@type": "Note","displayName": "A Note"}}'; 222 | res.status(200).send(obj); 223 | }); 224 | app.get('/asActivity/0002', function(req, res) { 225 | var obj = '{"@context": ["http://asjsonld.mybluemix.net",{"Assign": "http://foo/Bar"}],"@type": "Assign"}'; 226 | res.status(200).send(obj); 227 | }); 228 | // ===================================== 229 | // AS displayName (invalid / object) === 230 | // ===================================== 231 | app.get('/asdisplayName/0001', function(req, res) { 232 | var obj = '{"@context":"http://dandus.mybluemix.net/context","@id":"http://dandus.mybluemix.net/r/res1428409632038","@type":"Announce","actor":{"@id":"acct:workflow@example.org","@type":"Application"},"displayName": {"key": "Announce: Reassigned patient"},"object":{"@type":"Assign","actor":"acct:workflow@example.org","object":{"@id":"acct:33333","@type":"Person"},"target":{"@id":"acct:11111","@type":"Person"}},"published":"2015-04-07T12:27:12.048Z","summary":"Reassigned patient Jane to doctor Dr. Samantha.","updated":"2015-04-07T12:27:12.048Z"}'; 233 | res.status(200).send(obj); 234 | }); 235 | // ===================================== 236 | // AS displayName (invalid / HTML) ===== 237 | // ===================================== 238 | app.get('/asdisplayName/0002', function(req, res) { 239 | var obj = '{"@context":"http://dandus.mybluemix.net/context","@id":"http://dandus.mybluemix.net/r/res1428409632038","@type":"Announce","actor":{"@id":"acct:workflow@example.org","@type":"Application"},"displayName": "Announce: Reassigned patient","object":{"@type":"Assign","actor":"acct:workflow@example.org","object":{"@id":"acct:33333","@type":"Person"},"target":{"@id":"acct:11111","@type":"Person"}},"published":"2015-04-07T12:27:12.048Z","summary":"Reassigned patient Jane to doctor Dr. Samantha.","updated":"2015-04-07T12:27:12.048Z"}'; 240 | res.status(200).send(obj); 241 | }); 242 | // ===================================== 243 | // AS displayName w/ displayNameMap ==== 244 | // ===================================== 245 | app.get('/asdisplayName/0003', function(req, res) { 246 | var obj = '{"@context":"http://dandus.mybluemix.net/context","@id":"http://dandus.mybluemix.net/r/res1428409632038","@type":"Announce","actor":{"@id":"acct:workflow@example.org","@type":"Application"},"displayNameFull": "bob","displayName":"Announce: Reassigned patient","displayNameMap": {"en": "A simple note","sp": "Una simple nota"},"object":{"@type":"Assign","actor":"acct:workflow@example.org","object":{"@id":"acct:33333","@type":"Person"},"target":{"@id":"acct:11111","@type":"Person"}},"published":"2015-04-07T12:27:12.048Z","summary":"Reassigned patient Jane to doctor Dr. Samantha.","updated":"2015-04-07T12:27:12.048Z"}'; 247 | res.status(200).send(obj); 248 | }); 249 | } 250 | -------------------------------------------------------------------------------- /public/javascript/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.2 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.2",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.2",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.2",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.2",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('