├── .gitignore ├── doc ├── gltf.png └── cesium.png ├── .jshintrc ├── routes ├── index.js └── convert.js ├── working └── .gitignore ├── .settings ├── org.eclipse.core.resources.prefs └── com.eclipsesource.jshint.ui.prefs ├── collada2gltf ├── mac │ └── collada2gltf └── win32 │ └── collada2gltf.exe ├── config.json ├── server.js ├── nodemon.json ├── lib ├── Verbose.js ├── createGuid.js ├── Errors.js ├── nconf.js └── collada2gltf.js ├── .project ├── app.js ├── test ├── convert │ └── index.js └── data │ └── box.dae ├── package.json ├── README.md └── LICENSE.md /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | .DS_Store 3 | Thumbs.db -------------------------------------------------------------------------------- /doc/gltf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CesiumGS/collada2gltf-web-service/HEAD/doc/gltf.png -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "predef": [ 4 | "describe", 5 | "it" 6 | ] 7 | } -------------------------------------------------------------------------------- /doc/cesium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CesiumGS/collada2gltf-web-service/HEAD/doc/cesium.png -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | convert : require('./convert') 5 | }; -------------------------------------------------------------------------------- /working/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/.jshintrc=UTF-8 3 | -------------------------------------------------------------------------------- /collada2gltf/mac/collada2gltf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CesiumGS/collada2gltf-web-service/HEAD/collada2gltf/mac/collada2gltf -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "host" : "localhost", 3 | "port" : 3000, 4 | "verbose" : true, 5 | "uploadLimit" : "10mb" 6 | } -------------------------------------------------------------------------------- /.settings/com.eclipsesource.jshint.ui.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | included=//*.js 3 | projectSpecificOptions=true 4 | -------------------------------------------------------------------------------- /collada2gltf/win32/collada2gltf.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CesiumGS/collada2gltf-web-service/HEAD/collada2gltf/win32/collada2gltf.exe -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var app = require('./app'); 2 | var nconf = require('./lib/nconf'); 3 | 4 | app.listen(nconf.get('port'), function() { 5 | console.log('Server started: http://%s:%s', nconf.get('host'), nconf.get('port')); 6 | }); -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "verbose": true, 3 | "ignore": [ 4 | ".git", 5 | "doc", 6 | "working", 7 | "README.md", 8 | "LICENSE.md" 9 | ], 10 | "watch": [ 11 | "**/*.js", 12 | "config.json" 13 | ] 14 | } -------------------------------------------------------------------------------- /routes/convert.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var collada2gltf = require('./../lib/collada2gltf.js'); 3 | 4 | module.exports.convert = function(req, res, next) { 5 | collada2gltf(req.body, function(err, gltf) { 6 | if (err) { return next(err); } 7 | 8 | res.setHeader('Content-Type', 'application/json'); 9 | res.send(gltf); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /lib/Verbose.js: -------------------------------------------------------------------------------- 1 | var nconf = require('./nconf'); 2 | 3 | var verbose = !!nconf.get('verbose'); 4 | var f = function(arg) {}; 5 | 6 | // Timing, log, and error messages based on the verbose flag in config.json 7 | module.exports = { 8 | log : verbose ? function(message) { console.log(message); } : f, 9 | error : verbose ? function(message) { console.error(message); } : f, 10 | time : verbose ? function(label) { console.time(label); } : f, 11 | timeEnd : verbose ? function(label) { console.timeEnd(label); } : f 12 | }; -------------------------------------------------------------------------------- /lib/createGuid.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = createGuid; 4 | 5 | //From https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Core/createGuid.js 6 | function createGuid() { 7 | // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript 8 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 9 | var r = Math.random() * 16 | 0; 10 | var v = c === 'x' ? r : (r & 0x3 | 0x8); 11 | return v.toString(16); 12 | }); 13 | } -------------------------------------------------------------------------------- /lib/Errors.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | // Module based on https://github.com/alexyoung/nodeinpractice/tree/master/listings/web/error-handling 4 | 5 | function HTTPError() { 6 | Error.call(this, arguments); 7 | } 8 | 9 | util.inherits(HTTPError, Error); 10 | 11 | function Conversion(message) { 12 | HTTPError.call(this); 13 | Error.captureStackTrace(this, arguments.callee); 14 | this.statusCode = 500; 15 | this.message = message; 16 | this.name = 'Conversion'; 17 | } 18 | util.inherits(Conversion, HTTPError); 19 | 20 | module.exports = { 21 | HTTPError: HTTPError, 22 | Conversion: Conversion 23 | }; -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | collada2gltf-web-service 4 | 5 | 6 | 7 | 8 | 9 | com.eclipsesource.jshint.ui.builder 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 1426521625155 19 | 20 | 30 21 | 22 | org.eclipse.ui.ide.multiFilter 23 | 1.0-name-matches-false-false-node_modules 24 | 25 | 26 | 27 | 1426521625161 28 | 29 | 30 30 | 31 | org.eclipse.ui.ide.multiFilter 32 | 1.0-name-matches-false-false-working 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /lib/nconf.js: -------------------------------------------------------------------------------- 1 | var nconf = require('nconf'); 2 | 3 | // This module wraps nconf to make sure it is initialized before being used 4 | 5 | // Override options in this order: config.json < environment variables < command-line arguments 6 | nconf.argv() 7 | .env() 8 | .file({ file: 'config.json' }); 9 | 10 | // Set the path to the collada2gltf executable based on the platform unless 11 | // a path was already defined in config.json 12 | if (!nconf.get('collada2gltfPath')) { 13 | if (process.platform === 'darwin') { 14 | nconf.set('collada2gltfPath', 'collada2gltf/mac/collada2gltf'); 15 | } else if (process.platform === 'win32') { 16 | nconf.set('collada2gltfPath', 'collada2gltf/win32/collada2gltf.exe'); 17 | } else { 18 | console.error('Only Mac and Windows builds of collada2gltf are included. Build from source for your platform: https://github.com/KhronosGroup/glTF'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | module.exports = nconf; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var compression = require('compression'); 4 | var routes = require('./routes'); 5 | var nconf = require('./lib/nconf'); 6 | var Verbose = require('./lib/Verbose'); 7 | 8 | var app = express(); 9 | 10 | // Requests post the .dae file using Content-Type: text/plain 11 | // The upload filesize limit is defined in config.json 12 | app.use(bodyParser.text({ 13 | limit : nconf.get('uploadLimit') 14 | })); 15 | 16 | // compress 17 | app.use(compression()); 18 | 19 | // Custom middleware fore enabling CORS. From http://enable-cors.org/server_expressjs.html 20 | app.use(function(req, res, next) { 21 | res.header("Access-Control-Allow-Origin", "*"); 22 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 23 | next(); 24 | }); 25 | 26 | // Custom middleware for handling errors 27 | app.use(function(err, req, res, next) { 28 | Verbose.error(err.stack); 29 | 30 | res.status(err.statusCode || 500); 31 | res.format({ 32 | json: function() { 33 | res.send(err); 34 | } 35 | }); 36 | }); 37 | 38 | // Map, for example, localhost:3000/convert, to the function that does the conversion. 39 | // There is also app.get() for requests that pass parameters with GET. 40 | app.post('/convert', routes.convert.convert); 41 | 42 | module.exports = app; -------------------------------------------------------------------------------- /test/convert/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var fs = require('fs'); 3 | var assert = require('assert'); 4 | var request = require('supertest'); 5 | var app = require('./../../app'); 6 | 7 | describe('convert', function(){ 8 | it('convert a COLLADA model', function(done) { 9 | fs.readFile('test/data/box.dae', 'utf8', function(err, dae) { 10 | if (err) { return done(err); } 11 | 12 | request(app) 13 | .post('/convert') 14 | .set('Content-Type', 'text/plain') 15 | .send(dae) 16 | .expect('Content-Type', /json/) 17 | .expect(200) 18 | .end(function(err, res){ 19 | if (err) throw err; 20 | 21 | // Quick and dirty check for glTF 22 | assert(res.body.accessors); 23 | assert(res.body.bufferViews); 24 | assert(res.body.buffers); 25 | assert(res.body.materials); 26 | assert(res.body.meshes); 27 | assert(res.body.nodes); 28 | assert(res.body.programs); 29 | assert(res.body.scene); 30 | assert(res.body.scenes); 31 | assert(res.body.shaders); 32 | assert(res.body.techniques); 33 | done(); 34 | }); 35 | }); 36 | }); 37 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "collada2gltf-web-service", 3 | "version": "0.0.1", 4 | "description": "Simple web service to convert 3D models from COLLADA to glTF using COLLADA2GLTF.", 5 | "license": "Apache-2.0", 6 | "author": { 7 | "name": "Patrick Cozzi", 8 | "email": "pcozzi@agi.com", 9 | "url": "https://twitter.com/pjcozzi" 10 | }, 11 | "keywords": [ 12 | "collada", 13 | "gltf" 14 | ], 15 | "homepage": "https://github.com/AnalyticalGraphicsInc/collada2gltf-web-service", 16 | "repository": { 17 | "type": "git", 18 | "url": "git@github.com:AnalyticalGraphicsInc/collada2gltf-web-service.git" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/AnalyticalGraphicsInc/collada2gltf-web-service/issues" 22 | }, 23 | "scripts": { 24 | "test": "mocha test/**/*.js", 25 | "jshint": "jshint app.js server.js lib routes test" 26 | }, 27 | "directories": {}, 28 | "dependencies": { 29 | "body-parser": "^1.12.0", 30 | "compression": "^1.4.3", 31 | "express": "^4.12.2", 32 | "nconf": "^0.7.1", 33 | "rimraf": "^2.3.2" 34 | }, 35 | "devDependencies": { 36 | "jshint": "^2.6.0", 37 | "mocha": "^2.1.0", 38 | "nodemon": "^1.3.7", 39 | "supertest": "^0.15.0" 40 | }, 41 | "engines": { 42 | "node": ">=0.10.x" 43 | }, 44 | "jshintConfig": { 45 | "node": true, 46 | "predef": [ 47 | "describe", 48 | "it" 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # collada2gltf-web-service 2 | 3 |

4 | 5 |

6 | 7 | Simple web service to convert 3D models from COLLADA to glTF using [COLLADA2GLTF](https://github.com/KhronosGroup/glTF). 8 | 9 | ## Overview 10 | 11 | This is a code sample that is a starting point for a Node.js web service that converts COLLADA models to 12 | glTF. This version just converts a .dae file to a .gltf with embedded geometry, animations, skins, and shaders. It does not handle textures. 13 | 14 | ## Install 15 | 16 | Clone this repo. Install [Node.js](http://nodejs.org/). From this repo's root directory, run: 17 | ``` 18 | npm install 19 | ``` 20 | 21 | ## Usage 22 | 23 | Start the server: 24 | ``` 25 | npm start 26 | ``` 27 | 28 | Invoke the web service by issuing an HTTP request and providing the COLLADA model with POST: 29 | ``` 30 | curl -X POST -H "Content-Type:text/plain" -d @test/data/box.dae localhost:3000/convert 31 | ``` 32 | 33 | A few settings can be changed by modifying [config.json](config.json). This is loaded using [nconf](https://www.npmjs.com/package/nconf) so environment variables and command-line arguments can override this. 34 | 35 | ## Development and Testing 36 | 37 | To automatically restart the server during development, install and run [nodemon](http://nodemon.io/): 38 | ``` 39 | npm install nodemon -g 40 | nodemon server.js 41 | ``` 42 | 43 | Install and run [JSHint](http://jshint.com/): 44 | ``` 45 | npm install jshint -g 46 | npm run jshint 47 | ``` 48 | 49 | Install [mocha](http://mochajs.org/) and run the tests: 50 | ``` 51 | npm install mocha -g 52 | npm test 53 | ``` 54 | 55 | ## COLLADA2GLTF builds 56 | 57 | Build are in the [collada2gltf](collada2gltf) directory. They are currently version 0.8 from [here](https://github.com/KhronosGroup/glTF/wiki/Converter-builds). 58 | 59 | ## Resources 60 | 61 | * [9 uses for cURL worth knowing](http://httpkit.com/resources/HTTP-from-the-Command-Line/) 62 | * [nodeinpractice](https://github.com/alexyoung/nodeinpractice) - book and sample code 63 | 64 | *** 65 | 66 | Developed by AGI, founders of the Cesium WebGL engine. 67 |

68 | 69 |

70 | -------------------------------------------------------------------------------- /lib/collada2gltf.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var child_process = require('child_process'); 5 | var rimraf = require('rimraf'); 6 | var Errors = require('./Errors'); 7 | var Verbose = require('./Verbose'); 8 | var createGuid = require('./createGuid'); 9 | var nconf = require('./nconf'); 10 | 11 | module.exports = collada2gltf; 12 | 13 | function returnError(err, dirPath, message, callback) { 14 | rimraf(dirPath, function(err) { 15 | if (err) { Verbose.error(err.message); } 16 | 17 | process.nextTick(function() { 18 | Verbose.timeEnd('total time'); 19 | callback(new Errors.Conversion(message + ': ' + err.message), undefined); 20 | }); 21 | }); 22 | 23 | return undefined; 24 | } 25 | 26 | function collada2gltf(collada, callback) { 27 | // 1. Create a temporary directory 28 | // 2. Write the input COLLADA file to the directory 29 | // 3. Run collada2gltf with -e to embed resources 30 | // 4. Read the generated glTF file 31 | // -> Remove the temporary directory on success or failure 32 | 33 | Verbose.time('total time'); 34 | 35 | var dirPath = path.join('working', createGuid()); 36 | fs.mkdir(dirPath, undefined, function(err) { 37 | if (err) { return returnError(err, dirPath, '1/5 mkdir', callback); } 38 | 39 | var daePath = path.join(dirPath, 'input.dae'); 40 | var gltfPath = path.join(dirPath, 'output.gltf'); 41 | 42 | fs.writeFile(daePath, collada, function(err) { 43 | if (err) { return returnError(err, dirPath, '2/5 writeFile', callback); } 44 | 45 | Verbose.time('collada2gltf time'); 46 | 47 | child_process.execFile(nconf.get('collada2gltfPath'), [ 48 | '-f', daePath, 49 | '-o', gltfPath, 50 | '-e'], 51 | function(err, stdout, stderr) { 52 | Verbose.timeEnd('collada2gltf time'); 53 | Verbose.log('collada2gltf stdout: ' + stdout); 54 | Verbose.log('collada2gltf stderr: ' + stderr); 55 | 56 | if (err) { return returnError(err, dirPath, '3/5 execFile', callback); } 57 | 58 | fs.readFile(gltfPath, 'utf8', function(err, data){ 59 | if (err) { return returnError(err, dirPath, '4/5 readFile', callback); } 60 | 61 | rimraf(dirPath, function(err) { 62 | if (err) { return returnError(err, dirPath, '5/5 rimraf', callback); } 63 | 64 | process.nextTick(function() { 65 | Verbose.timeEnd('total time'); 66 | callback(undefined, data); 67 | }); 68 | }); 69 | }); 70 | }); 71 | }); 72 | }); 73 | } 74 | -------------------------------------------------------------------------------- /test/data/box.dae: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | modo 801 [Build 77509], Microsoft Windows 7 Service Pack 1 (6.1.7601 Service Pack 1) 6 | Plug-in: [Build 77509]; Use Absolute Path: No; Merge Reference Items: No; Save Hidden Items: No; Save Cameras: No; Save Lights: No; Save Locators: Yes; Save Triangles as Triangles: Yes; Order Vertex Maps Alphabetically: Yes; Bake Matrices: No; Save Vertex Normals: Yes; Save UV Texture Coordinates: Yes; Save Vertex Colors: No; Save Vertex Weights: No; Save Animation: Yes; Sample Animation: No; Sample Animation Start: 0; Sample Animation End: 120; Save modo Profile: No; Save Maya Profile: No; Save 3ds Max Profile: No; Formatted Arrays: No; 7 | file:///C:/Users/Branden/Creative%20Cloud%20Files/03-2015%20Cesium%20Test%20Models/CesiumBoxTest.lxo 8 | 9 | 2015-03-04T16:39:37Z 10 | 2015-03-04T16:39:37Z 11 | Z_UP 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 0.8 0 0 1 25 | 26 | 27 | 0.2 0.2 0.2 1 28 | 29 | 30 | 256 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 0.5 0.5 0.5 -0.5 0.5 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 0 0 1 0 -1 0 1 0 0 0 1 0 -1 0 0 0 0 -1 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0.25 1 0.25 0.666667 0.5 1 0.5 0.666667 0 0.666667 0.25 0.333333 0 0.333333 0.5 0.333333 0.75 0.666667 0.75 0.333333 1 0.666667 1 0.333333 0.25 0 0.5 0 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |

4 0 0 7 0 1 5 0 2 6 0 3 5 0 2 7 0 1 7 1 1 4 1 4 3 1 5 0 1 6 3 1 5 4 1 4 6 2 3 7 2 1 2 2 7 3 2 5 2 2 7 7 2 1 5 3 8 6 3 3 1 3 9 2 3 7 1 3 9 6 3 3 4 4 10 5 4 8 0 4 11 1 4 9 0 4 11 5 4 8 0 5 12 1 5 13 3 5 5 2 5 7 3 5 5 1 5 13

77 |
78 |
79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2015-2017 Analytical Graphics, Inc. and Contributors 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "{}" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright 2015-2017 Analytical Graphics, Inc. and Contributors 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | 205 | Third-Party Code 206 | ================ 207 | 208 | ### Node.js in Practice 209 | 210 | > https://github.com/alexyoung/nodeinpractice 211 | 212 | > The MIT License (MIT) 213 | 214 | > Copyright (c) 2014 Alex Young 215 | 216 | > Permission is hereby granted, free of charge, to any person obtaining a copy 217 | > of this software and associated documentation files (the "Software"), to deal 218 | > in the Software without restriction, including without limitation the rights 219 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 220 | > copies of the Software, and to permit persons to whom the Software is 221 | > furnished to do so, subject to the following conditions: 222 | 223 | > The above copyright notice and this permission notice shall be included in all 224 | > copies or substantial portions of the Software. 225 | 226 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 227 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 228 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 229 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 230 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 231 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 232 | > SOFTWARE. 233 | --------------------------------------------------------------------------------