├── .gitignore ├── LICENSE ├── README.rst ├── docs ├── density.json ├── for-scale-objects.json └── open-a-file.json ├── gulpfile.js ├── index.html ├── js ├── client.js ├── common.js ├── controls.js ├── gh-loader.js ├── laslaz.js ├── render.js ├── ui.js └── util.js ├── less ├── bootstrap-theme.min.css ├── bootstrap.min.css ├── jquery.nouislider.min.css ├── layout-default-latest.css └── style.less ├── package-lock.json ├── package.json ├── resources ├── assets │ └── circle.png ├── colormaps │ ├── awesome-green.png │ ├── black-orange.png │ ├── blue-hue.png │ ├── blue-orange.png │ ├── blue-red.png │ ├── heat-map.png │ └── pestel-shades.png ├── data │ └── .gitignore ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── iowa │ ├── css │ │ └── style.css │ ├── index.html │ ├── js │ │ ├── plasio-lib.js │ │ ├── plasio-renderer.js │ │ └── react.js │ └── plasio_ui.min.js ├── jslaz │ └── index.html ├── nepal │ ├── hobu.png │ ├── index.html │ ├── lib │ │ └── dist │ │ │ ├── laz-perf.js │ │ │ └── plasio-lib.js │ ├── plasio-renderer.js │ └── workers │ │ └── decompress.js ├── plasio_laszip.nmf ├── plasio_laszip.pexe └── scale-objects │ └── EmpireStateBuilding │ ├── Brick_Antique.jpg │ ├── Brick_Colored_Blue.jpg │ ├── Color_000.jpg │ ├── Color_001.jpg │ ├── Color_001_1_.jpg │ ├── Color_001_2_.jpg │ ├── Color_006.jpg │ ├── EmpireStateBuilding.bin │ ├── EmpireStateBuilding.js │ ├── _Brick_Antique_1.jpg │ ├── _Brick_Colored_Blue_2.jpg │ ├── _Brick_Colored_Blue_3.jpg │ ├── _Brick_Rough_Dark_1.jpg │ ├── _Color_001_1.jpg │ ├── _Color_005_2.jpg │ ├── _Color_005_3.jpg │ ├── _Color_005_5.jpg │ ├── _Color_006_3.jpg │ └── _Color_009_1.jpg ├── test ├── MIT.LICENSE ├── index.html ├── lib │ └── jasmine-2.0.3 │ │ ├── boot.js │ │ ├── console.js │ │ ├── jasmine-html.js │ │ ├── jasmine.css │ │ ├── jasmine.js │ │ └── jasmine_favicon.png └── spec │ ├── gh-reader-test.js │ └── specs.js ├── vendor ├── bluebird.js ├── bootstrap.min.js ├── closure-compiler │ └── compiler.jar ├── controls │ └── TrackballControls.js ├── jquery.js ├── jquery.layout.js ├── jquery.nouislider.min.js ├── jquery.ui.js ├── laz-perf.js ├── loaders │ └── BinaryLoader.js ├── lodash.min.js └── three.js └── workers ├── laz-loader-worker.js └── laz-perf.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | pnacl_test*.* 3 | build/ 4 | node_modules/ 5 | *.iml 6 | .idea/ 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Uday Verma, uday.karan@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | plasio 2 | ------------------------------------------------------------------------------- 3 | 4 | plasio is a project by `Uday Verma`_ and `Howard Butler`_ that implements point 5 | cloud rendering capability in a browser. Specifically, it provides a functional 6 | implementation of the `ASPRS LAS`_ format, and it can consume 7 | `LASzip`_-compressed data using LASzip `NaCl`_ module. Plasio is `Chrome`_-only at 8 | this time, but it is hoped that other contributors can step forward to bring it 9 | to other browsers. 10 | 11 | It is expected that most WebGL-capable browers should be 12 | able to support plasio, and it contains nothing that is explicitly Chrome-specific beyond the optional NaCL LASzip module. We just haven't tested it beyond `Mac and Windows Chrome Canary`_ at this time. 13 | 14 | 15 | Demo 16 | ............................................................................... 17 | 18 | http://plas.io contains a demo of the interface and supports both LAS and LAZ. 19 | 20 | FAQ 21 | ............................................................................... 22 | 23 | What does the name plasio mean? 24 | 25 | Nothing. 26 | 27 | What are future plans for the software? 28 | 29 | We hope that plasio provides a significant enough capability that others 30 | start to contribute exploitation and visualization flourishes. 31 | 32 | When will it support X, Y, or Z? 33 | 34 | The software is its formative stages at this point, and pull 35 | requests that provide new capabilities or fix signficant issues 36 | are going to be the most persuasive way to impact its future 37 | development. 38 | 39 | Developers 40 | ............................................................................... 41 | Plasio uses the Gulp_ build system:: 42 | 43 | npm install -g gulp 44 | 45 | To setup the development environment, you can run:: 46 | 47 | npm install 48 | 49 | This will download all dependencies required to setup the build system. 50 | 51 | You can then build and stage files under the ``build`` directory by running:: 52 | 53 | gulp 54 | 55 | While developing, you may run:: 56 | 57 | gulp develop 58 | 59 | This will serve built files locally and open your default browser pointing to the index page. Any changes you make to 60 | source files will fire gulp tasks that will keep the ``build`` directory up to date. The build system also uses 61 | gulp's live-reload plugin, which works great with `Google Chrome's Live Reload`_ extension. 62 | 63 | The gulp file includes a task to publish directly to plas.io, however, you need AWS Access for that to work. You may direct plasio 64 | to your own AWS buckets, in which case you will have to edit ``gulpfile.js`` to direct it likewise. 65 | 66 | The publish task looks for ``~/.aws.json`` which should include two fields, ``key`` and ``secret``. 67 | 68 | To publish to AWS simply run:: 69 | 70 | gulp publish 71 | 72 | 73 | Credits 74 | ............................................................................... 75 | 76 | - Blue Marker Icon from `Function Icons`_ By `Liam McKay`_ 77 | - High precision GPU point picking wouldn't have been possible without the `Work done here`_. 78 | - `Carlos Scheidegger`_ for GPU float to bytes conversion. 79 | 80 | 81 | License 82 | ............................................................................... 83 | 84 | The software is licensed under the permissive `MIT`_ license. 85 | 86 | .. _`Howard Butler`: http://github.com/hobu 87 | .. _`Uday Verma`: http://github.com/verma 88 | .. _`Mazira`: http://www.mazira.com 89 | .. _`ASPRS LAS`: http://www.asprs.org/Committee-General/LASer-LAS-File-Format-Exchange-Activities.html 90 | .. _`Chrome`: https://www.google.com/intl/en/chrome/browser/ 91 | .. _`LASzip`: http://laszip.org 92 | .. _`NaCl`: https://developers.google.com/native-client/dev/ 93 | .. _`MIT`: http://opensource.org/licenses/MIT 94 | .. _`Mac and Windows Chrome Canary`: https://www.google.com/intl/en/chrome/browser/canary.html 95 | .. _`Gulp`: http://gulpjs.com/ 96 | .. _`Google Chrome's Live Reload`: https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=en 97 | .. _`Function Icons`: https://www.iconfinder.com/search/?q=iconset:function_icon_set 98 | .. _`Liam McKay`: http://wefunction.com/contact/ 99 | .. _`Work done here`: http://concord-consortium.github.io/lab/experiments/webgl-gpgpu/webgl.html 100 | .. _`Carlos Scheidegger`: http://www.khronos.org/webgl/public-mailing-list/archives/1206/msg00233.html 101 | -------------------------------------------------------------------------------- /docs/density.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Setting the load Density", 3 | "summary": "The Density Slider allows you to load your LAS/LAZ file from 10% to 100% of the total points.", 4 | "video": "/docs/videos/density.webm", 5 | "tags": [ 6 | { 7 | "title": "Low Density", 8 | "offset": 0 9 | }, 10 | { 11 | "title": "High Density", 12 | "offset": 11 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /docs/for-scale-objects.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "For Scale Objects", 3 | "summary": "For scale objects provide perspective into the scale of your data.", 4 | "video": "/docs/videos/for-scale-objects.webm", 5 | "tags": [ 6 | { 7 | "title": "Place Objects", 8 | "offset": 0 9 | }, 10 | { 11 | "title": "Clear Objects", 12 | "offset": 13 13 | }, 14 | { 15 | "title": "Change Units", 16 | "offset": 17 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /docs/open-a-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Opening a LAS/LAZ file", 3 | "summary": "Note that LAZ file loading is only available in Google Chrome", 4 | "video": "/docs/videos/open-a-file.webm", 5 | "tags": [ 6 | { 7 | "title": "Browse", 8 | "offset": 0 9 | }, 10 | { 11 | "title": "Drag-n-Drop", 12 | "offset": 9 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | //gulp & plugins 2 | var gulp = require('gulp'); 3 | 4 | var jshint = require('gulp-jshint'); 5 | var less = require('gulp-less'); 6 | var concat = require('gulp-concat'); 7 | var uglify = require('gulp-uglify'); 8 | var rename = require('gulp-rename'); 9 | var browserify = require('gulp-browserify'); 10 | var nodemon = require('gulp-nodemon'); 11 | var gutil = require('gulp-util'); 12 | var watch = require('gulp-watch'); 13 | var livereload = require('gulp-livereload'); 14 | var clean = require('gulp-clean'); 15 | var awspublish = require('gulp-awspublish'); 16 | var uglify = require('gulp-uglify'); 17 | var htmlreplace = require('gulp-html-replace'); 18 | var react = require('gulp-react'); 19 | 20 | var connect = require('connect'); 21 | var http = require('http'); 22 | var open = require('open'); 23 | var path = require('path'); 24 | var logger = require('morgan'); 25 | var serveStatic = require('serve-static'); 26 | 27 | var execFile = require('child_process').execFile; 28 | var fs = require('fs'); 29 | 30 | /** 31 | * Tasks: 32 | * 33 | * build (default): 34 | * builds the client into ./dist 35 | * 36 | * develop: 37 | * builds client, and runs auto reloading dev server 38 | * 39 | * lint: 40 | * lint all javascript sourcefiles 41 | * 42 | * test: 43 | * run mocha tests in ./test/ 44 | * 45 | * debug: 46 | * like develop but also runs tests and linting 47 | */ 48 | 49 | gulp.task('default', ['build']); 50 | gulp.task('build', ['css', 'less', 'bad-scripts', 'workers', 'lint', 'scripts', 'resources', 'html', 'docs']); 51 | gulp.task('develop', ['build', 'serve', 'livereload']); 52 | gulp.task('tdd', ['serve-specs', 'livereload-tests']); 53 | 54 | 55 | /** 56 | * path globs / expressions for targets below 57 | */ 58 | 59 | var paths = { 60 | main : 'js/client.js', 61 | sources : 'js/**/*.js', 62 | jsx : 'js/**/*.jsx', 63 | specs : 'test/spec/specs.js', 64 | badScripts: ['vendor/bluebird.js', 'vendor/laz-perf.js'], 65 | workers: 'workers/**', 66 | resources: 'resources/**', 67 | css : 'less/**/*.css', 68 | less : 'less/style.less', 69 | jade : 'client/**/*.jade', 70 | html : '*.html', 71 | docs : 'docs/**/*', 72 | build : './build/' 73 | }; 74 | 75 | 76 | //clean build directory 77 | gulp.task('clean', function(){ 78 | return gulp.src(paths.client.build, {read: false} ) 79 | .pipe(clean()); 80 | }); 81 | 82 | gulp.task('resources', function() { 83 | return gulp.src(paths.resources) 84 | .pipe(gulp.dest(paths.build)); 85 | }); 86 | 87 | // lint all of our js source files 88 | gulp.task('lint', function (){ 89 | return gulp.src(paths.sources) 90 | .pipe(jshint({ 91 | "smarttabs": true, 92 | "linter": require("jshint-jsx").JSXHINT 93 | })) 94 | .pipe(jshint.reporter('default')); 95 | }); 96 | 97 | var startServer = function(path, cb) { 98 | var devApp, devServer, devAddress, devHost, url, log=gutil.log, colors=gutil.colors; 99 | devApp = connect(); 100 | devApp.use(logger()); 101 | devApp.use(serveStatic(path)); 102 | devServer = http.createServer(devApp).listen(8000); 103 | devServer.on('error', function(error) { 104 | log(colors.underline(colors.red('ERROR'))+' Unable to start server!'); 105 | cb(error); 106 | }); 107 | 108 | devServer.on('listening', function() { 109 | devAddress = devServer.address(); 110 | devHost = devAddress.address === '0.0.0.0' ? 'localhost' : devAddress.address; 111 | url = 'http://' + devHost + ':' + devAddress.port + '/' + 'index.html'; 112 | 113 | log(''); 114 | log('Started dev server at '+colors.magenta(url)); 115 | open(url); 116 | cb(); 117 | }); 118 | }; 119 | 120 | gulp.task('serve', ['build'], function(cb) { 121 | startServer('build', cb); 122 | }); 123 | 124 | gulp.task('serve-specs', ['build-specs'], function(cb) { 125 | startServer('test', cb); 126 | }); 127 | 128 | gulp.task('watch', ['build'], function() { 129 | // watch all our dirs and reload if any build stuff changes 130 | // 131 | gulp.watch(paths.sources, ['lint', 'scripts']); 132 | gulp.watch(paths.html, ['html']); 133 | gulp.watch(paths.less, ['less']); 134 | gulp.watch(paths.docs, ['docs']); 135 | gulp.watch(paths.workers, ['workers']); 136 | gulp.watch(paths.resources, ['resources']); 137 | }); 138 | 139 | gulp.task('livereload', ['watch'], function() { 140 | livereload.listen(); 141 | }); 142 | 143 | gulp.task('livereload-tests', ['watch-specs'], function() { 144 | livereload.listen(); 145 | }); 146 | 147 | gulp.task('bad-scripts', function() { 148 | return gulp.src(paths.badScripts) 149 | .pipe(concat("bad.js")) 150 | .pipe(gulp.dest(paths.build)); 151 | }); 152 | 153 | // build client side js app 154 | gulp.task('build-specs', function(){ 155 | return gulp.src([paths.specs]) 156 | .pipe(browserify()) 157 | .on("error", gutil.log) 158 | .on("error", gutil.beep) 159 | .pipe(gulp.dest("test/build")); 160 | }); 161 | 162 | 163 | gulp.task('watch-specs', function() { 164 | gulp.watch([paths.sources, 'test/spec/**/*.js'], ['build-specs']); 165 | }); 166 | 167 | // build client side js app 168 | gulp.task('scripts', function(){ 169 | return gulp.src([paths.main, paths.jsx]) 170 | .pipe(browserify({ 171 | debug: gulp.env.production, 172 | transform: ['reactify'] 173 | })) 174 | .on("error", gutil.log) 175 | .on("error", gutil.beep) 176 | .pipe(gulp.dest(paths.build)); 177 | }); 178 | 179 | gulp.task('css', function() { 180 | return gulp.src(paths.css). 181 | pipe(concat('all.css')). 182 | pipe(gulp.dest(path.join(paths.build, 'css'))); 183 | }); 184 | 185 | gulp.task('less', function() { 186 | return gulp.src(paths.less). 187 | pipe(less({ 188 | paths: ['./less/'] 189 | })). 190 | pipe(gulp.dest(path.join(paths.build, 'css'))); 191 | }); 192 | 193 | gulp.task('html', function() { 194 | return gulp.src(paths.html). 195 | pipe(gulp.dest(paths.build)); 196 | }); 197 | 198 | gulp.task('clean', function() { 199 | return gulp.src(paths.build, { read: false }) 200 | .pipe(clean()); 201 | }); 202 | 203 | gulp.task('optimize', ['build'], function(cb) { 204 | var input = path.join(paths.build, 'client.js'); 205 | var tmp = path.join(paths.build, 'client.tmp.js'); 206 | 207 | execFile('java', [ 208 | '-jar', 'vendor/closure-compiler/compiler.jar', 209 | '--js', input, 210 | '--language_in', 'ECMASCRIPT5', 211 | '--compilation_level', 'SIMPLE_OPTIMIZATIONS', 212 | '--js_output_file', tmp], 213 | {maxBuffer: (1000*4096)}, 214 | function(err, stdout, stderr) { 215 | if (err) 216 | return cb(err); 217 | 218 | fs.unlinkSync(input); 219 | fs.renameSync(tmp, input); 220 | 221 | cb(); 222 | }); 223 | }); 224 | 225 | gulp.task('docs', function() { 226 | return gulp.src(paths.docs). 227 | pipe(gulp.dest(path.join(paths.build, 'docs'))); 228 | }); 229 | 230 | gulp.task('workers', function() { 231 | return gulp.src(paths.workers). 232 | pipe(gulp.dest(path.join(paths.build, 'workers'))); 233 | }); 234 | 235 | gulp.task('prod-build', ['build', 'optimize']); 236 | 237 | gulp.task('publish', ['prod-build'], function() { 238 | var homeDir = process.env['HOME']; 239 | var settings = require(path.join(homeDir, ".aws.json")); 240 | 241 | settings.bucket = "plas.io"; 242 | 243 | var publisher = awspublish.create(settings); 244 | 245 | return gulp.src(paths.build + "/**/*") 246 | .pipe(publisher.publish()) 247 | .pipe(publisher.sync()) 248 | .pipe(awspublish.reporter()); 249 | }); 250 | 251 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | plas.io 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 |
14 |
15 |
plas.io
16 |
Sorry, your browser does not support WebGL. Find out more.
17 |
18 |
19 | 21 | 22 | 27 |
28 |
29 |
30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 |

plas.io

39 | Fork me on GitHub 40 |
41 |
42 | 43 |
44 |

File

45 |
46 |
47 | 48 |
49 | 50 |

Choose data to display

51 |
Pick your own or click the dropdown for some examples
52 | 55 |
56 | 59 | 63 | 72 |
73 |
74 | 77 | 83 |
84 | 85 |
86 | 87 |

Density

88 |
Set the load density. Smaller values load and display faster. 89 | Reopen the file to load at new density.
90 |
91 |
92 |
93 | 107 | 108 |
109 |

For scale objects

110 | 111 |
Place the Empire State Building by ALT (OPTION on Mac OS X) + Double-Clicking anywhere on the point cloud.
112 | 113 |
Change your world units so that for-scale object sizes are still relevant
114 |
115 | 117 | 122 |
123 |
124 |
125 |
126 | 127 |
128 |
129 |

Camera

130 |
131 |
132 |
133 |

Type

134 |
Perspective camera provides a 3D view, while orthographic and top-view cameras provide an ortho views
135 |
136 | 137 | 138 | 139 |
140 |

Reset

141 |
Take view back to its initial state
142 | 143 |

Field of View

144 |
Changing Field of View provides interesting effects, only applies to Perspective Cameras
145 |
146 |
147 | 148 |
149 |

Clipping Regions

150 |
Choose alternate ways of viewing data
151 |
152 |
153 |
154 |
155 | 156 |
157 |
158 |

Data

159 |
160 |
161 |
162 |

Measurement

163 |
Measurement segments currently in view area
164 | 165 |
166 |
167 |
168 |
169 |

Particle Size

170 |
Larger sizes fill in the display
171 |
172 |
173 |
174 |

Z-Exaggeration

175 |
Higher values make elevation deltas more apparent
176 |
177 |
178 |
179 |

Colorization

180 |
Choose an attribute to colorize
181 |
182 | 185 | 191 |
192 |
193 |
194 |

Colormap

195 |
Color gradient values used for Heightmap Color and Classification color sources
196 | 219 |
220 | 221 |
222 |
223 |
224 |
225 |

Intensity Source

226 |
Color modulators, modulation can be played with
227 |
228 | 231 | 236 |
237 |
238 |
239 |

Intensity Blending

240 |
How much of intensity to blend with color
241 |
242 |
243 |
All Color
244 |
All Intensity
245 |
246 |
247 |
248 |

Intensity Scaling

249 |
Narrow down on a range of intensity values, only applies to intensity values fetch from point source
250 |
251 |
252 |
253 |
254 | 255 |
256 |
257 |

Utilities

258 |
259 |
260 |
261 |

Inundation

262 |
Enable an Inundation Plane and manipulate it using a slider
263 |
264 |
265 |
266 |
267 |
268 |
269 | 270 |
271 | 272 | 273 | 304 | 305 | 306 | 325 | 326 | 327 | 328 | 329 | 352 | 353 | 354 | 371 | 372 | 373 | 374 | 375 | 449 | 467 | 477 | 478 | 479 | 480 | -------------------------------------------------------------------------------- /js/client.js: -------------------------------------------------------------------------------- 1 | // client.js 2 | // Client side stuffs for greyhound web viewer 3 | // 4 | 5 | // Import all modules here even if we don't want to use them 6 | // so that browserify can pick them up 7 | var $ = require('jquery'), 8 | render = require('./render'), 9 | ui = require('./ui'), 10 | laslaz = require('./laslaz'); 11 | 12 | 13 | function endsWith(str, s) { 14 | return str.indexOf(s) === (str.length - s.length); 15 | } 16 | 17 | (function(w) { 18 | "use strict"; 19 | 20 | // The NACL module calls method on the window, make sure the laslaz module 21 | // can see messages sent by NACL 22 | // 23 | window.handleMessage = laslaz.handleMessage; 24 | 25 | // show an error message to the user 26 | // 27 | var errorOut = function(msg) { 28 | $("#messages").html("

" + msg + "

"); 29 | console.log('Error : ' + msg); 30 | }; 31 | 32 | // show a status message to the user 33 | var message = function(msg) { 34 | $("#messages").html("

" + msg + "

"); 35 | console.log('Status: ' + msg); 36 | }; 37 | 38 | $(document).on("plasio.start", function() { 39 | render.startRenderer($("#container").get(0), message); 40 | }); 41 | 42 | })(window); 43 | 44 | $(function() { 45 | setTimeout(function() { 46 | var isWebGLSupported = function() { 47 | if ("WebGLRenderingContext" in window) { 48 | // might have support 49 | // 50 | var e = document.createElement("canvas"); 51 | var webgl = e.getContext("webgl"); 52 | var experimental = false; 53 | if (webgl === null) { 54 | webgl = e.getContext("experimental-webgl"); 55 | experimental = true; 56 | } 57 | 58 | return [webgl !== null, experimental]; 59 | } 60 | 61 | return false; 62 | }; 63 | 64 | // if we're good to go, trigger the plasio.start event, all initializers 65 | // should be hooked to this event, and not DOMContentLoaded 66 | // 67 | var r = isWebGLSupported(); 68 | var supported = r[0]; 69 | var experimental = r[1]; 70 | if(supported) { 71 | $(".fullscreen").fadeOut(200); 72 | // we need to intialize the UI first, before we initialize everything else, 73 | // since UI has to show results and statuses about things as they initialize 74 | // 75 | $.event.trigger({ 76 | type: "plasio.startUI" 77 | }); 78 | 79 | $.event.trigger({ 80 | type: "plasio.start" 81 | }); 82 | 83 | if (experimental) { 84 | $.event.trigger({ 85 | type: "plasio.webglIsExperimental" 86 | }); 87 | } 88 | 89 | var parseURL = function(qs) { 90 | var name = qs.match(/\?s=(\S+)/); 91 | return name ? name[1] : null; 92 | }; 93 | 94 | 95 | var figureFilename = function(path) { 96 | var i = path.lastIndexOf("/"); 97 | if (i === -1) 98 | return path; 99 | 100 | return path.substr(i+1); 101 | }; 102 | 103 | // If a URL is specified, load that now 104 | var query = window.location.search; 105 | if (query) { 106 | query = parseURL(query); 107 | if (query && query.length > 0) { 108 | $.event.trigger({ 109 | type: "plasio.loadfiles.remote", 110 | url: query, 111 | name: figureFilename(query) 112 | }); 113 | } 114 | } 115 | } 116 | else { 117 | $("#no-support").css("opacity", 1.0); 118 | } 119 | }, 1000); 120 | }); 121 | -------------------------------------------------------------------------------- /js/common.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Set to true when the Document is loaded IFF "test=true" is in the query 6 | // string. 7 | var isTest = false; 8 | 9 | // Set to true when loading a "Release" NaCl module, false when loading a 10 | // "Debug" NaCl module. 11 | var isRelease = true; 12 | 13 | // Javascript module pattern: 14 | // see http://en.wikipedia.org/wiki/Unobtrusive_JavaScript#Namespaces 15 | // In essence, we define an anonymous function which is immediately called and 16 | // returns a new object. The new object contains only the exported definitions; 17 | // all other definitions in the anonymous function are inaccessible to external 18 | // code. 19 | var common = (function() { 20 | 21 | function isHostToolchain(tool) { 22 | return tool == 'win' || tool == 'linux' || tool == 'mac'; 23 | } 24 | 25 | /** 26 | * Return the mime type for NaCl plugin. 27 | * 28 | * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. 29 | * @return {string} The mime-type for the kind of NaCl plugin matching 30 | * the given toolchain. 31 | */ 32 | function mimeTypeForTool(tool) { 33 | // For NaCl modules use application/x-nacl. 34 | var mimetype = 'application/x-pnacl'; 35 | if (isHostToolchain(tool)) { 36 | // For non-NaCl PPAPI plugins use the x-ppapi-debug/release 37 | // mime type. 38 | if (isRelease) 39 | mimetype = 'application/x-ppapi-release'; 40 | else 41 | mimetype = 'application/x-ppapi-debug'; 42 | } else if (tool == 'pnacl' && isRelease) { 43 | mimetype = 'application/x-pnacl'; 44 | } 45 | return mimetype; 46 | } 47 | 48 | /** 49 | * Check if the browser supports NaCl plugins. 50 | * 51 | * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. 52 | * @return {bool} True if the browser supports the type of NaCl plugin 53 | * produced by the given toolchain. 54 | */ 55 | function browserSupportsNaCl(tool) { 56 | // Assume host toolchains always work with the given browser. 57 | // The below mime-type checking might not work with 58 | // --register-pepper-plugins. 59 | if (isHostToolchain(tool)) { 60 | return true; 61 | } 62 | var mimetype = mimeTypeForTool(tool); 63 | return navigator.mimeTypes[mimetype] !== undefined; 64 | } 65 | 66 | /** 67 | * Inject a script into the DOM, and call a callback when it is loaded. 68 | * 69 | * @param {string} url The url of the script to load. 70 | * @param {Function} onload The callback to call when the script is loaded. 71 | * @param {Function} onerror The callback to call if the script fails to load. 72 | */ 73 | function injectScript(url, onload, onerror) { 74 | var scriptEl = document.createElement('script'); 75 | scriptEl.type = 'text/javascript'; 76 | scriptEl.src = url; 77 | scriptEl.onload = onload; 78 | if (onerror) { 79 | scriptEl.addEventListener('error', onerror, false); 80 | } 81 | document.head.appendChild(scriptEl); 82 | } 83 | 84 | /** 85 | * Run all tests for this example. 86 | * 87 | * @param {Object} moduleEl The module DOM element. 88 | */ 89 | function runTests(moduleEl) { 90 | console.log('runTests()'); 91 | common.tester = new Tester(); 92 | 93 | // All NaCl SDK examples are OK if the example exits cleanly; (i.e. the 94 | // NaCl module returns 0 or calls exit(0)). 95 | // 96 | // Without this exception, the browser_tester thinks that the module 97 | // has crashed. 98 | common.tester.exitCleanlyIsOK(); 99 | 100 | common.tester.addAsyncTest('loaded', function(test) { 101 | test.pass(); 102 | }); 103 | 104 | if (typeof window.addTests !== 'undefined') { 105 | window.addTests(); 106 | } 107 | 108 | common.tester.waitFor(moduleEl); 109 | common.tester.run(); 110 | } 111 | 112 | /** 113 | * Create the Native Client element as a child of the DOM element 114 | * named "listener". 115 | * 116 | * @param {string} name The name of the example. 117 | * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. 118 | * @param {string} path Directory name where .nmf file can be found. 119 | * @param {number} width The width to create the plugin. 120 | * @param {number} height The height to create the plugin. 121 | * @param {Object} attrs Dictionary of attributes to set on the module. 122 | */ 123 | function createNaClModule(name, tool, path, width, height, attrs) { 124 | var mimetype = mimeTypeForTool(tool); 125 | 126 | var moduleEl = document.createElement('embed'); 127 | moduleEl.setAttribute('name', 'nacl_module'); 128 | moduleEl.setAttribute('id', 'nacl_module'); 129 | moduleEl.setAttribute('width', width); 130 | moduleEl.setAttribute('height', height); 131 | moduleEl.setAttribute('path', path); 132 | moduleEl.setAttribute('src', path + '/' + name + '.nmf'); 133 | 134 | 135 | // Add any optional arguments 136 | if (attrs) { 137 | for (var key in attrs) { 138 | moduleEl.setAttribute(key, attrs[key]); 139 | } 140 | } 141 | 142 | moduleEl.setAttribute('type', mimetype); 143 | 144 | 145 | // The element is wrapped inside a
, which has both a 'load' 146 | // and a 'message' event listener attached. This wrapping method is used 147 | // instead of attaching the event listeners directly to the element 148 | // to ensure that the listeners are active before the NaCl module 'load' 149 | // event fires. 150 | var listenerDiv = document.getElementById('listener'); 151 | listenerDiv.appendChild(moduleEl); 152 | 153 | // Host plugins don't send a moduleDidLoad message. We'll fake it here. 154 | var isHost = isHostToolchain(tool); 155 | if (isHost) { 156 | window.setTimeout(function() { 157 | moduleEl.readyState = 1; 158 | moduleEl.dispatchEvent(new CustomEvent('loadstart')); 159 | moduleEl.readyState = 4; 160 | moduleEl.dispatchEvent(new CustomEvent('load')); 161 | moduleEl.dispatchEvent(new CustomEvent('loadend')); 162 | }, 100); // 100 ms 163 | } 164 | 165 | // This is code that is only used to test the SDK. 166 | if (isTest) { 167 | var loadNaClTest = function() { 168 | injectScript('nacltest.js', function() { 169 | runTests(moduleEl); 170 | }); 171 | }; 172 | 173 | // Try to load test.js for the example. Whether or not it exists, load 174 | // nacltest.js. 175 | injectScript('test.js', loadNaClTest, loadNaClTest); 176 | } 177 | } 178 | 179 | /** 180 | * Add the default "load" and "message" event listeners to the element with 181 | * id "listener". 182 | * 183 | * The "load" event is sent when the module is successfully loaded. The 184 | * "message" event is sent when the naclModule posts a message using 185 | * PPB_Messaging.PostMessage() (in C) or pp::Instance().PostMessage() (in 186 | * C++). 187 | */ 188 | function attachDefaultListeners() { 189 | var listenerDiv = document.getElementById('listener'); 190 | listenerDiv.addEventListener('load', moduleDidLoad, true); 191 | listenerDiv.addEventListener('message', handleMessage, true); 192 | listenerDiv.addEventListener('error', handleError, true); 193 | listenerDiv.addEventListener('crash', handleCrash, true); 194 | if (typeof window.attachListeners !== 'undefined') { 195 | window.attachListeners(); 196 | } 197 | } 198 | 199 | /** 200 | * Called when the NaCl module fails to load. 201 | * 202 | * This event listener is registered in createNaClModule above. 203 | */ 204 | function handleError(event) { 205 | // We can't use common.naclModule yet because the module has not been 206 | // loaded. 207 | var moduleEl = document.getElementById('nacl_module'); 208 | updateStatus('ERROR [' + moduleEl.lastError + ']'); 209 | 210 | $.event.trigger({ 211 | type: "plasio.nacl.error", 212 | message: moduleEl.lastError 213 | }); 214 | } 215 | 216 | /** 217 | * Called when the Browser can not communicate with the Module 218 | * 219 | * This event listener is registered in attachDefaultListeners above. 220 | */ 221 | function handleCrash(event) { 222 | var msg = "Unknown Error"; 223 | if (common.naclModule.exitStatus == -1) { 224 | updateStatus('CRASHED'); 225 | msg = "The module has crashed"; 226 | } else { 227 | updateStatus('EXITED [' + common.naclModule.exitStatus + ']'); 228 | msg = "The module has exited"; 229 | } 230 | if (typeof window.handleCrash !== 'undefined') { 231 | window.handleCrash(common.naclModule.lastError); 232 | msg = common.naclModule.lastError; 233 | } 234 | 235 | $.event.trigger({ 236 | type: "plasio.nacl.error", 237 | message: msg 238 | }); 239 | } 240 | 241 | /** 242 | * Called when the NaCl module is loaded. 243 | * 244 | * This event listener is registered in attachDefaultListeners above. 245 | */ 246 | function moduleDidLoad() { 247 | common.naclModule = document.getElementById('nacl_module'); 248 | updateStatus('RUNNING'); 249 | 250 | hideModule(); 251 | $.event.trigger({ 252 | type: "plasio.nacl.available" 253 | }); 254 | } 255 | 256 | /** 257 | * Hide the NaCl module's embed element. 258 | * 259 | * We don't want to hide by default; if we do, it is harder to determine that 260 | * a plugin failed to load. Instead, call this function inside the example's 261 | * "moduleDidLoad" function. 262 | * 263 | */ 264 | function hideModule() { 265 | // Setting common.naclModule.style.display = "None" doesn't work; the 266 | // module will no longer be able to receive postMessages. 267 | common.naclModule.style.height = '0'; 268 | } 269 | 270 | /** 271 | * Remove the NaCl module from the page. 272 | */ 273 | function removeModule() { 274 | common.naclModule.parentNode.removeChild(common.naclModule); 275 | common.naclModule = null; 276 | } 277 | 278 | /** 279 | * Return true when |s| starts with the string |prefix|. 280 | * 281 | * @param {string} s The string to search. 282 | * @param {string} prefix The prefix to search for in |s|. 283 | */ 284 | function startsWith(s, prefix) { 285 | // indexOf would search the entire string, lastIndexOf(p, 0) only checks at 286 | // the first index. See: http://stackoverflow.com/a/4579228 287 | return s.lastIndexOf(prefix, 0) === 0; 288 | } 289 | 290 | /** Maximum length of logMessageArray. */ 291 | var kMaxLogMessageLength = 20; 292 | 293 | /** An array of messages to display in the element with id "log". */ 294 | var logMessageArray = []; 295 | 296 | /** 297 | * Add a message to an element with id "log". 298 | * 299 | * This function is used by the default "log:" message handler. 300 | * 301 | * @param {string} message The message to log. 302 | */ 303 | function logMessage(message) { 304 | console.log(message); 305 | } 306 | 307 | /** 308 | */ 309 | var defaultMessageTypes = { 310 | 'alert': alert, 311 | 'log': logMessage 312 | }; 313 | 314 | /** 315 | * Called when the NaCl module sends a message to JavaScript (via 316 | * PPB_Messaging.PostMessage()) 317 | * 318 | * This event listener is registered in createNaClModule above. 319 | * 320 | * @param {Event} message_event A message event. message_event.data contains 321 | * the data sent from the NaCl module. 322 | */ 323 | function handleMessage(message_event) { 324 | console.log(JSON.stringify(message_event.data)); 325 | if (typeof message_event.data === 'string') { 326 | for (var type in defaultMessageTypes) { 327 | if (defaultMessageTypes.hasOwnProperty(type)) { 328 | if (startsWith(message_event.data, type + ':')) { 329 | func = defaultMessageTypes[type]; 330 | func(message_event.data.slice(type.length + 1)); 331 | return; 332 | } 333 | } 334 | } 335 | } 336 | 337 | if (typeof window.handleMessage !== 'undefined') { 338 | window.handleMessage(message_event); 339 | return; 340 | } 341 | 342 | logMessage('Unhandled message: ' + message_event.data); 343 | } 344 | 345 | /** 346 | * Called when the DOM content has loaded; i.e. the page's document is fully 347 | * parsed. At this point, we can safely query any elements in the document via 348 | * document.querySelector, document.getElementById, etc. 349 | * 350 | * @param {string} name The name of the example. 351 | * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. 352 | * @param {string} path Directory name where .nmf file can be found. 353 | * @param {number} width The width to create the plugin. 354 | * @param {number} height The height to create the plugin. 355 | * @param {Object} attrs Optional dictionary of additional attributes. 356 | */ 357 | function startNaCl(name, tool, path, width, height, attrs) { 358 | // If the page loads before the Native Client module loads, then set the 359 | // status message indicating that the module is still loading. Otherwise, 360 | // do not change the status message. 361 | updateStatus('Page loaded.'); 362 | if (!browserSupportsNaCl(tool)) { 363 | updateStatus( 364 | 'Browser does not support NaCl (' + tool + '), or NaCl is disabled'); 365 | } else if (common.naclModule === null) { 366 | updateStatus('Creating embed: ' + tool); 367 | 368 | // We use a non-zero sized embed to give Chrome space to place the bad 369 | // plug-in graphic, if there is a problem. 370 | width = typeof width !== 'undefined' ? width : 200; 371 | height = typeof height !== 'undefined' ? height : 200; 372 | attachDefaultListeners(); 373 | createNaClModule(name, tool, path, width, height, attrs); 374 | } else { 375 | // It's possible that the Native Client module onload event fired 376 | // before the page's onload event. In this case, the status message 377 | // will reflect 'SUCCESS', but won't be displayed. This call will 378 | // display the current message. 379 | updateStatus('Waiting.'); 380 | } 381 | } 382 | 383 | /** Saved text to display in the element with id 'statusField'. */ 384 | var statusText = 'NO-STATUSES'; 385 | 386 | /** 387 | * Set the global status message. If the element with id 'statusField' 388 | * exists, then set its HTML to the status message as well. 389 | * 390 | * @param {string} opt_message The message to set. If null or undefined, then 391 | * set element 'statusField' to the message from the last call to 392 | * updateStatus. 393 | */ 394 | function updateStatus(opt_message) { 395 | console.log(opt_message); 396 | } 397 | 398 | // The symbols to export. 399 | return { 400 | /** A reference to the NaCl module, once it is loaded. */ 401 | naclModule: null, 402 | 403 | attachDefaultListeners: attachDefaultListeners, 404 | startNaCl: startNaCl, 405 | createNaClModule: createNaClModule, 406 | hideModule: hideModule, 407 | removeModule: removeModule, 408 | logMessage: logMessage, 409 | updateStatus: updateStatus, 410 | browserSupportsNaCl: browserSupportsNaCl 411 | }; 412 | 413 | }()); 414 | 415 | module.exports = common; 416 | 417 | // listen to the plasio start notification to trigger NaCl stuff 418 | // 419 | $(document).on("plasio.start", function() { 420 | var body = document.body; 421 | 422 | // The data-* attributes on the body can be referenced via body.dataset. 423 | if (body.dataset) { 424 | var loadFunction; 425 | if (!body.dataset.customLoad) { 426 | loadFunction = common.startNaCl; 427 | } else if (typeof window.startNaCl !== 'undefined') { 428 | loadFunction = window.startNaCl; 429 | } 430 | 431 | // From https://developer.mozilla.org/en-US/docs/DOM/window.location 432 | var searchVars = {}; 433 | if (window.location.search.length > 1) { 434 | var pairs = window.location.search.substr(1).split('&'); 435 | for (var key_ix = 0; key_ix < pairs.length; key_ix++) { 436 | var keyValue = pairs[key_ix].split('='); 437 | searchVars[unescape(keyValue[0])] = 438 | keyValue.length > 1 ? unescape(keyValue[1]) : ''; 439 | } 440 | } 441 | 442 | if (loadFunction) { 443 | var toolchains = body.dataset.tools.split(' '); 444 | var configs = body.dataset.configs.split(' '); 445 | 446 | var attrs = {}; 447 | if (body.dataset.attrs) { 448 | var attr_list = body.dataset.attrs.split(' '); 449 | for (var key in attr_list) { 450 | var attr = attr_list[key].split('='); 451 | var k = attr[0]; 452 | var value = attr[1]; 453 | attrs[k] = value; 454 | } 455 | } 456 | 457 | var tc = toolchains.indexOf(searchVars.tc) !== -1 ? 458 | searchVars.tc : toolchains[0]; 459 | 460 | // If the config value is included in the search vars, use that. 461 | // Otherwise default to Release if it is valid, or the first value if 462 | // Release is not valid. 463 | var config; 464 | if (configs.indexOf(searchVars.config) !== -1) 465 | config = searchVars.config; 466 | else if (configs.indexOf('Release') !== -1) 467 | config = 'Release'; 468 | else 469 | config = configs[0]; 470 | 471 | var pathFormat = body.dataset.path; 472 | var path = pathFormat.replace('{tc}', tc).replace('{config}', config); 473 | 474 | isTest = searchVars.test === 'true'; 475 | isRelease = path.toLowerCase().indexOf('release') != -1; 476 | 477 | loadFunction(body.dataset.name, tc, path, body.dataset.width, 478 | body.dataset.height, attrs); 479 | } 480 | } 481 | }); 482 | 483 | -------------------------------------------------------------------------------- /js/gh-loader.js: -------------------------------------------------------------------------------- 1 | // gh-loader.js 2 | // point loader abstraction for loading stuff off of a greyhound buffer, provides the same interface as laslaz. 3 | // 4 | 5 | (function(scope) { 6 | "use strict"; 7 | 8 | var GHLoader = function(arraybuffer, numPoints, schema) { 9 | this.arraybuffer = (arraybuffer instanceof Uint8Array) ? 10 | arraybuffer.buffer : arraybuffer; 11 | this.numPoints = numPoints; 12 | this.schema = schema; 13 | }; 14 | 15 | GHLoader.prototype.open = function() { 16 | this.readOffset = 0; 17 | return new Promise(function(res, rej) { 18 | setTimeout(res); 19 | }); 20 | }; 21 | 22 | GHLoader.prototype.getHeader = function() { 23 | var o = this; 24 | return new Promise(function(res, rej) { 25 | setTimeout(function() { 26 | // made up stuff we can figure out from our schema and stuff 27 | var schemaSize = o.schema.reduce(function(acc, i) { 28 | return acc + i.size; 29 | }, 0); 30 | 31 | console.log(schemaSize); 32 | 33 | var header = { 34 | pointsOffset: 0, 35 | scale: [1, 1, 1], 36 | offset: [0, 0, 0], 37 | pointsCount: o.numPoints, 38 | pointsStructSize: schemaSize, // TODO: use schema to figure this 39 | schema: o.schema 40 | }; 41 | o.header = header; 42 | 43 | res(header); 44 | }); 45 | }); 46 | }; 47 | 48 | GHLoader.prototype.readData = function(count, offset, skip) { 49 | var o = this; 50 | 51 | return new Promise(function(res, rej) { 52 | setTimeout(function() { 53 | var start; 54 | if (skip <= 1) { 55 | count = Math.min(count, o.header.pointsCount - o.readOffset); 56 | start = o.header.pointsOffset + o.readOffset * o.header.pointsStructSize; 57 | var end = start + count * o.header.pointsStructSize; 58 | console.log(start, end); 59 | res({ 60 | buffer: o.arraybuffer.slice(start, end), 61 | count: count, 62 | hasMoreData: o.readOffset + count < o.header.pointsCount}); 63 | o.readOffset += count; 64 | } 65 | else { 66 | var pointsToRead = Math.min(count * skip, o.header.pointsCount - o.readOffset); 67 | var bufferSize = Math.ceil(pointsToRead / skip); 68 | var pointsRead = 0; 69 | 70 | var buf = new Uint8Array(bufferSize * o.header.pointsStructSize); 71 | console.log("Destination size:", buf.byteLength); 72 | for (var i = 0 ; i < pointsToRead ; i ++) { 73 | if (i % skip === 0) { 74 | start = o.header.pointsOffset + o.readOffset * o.header.pointsStructSize; 75 | var src = new Uint8Array(o.arraybuffer, start, o.header.pointsStructSize); 76 | 77 | buf.set(src, pointsRead * o.header.pointsStructSize); 78 | pointsRead ++; 79 | } 80 | 81 | o.readOffset ++; 82 | } 83 | 84 | res({ 85 | buffer: buf.buffer, 86 | count: pointsRead, 87 | hasMoreData: o.readOffset < o.header.pointsCount 88 | }); 89 | } 90 | }, 0); 91 | }); 92 | }; 93 | 94 | GHLoader.prototype.close = function() { 95 | var o = this; 96 | 97 | return new Promise(function(res) { 98 | o.arraybuffer = null; 99 | setTimeout(res); 100 | }); 101 | }; 102 | 103 | 104 | var PointDecomp = function(buffer, len, header) { 105 | // point decompressor 106 | this.arrayb = buffer; 107 | this.header = header; 108 | this.pointSize = header.pointsStructSize; 109 | this.pointsCount = len; 110 | this.scale = header.scale; 111 | this.offset = header.offset; 112 | this.mins = [0, 0, 0]; 113 | this.maxs = [0, 0, 0]; 114 | }; 115 | 116 | var decodeWithSchema = (function() { 117 | var fs = { 118 | "floating": { 119 | 4: DataView.prototype.getFloat32, 120 | 8: DataView.prototype.getFloat64 121 | }, 122 | "unsigned": { 123 | 1: DataView.prototype.getUint8, 124 | 2: DataView.prototype.getUint16, 125 | 4: DataView.prototype.getUint32 126 | } 127 | }; 128 | 129 | var safe_fs = function(type, size) { 130 | if(!fs[type]) return undefined; 131 | return fs[type][size]; 132 | }; 133 | 134 | return function(dv, schema) { 135 | var obj = {}; 136 | var off = 0; 137 | 138 | schema.forEach(function(i) { 139 | var f = safe_fs(i.type, i.size); 140 | obj[i.name] = f.call(dv, off, true); 141 | off += i.size; 142 | }); 143 | 144 | 145 | // coerce into what we want the decoder to return 146 | var r = {}; 147 | if (obj.X || obj.Y || obj.Z) { 148 | r.position = [obj.X, obj.Y, obj.Z]; 149 | } 150 | 151 | if (obj.Red || obj.Green || obj.Red) { 152 | r.color = [obj.Red, obj.Green, obj.Red]; 153 | } 154 | 155 | r.intensity = obj.Intensity; 156 | 157 | return r; 158 | }; 159 | })(); 160 | 161 | PointDecomp.prototype.getPoint = function(index) { 162 | // based on the schema, decode this point! 163 | if (index < 0 || index >= this.pointsCount) 164 | throw new Error("Point index out of range"); 165 | 166 | var dv = new DataView(this.arrayb, index * this.pointSize, this.pointSize); 167 | return decodeWithSchema(dv, this.header.schema); 168 | }; 169 | 170 | GHLoader.prototype.getUnpacker = function() { 171 | return PointDecomp; 172 | }; 173 | 174 | scope.GHLoader = GHLoader; 175 | })(module.exports); 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /js/laslaz.js: -------------------------------------------------------------------------------- 1 | // laslaz.js 2 | // LAS/LAZ loading 3 | // 4 | 5 | var common = require("./common"), 6 | Promise = require("bluebird"); 7 | 8 | (function(scope) { 9 | "use strict"; 10 | 11 | var pointFormatReaders = { 12 | 0: function(dv) { 13 | return { 14 | "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)], 15 | "intensity": dv.getUint16(12, true), 16 | "classification": dv.getUint8(15, true) 17 | }; 18 | }, 19 | 1: function(dv) { 20 | return { 21 | "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)], 22 | "intensity": dv.getUint16(12, true), 23 | "classification": dv.getUint8(15, true) 24 | }; 25 | }, 26 | 2: function(dv) { 27 | return { 28 | "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)], 29 | "intensity": dv.getUint16(12, true), 30 | "classification": dv.getUint8(15, true), 31 | "color": [dv.getUint16(20, true), dv.getUint16(22, true), dv.getUint16(24, true)] 32 | }; 33 | }, 34 | 3: function(dv) { 35 | return { 36 | "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)], 37 | "intensity": dv.getUint16(12, true), 38 | "classification": dv.getUint8(15, true), 39 | "color": [dv.getUint16(28, true), dv.getUint16(30, true), dv.getUint16(32, true)] 40 | }; 41 | } 42 | }; 43 | 44 | function readAs(buf, Type, offset, count) { 45 | count = (count === undefined || count === 0 ? 1 : count); 46 | var sub = buf.slice(offset, offset + Type.BYTES_PER_ELEMENT * count); 47 | 48 | var r = new Type(sub); 49 | if (count === undefined || count === 1) 50 | return r[0]; 51 | 52 | var ret = []; 53 | for (var i = 0 ; i < count ; i ++) { 54 | ret.push(r[i]); 55 | } 56 | 57 | return ret; 58 | } 59 | 60 | function parseLASHeader(arraybuffer) { 61 | var o = {}; 62 | 63 | o.pointsOffset = readAs(arraybuffer, Uint32Array, 32*3); 64 | o.pointsFormatId = readAs(arraybuffer, Uint8Array, 32*3+8); 65 | o.pointsStructSize = readAs(arraybuffer, Uint16Array, 32*3+8+1); 66 | o.pointsCount = readAs(arraybuffer, Uint32Array, 32*3 + 11); 67 | 68 | 69 | var start = 32*3 + 35; 70 | o.scale = readAs(arraybuffer, Float64Array, start, 3); start += 24; // 8*3 71 | o.offset = readAs(arraybuffer, Float64Array, start, 3); start += 24; 72 | 73 | console.log("Read stuff:", o.scale, o.offset); 74 | 75 | 76 | var bounds = readAs(arraybuffer, Float64Array, start, 6); start += 48; // 8*6; 77 | o.maxs = [bounds[0], bounds[2], bounds[4]]; 78 | o.mins = [bounds[1], bounds[3], bounds[5]]; 79 | 80 | return o; 81 | } 82 | 83 | var msgIndex = 0; 84 | var waitHandlers = {}; 85 | 86 | // This method is scope-wide since the nacl module uses this fuction to notify 87 | // us of events 88 | scope.handleMessage = function(message_event) { 89 | var msg = message_event.data; 90 | var resolver = waitHandlers[msg.id]; 91 | delete waitHandlers[msg.id]; 92 | 93 | // call the callback in a separate context, make sure we've cleaned our 94 | // state out before the callback is invoked since it may queue more doExchanges 95 | setTimeout(function() { 96 | if (msg.error) 97 | return resolver.reject(new Error(msg.message || "Unknown Error")); 98 | 99 | if (msg.hasOwnProperty('count') && msg.hasOwnProperty('hasMoreData')) { 100 | return resolver.resolve({ 101 | buffer: msg.result, 102 | count: msg.count, 103 | hasMoreData: msg.hasMoreData}); 104 | } 105 | 106 | resolver.resolve(msg.result); 107 | }, 0); 108 | }; 109 | 110 | var doDataExchange = function(cmd, callback) { 111 | cmd.id = msgIndex.toString(); 112 | msgIndex ++; 113 | 114 | var resolver = Promise.defer(); 115 | waitHandlers[cmd.id] = resolver; 116 | 117 | nacl_module.postMessage(cmd); 118 | 119 | return resolver.promise.cancellable(); 120 | }; 121 | 122 | // LAS Loader 123 | // Loads uncompressed files 124 | // 125 | var LASLoader = function(arraybuffer) { 126 | this.arraybuffer = arraybuffer; 127 | }; 128 | 129 | LASLoader.prototype.open = function() { 130 | // nothing needs to be done to open this file 131 | // 132 | this.readOffset = 0; 133 | return new Promise(function(res, rej) { 134 | setTimeout(res, 0); 135 | }); 136 | }; 137 | 138 | LASLoader.prototype.getHeader = function() { 139 | var o = this; 140 | 141 | return new Promise(function(res, rej) { 142 | setTimeout(function() { 143 | o.header = parseLASHeader(o.arraybuffer); 144 | res(o.header); 145 | }, 0); 146 | }); 147 | }; 148 | 149 | LASLoader.prototype.readData = function(count, offset, skip) { 150 | var o = this; 151 | 152 | return new Promise(function(res, rej) { 153 | setTimeout(function() { 154 | if (!o.header) 155 | return rej(new Error("Cannot start reading data till a header request is issued")); 156 | 157 | var start; 158 | if (skip <= 1) { 159 | count = Math.min(count, o.header.pointsCount - o.readOffset); 160 | start = o.header.pointsOffset + o.readOffset * o.header.pointsStructSize; 161 | var end = start + count * o.header.pointsStructSize; 162 | console.log(start, end); 163 | res({ 164 | buffer: o.arraybuffer.slice(start, end), 165 | count: count, 166 | hasMoreData: o.readOffset + count < o.header.pointsCount}); 167 | o.readOffset += count; 168 | } 169 | else { 170 | var pointsToRead = Math.min(count * skip, o.header.pointsCount - o.readOffset); 171 | var bufferSize = Math.ceil(pointsToRead / skip); 172 | var pointsRead = 0; 173 | 174 | var buf = new Uint8Array(bufferSize * o.header.pointsStructSize); 175 | console.log("Destination size:", buf.byteLength); 176 | for (var i = 0 ; i < pointsToRead ; i ++) { 177 | if (i % skip === 0) { 178 | start = o.header.pointsOffset + o.readOffset * o.header.pointsStructSize; 179 | var src = new Uint8Array(o.arraybuffer, start, o.header.pointsStructSize); 180 | 181 | buf.set(src, pointsRead * o.header.pointsStructSize); 182 | pointsRead ++; 183 | } 184 | 185 | o.readOffset ++; 186 | } 187 | 188 | res({ 189 | buffer: buf.buffer, 190 | count: pointsRead, 191 | hasMoreData: o.readOffset < o.header.pointsCount 192 | }); 193 | } 194 | }, 0); 195 | }); 196 | }; 197 | 198 | LASLoader.prototype.close = function() { 199 | var o = this; 200 | return new Promise(function(res, rej) { 201 | o.arraybuffer = null; 202 | setTimeout(res, 0); 203 | }); 204 | }; 205 | 206 | // LAZ Loader 207 | // Uses NaCL module to load LAZ files 208 | // 209 | var LAZLoader = function(arraybuffer) { 210 | this.arraybuffer = arraybuffer; 211 | this.ww = new Worker("workers/laz-loader-worker.js"); 212 | 213 | this.nextCB = null; 214 | var o = this; 215 | 216 | this.ww.onmessage = function(e) { 217 | if (o.nextCB !== null) { 218 | console.log('dorr: >>', e.data); 219 | o.nextCB(e.data); 220 | o.nextCB = null; 221 | } 222 | }; 223 | 224 | this.dorr = function(req, cb) { 225 | console.log('dorr: <<', req); 226 | o.nextCB = cb; 227 | o.ww.postMessage(req); 228 | }; 229 | }; 230 | 231 | LAZLoader.prototype.open = function() { 232 | 233 | // nothing needs to be done to open this file 234 | // 235 | var o = this; 236 | return new Promise(function(res, rej) { 237 | o.dorr({type:"open", arraybuffer: o.arraybuffer}, function(r) { 238 | if (r.status !== 1) 239 | return rej(new Error("Failed to open file")); 240 | 241 | res(true); 242 | }); 243 | }); 244 | }; 245 | 246 | LAZLoader.prototype.getHeader = function() { 247 | var o = this; 248 | 249 | return new Promise(function(res, rej) { 250 | o.dorr({type:'header'}, function(r) { 251 | if (r.status !== 1) 252 | return rej(new Error("Failed to get header")); 253 | 254 | res(r.header); 255 | }); 256 | }); 257 | }; 258 | 259 | LAZLoader.prototype.readData = function(count, offset, skip) { 260 | var o = this; 261 | 262 | return new Promise(function(res, rej) { 263 | o.dorr({type:'read', count: count, offset: offset, skip: skip}, function(r) { 264 | if (r.status !== 1) 265 | return rej(new Error("Failed to read data")); 266 | res({ 267 | buffer: r.buffer, 268 | count: r.count, 269 | hasMoreData: r.hasMoreData 270 | }); 271 | }); 272 | }); 273 | }; 274 | 275 | LAZLoader.prototype.close = function() { 276 | var o = this; 277 | 278 | return new Promise(function(res, rej) { 279 | o.dorr({type:'close'}, function(r) { 280 | if (r.status !== 1) 281 | return rej(new Error("Failed to close file")); 282 | 283 | res(true); 284 | }); 285 | }); 286 | }; 287 | 288 | // A single consistent interface for loading LAS/LAZ files 289 | var LASFile = function(arraybuffer) { 290 | this.arraybuffer = arraybuffer; 291 | 292 | this.determineVersion(); 293 | if (this.version > 13) 294 | throw new Error("Only file versions <= 1.3 are supported at this time"); 295 | 296 | this.determineFormat(); 297 | if (pointFormatReaders[this.formatId] === undefined) 298 | throw new Error("The point format ID is not supported"); 299 | 300 | this.loader = this.isCompressed ? 301 | new LAZLoader(this.arraybuffer) : 302 | new LASLoader(this.arraybuffer); 303 | }; 304 | 305 | LASFile.prototype.determineFormat = function() { 306 | var formatId = readAs(this.arraybuffer, Uint8Array, 32*3+8); 307 | var bit_7 = (formatId & 0x80) >> 7; 308 | var bit_6 = (formatId & 0x40) >> 6; 309 | 310 | if (bit_7 === 1 && bit_6 === 1) 311 | throw new Error("Old style compression not supported"); 312 | 313 | this.formatId = formatId & 0x3f; 314 | this.isCompressed = (bit_7 === 1 || bit_6 === 1); 315 | }; 316 | 317 | LASFile.prototype.determineVersion = function() { 318 | var ver = new Int8Array(this.arraybuffer, 24, 2); 319 | this.version = ver[0] * 10 + ver[1]; 320 | this.versionAsString = ver[0] + "." + ver[1]; 321 | }; 322 | 323 | LASFile.prototype.open = function() { 324 | return this.loader.open(); 325 | }; 326 | 327 | LASFile.prototype.getHeader = function() { 328 | return this.loader.getHeader(); 329 | }; 330 | 331 | LASFile.prototype.readData = function(count, start, skip) { 332 | return this.loader.readData(count, start, skip); 333 | }; 334 | 335 | LASFile.prototype.close = function() { 336 | return this.loader.close(); 337 | }; 338 | 339 | // Decodes LAS records into points 340 | // 341 | var LASDecoder = function(buffer, len, header) { 342 | console.log(header); 343 | console.log("POINT FORMAT ID:", header.pointsFormatId); 344 | this.arrayb = buffer; 345 | this.decoder = pointFormatReaders[header.pointsFormatId]; 346 | this.pointsCount = len; 347 | this.pointSize = header.pointsStructSize; 348 | this.scale = header.scale; 349 | this.offset = header.offset; 350 | this.mins = header.mins; 351 | this.maxs = header.maxs; 352 | }; 353 | 354 | LASDecoder.prototype.getPoint = function(index) { 355 | if (index < 0 || index >= this.pointsCount) 356 | throw new Error("Point index out of range"); 357 | 358 | var dv = new DataView(this.arrayb, index * this.pointSize, this.pointSize); 359 | return this.decoder(dv); 360 | }; 361 | 362 | // NACL Module support 363 | // Called by the common.js module. 364 | // 365 | window.startNaCl = function(name, tc, config, width, height) { 366 | // check browser support for nacl 367 | // 368 | if(!common.browserSupportsNaCl()) { 369 | return $.event.trigger({ 370 | type: "plasio.nacl.error", 371 | message: "NaCl support is not available" 372 | }); 373 | } 374 | console.log("Requesting persistent memory"); 375 | 376 | navigator.webkitPersistentStorage.requestQuota(2048 * 2048, function(bytes) { 377 | common.updateStatus( 378 | 'Allocated ' + bytes + ' bytes of persistant storage.'); 379 | common.attachDefaultListeners(); 380 | common.createNaClModule(name, tc, config, width, height); 381 | }, 382 | function(e) { 383 | console.log("Failed!"); 384 | $.event.trigger({ 385 | type: "plasio.nacl.error", 386 | message: "Could not allocate persistant storage" 387 | }); 388 | }); 389 | 390 | $(document).on("plasio.nacl.available", function() { 391 | scope.LASModuleWasLoaded = true; 392 | console.log("NACL Available"); 393 | }); 394 | }; 395 | 396 | LASFile.prototype.getUnpacker = function() { 397 | return LASDecoder; 398 | }; 399 | 400 | scope.LASFile = LASFile; 401 | scope.LASModuleWasLoaded = false; 402 | })(module.exports); 403 | 404 | -------------------------------------------------------------------------------- /js/util.js: -------------------------------------------------------------------------------- 1 | // util.js 2 | // Utility functions 3 | // 4 | 5 | 6 | var $ = require("jquery"); 7 | var m = require('mori'); 8 | 9 | (function(scope) { 10 | "use strict"; 11 | 12 | scope.withRefresh = function(f) { 13 | // return f wrapped around with a call to renderer.needRefresh 14 | return function() { 15 | var r = f.apply(this, arguments); 16 | $.event.trigger({ 17 | type: 'plasio.renderer.needRefresh' 18 | }); 19 | 20 | return r; 21 | }; 22 | }; 23 | 24 | // Borrowed without shame from here: http://www.abeautifulsite.net/parsing-urls-in-javascript/ 25 | var parseURL = function (url) { 26 | var parser = document.createElement('a'), 27 | searchObject = {}, 28 | queries, split, i; 29 | 30 | // Let the browser do the work 31 | parser.href = url; 32 | // Convert query string to object 33 | queries = parser.search.split('&'); 34 | 35 | for( i = 0; i < queries.length; i++ ) { 36 | split = queries[i].split('='); 37 | searchObject[split[0]] = split[1]; 38 | } 39 | 40 | return { 41 | protocol: parser.protocol, 42 | host: parser.host, 43 | hostname: parser.hostname, 44 | port: parser.port, 45 | pathname: parser.pathname, 46 | search: parser.search, 47 | searchObject: searchObject, 48 | hash: parser.hash 49 | }; 50 | }; 51 | 52 | scope.parseGHComponents = function(url) { 53 | // needs to be one of the supported URL formats 54 | var parts = parseURL(url); 55 | console.log(parts); 56 | var pipeline = parts.pathname.match(/\/([a-zA-Z0-9]+)$/); 57 | if (!pipeline) 58 | return null; 59 | 60 | 61 | pipeline = pipeline[1]; 62 | 63 | return { 64 | server: parts.host, 65 | pipelineId: pipeline 66 | }; 67 | }; 68 | 69 | var RateCompute = function() { 70 | this.dl = 0; 71 | this.start = Date.now(); 72 | this.ts = []; 73 | this.message = "NA"; 74 | }; 75 | 76 | RateCompute.prototype.push = function(count) { 77 | if (this.ts.length > 5) 78 | this.ts = this.ts.slice(1); 79 | 80 | this.dl += count; 81 | this.ts.push([Date.now(), this.dl]); 82 | 83 | this._updateRate(); 84 | }; 85 | 86 | RateCompute.prototype._updateRate = function() { 87 | // running average of last five time slots 88 | if (this.ts.length < 2) return; // need two samples 89 | 90 | var rate = m.pipeline( 91 | this.ts, 92 | function(v) { return m.partition(2, 1, v); }, 93 | function(v) { 94 | return m.reduce(function(acc, v) { 95 | var a = m.first(v), 96 | b = m.first(m.rest(v)); 97 | 98 | var td = (b[0] - a[0]) / 1000.0; // time difference in seconds 99 | var dd = b[1] - a[1]; 100 | 101 | return m.conj(acc, dd / td); 102 | }, m.vector(), v); 103 | }, 104 | function(v) { 105 | return m.reduce(m.sum, v) / m.count(v); 106 | }); 107 | 108 | this.message = this._makePrettyMessage(rate); 109 | }; 110 | 111 | RateCompute.prototype._makePrettyMessage = function(r) { 112 | if (r < 1024) return r.toFixed(0) + "B/s"; 113 | if (r < 1024*1024) return (r/1024).toFixed(1) + "KB/s"; 114 | if (r < 1024*1024*1024) return (r/(1024 * 1024)).toFixed(1) + "MB/s"; 115 | return (r/(1024 * 1024 * 1024)).toFixed(1) + "GB/s WOAH!"; 116 | }; 117 | 118 | scope.RateCompute = RateCompute; 119 | scope.parseURL = parseURL; 120 | })(module.exports); 121 | -------------------------------------------------------------------------------- /less/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.1.1 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /less/jquery.nouislider.min.css: -------------------------------------------------------------------------------- 1 | .noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-user-select:none;-ms-touch-action:none;-ms-user-select:none;-moz-user-select:none;-moz-box-sizing:border-box;box-sizing:border-box}.noUi-base{width:100%;height:100%;position:relative}.noUi-origin{position:absolute;right:0;top:0;left:0;bottom:0}.noUi-handle{position:relative;z-index:1}.noUi-stacking .noUi-handle{z-index:10}.noUi-stacking+.noUi-origin{*z-index:-1}.noUi-state-tap .noUi-origin{-webkit-transition:left .3s,top .3s;transition:left .3s,top .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-horizontal{height:18px}.noUi-horizontal .noUi-handle{width:34px;height:28px;left:-17px;top:-6px}.noUi-horizontal.noUi-extended{padding:0 15px}.noUi-horizontal.noUi-extended .noUi-origin{right:-15px}.noUi-vertical{width:18px}.noUi-vertical .noUi-handle{width:28px;height:34px;left:-6px;top:-17px}.noUi-vertical.noUi-extended{padding:15px 0}.noUi-vertical.noUi-extended .noUi-origin{bottom:-15px}.noUi-background{background:#FAFAFA;box-shadow:inset 0 1px 1px #f0f0f0}.noUi-connect{background:#3FB8AF;box-shadow:inset 0 0 3px rgba(51,51,51,.45);-webkit-transition:background 450ms;transition:background 450ms}.noUi-origin{border-radius:2px}.noUi-target{border-radius:4px;border:1px solid #D3D3D3;box-shadow:inset 0 1px 1px #F0F0F0,0 3px 6px -5px #BBB}.noUi-target.noUi-connect{box-shadow:inset 0 0 3px rgba(51,51,51,.45),0 3px 6px -5px #BBB}.noUi-dragable{cursor:w-resize}.noUi-vertical .noUi-dragable{cursor:n-resize}.noUi-handle{border:1px solid #D9D9D9;border-radius:3px;background:#FFF;cursor:default;box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #EBEBEB,0 3px 6px -3px #BBB}.noUi-active{box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #DDD,0 3px 6px -3px #BBB}.noUi-handle:after,.noUi-handle:before{content:"";display:block;position:absolute;height:14px;width:1px;background:#E8E7E6;left:14px;top:6px}.noUi-handle:after{left:17px}.noUi-vertical .noUi-handle:after,.noUi-vertical .noUi-handle:before{width:14px;height:1px;left:6px;top:14px}.noUi-vertical .noUi-handle:after{top:17px}[disabled] .noUi-connect,[disabled].noUi-connect{background:#B8B8B8}[disabled] .noUi-handle{cursor:not-allowed}.noUi-state-blocked .noUi-connect,.noUi-state-blocked.noUi-connect{background:#4FDACF} 2 | -------------------------------------------------------------------------------- /less/layout-default-latest.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Default Layout Theme 3 | * 4 | * Created for jquery.layout 5 | * 6 | * Copyright (c) 2010 7 | * Fabrizio Balliano (http://www.fabrizioballiano.net) 8 | * Kevin Dalman (http://allpro.net) 9 | * 10 | * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) 11 | * and MIT (http://www.opensource.org/licenses/mit-license.php) licenses. 12 | * 13 | * Last Updated: 2010-02-10 14 | * NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars 15 | */ 16 | 17 | /* 18 | * DEFAULT FONT 19 | * Just to make demo-pages look better - not actually relevant to Layout! 20 | */ 21 | body { 22 | font-family: Geneva, Arial, Helvetica, sans-serif; 23 | font-size: 100%; 24 | *font-size: 80%; 25 | } 26 | 27 | /* 28 | * PANES & CONTENT-DIVs 29 | */ 30 | .ui-layout-pane { /* all 'panes' */ 31 | background: #FFF; 32 | border: 1px solid #BBB; 33 | padding: 10px; 34 | overflow: auto; 35 | /* DO NOT add scrolling (or padding) to 'panes' that have a content-div, 36 | otherwise you may get double-scrollbars - on the pane AND on the content-div 37 | - use ui-layout-wrapper class if pane has a content-div 38 | - use ui-layout-container if pane has an inner-layout 39 | */ 40 | } 41 | /* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */ 42 | .ui-layout-content { 43 | padding: 10px; 44 | position: relative; /* contain floated or positioned elements */ 45 | overflow: auto; /* add scrolling to content-div */ 46 | } 47 | 48 | /* 49 | * UTILITY CLASSES 50 | * Must come AFTER pane-class above so will override 51 | * These classes are NOT auto-generated and are NOT used by Layout 52 | */ 53 | .layout-child-container, 54 | .layout-content-container { 55 | padding: 0; 56 | overflow: hidden; 57 | } 58 | .layout-child-container { 59 | border: 0; /* remove border because inner-layout-panes probably have borders */ 60 | } 61 | .layout-scroll { 62 | overflow: auto; 63 | } 64 | .layout-hide { 65 | display: none; 66 | } 67 | 68 | /* 69 | * RESIZER-BARS 70 | */ 71 | .ui-layout-resizer { /* all 'resizer-bars' */ 72 | background: #DDD; 73 | border: 1px solid #BBB; 74 | border-width: 0; 75 | } 76 | .ui-layout-resizer-drag { /* REAL resizer while resize in progress */ 77 | } 78 | .ui-layout-resizer-hover { /* affects both open and closed states */ 79 | } 80 | /* NOTE: It looks best when 'hover' and 'dragging' are set to the same color, 81 | otherwise color shifts while dragging when bar can't keep up with mouse */ 82 | .ui-layout-resizer-open-hover , /* hover-color to 'resize' */ 83 | .ui-layout-resizer-dragging { /* resizer beging 'dragging' */ 84 | background: #C4E1A4; 85 | } 86 | .ui-layout-resizer-dragging { /* CLONED resizer being dragged */ 87 | border: 1px solid #BBB; 88 | } 89 | .ui-layout-resizer-north-dragging, 90 | .ui-layout-resizer-south-dragging { 91 | border-width: 1px 0; 92 | } 93 | .ui-layout-resizer-west-dragging, 94 | .ui-layout-resizer-east-dragging { 95 | border-width: 0 1px; 96 | } 97 | /* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */ 98 | .ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */ 99 | background: #E1A4A4; /* red */ 100 | } 101 | 102 | .ui-layout-resizer-closed-hover { /* hover-color to 'slide open' */ 103 | background: #EBD5AA; 104 | } 105 | .ui-layout-resizer-sliding { /* resizer when pane is 'slid open' */ 106 | opacity: .10; /* show only a slight shadow */ 107 | filter: alpha(opacity=10); 108 | } 109 | .ui-layout-resizer-sliding-hover { /* sliding resizer - hover */ 110 | opacity: 1.00; /* on-hover, show the resizer-bar normally */ 111 | filter: alpha(opacity=100); 112 | } 113 | /* sliding resizer - add 'outside-border' to resizer on-hover 114 | * this sample illustrates how to target specific panes and states */ 115 | .ui-layout-resizer-north-sliding-hover { border-bottom-width: 1px; } 116 | .ui-layout-resizer-south-sliding-hover { border-top-width: 1px; } 117 | .ui-layout-resizer-west-sliding-hover { border-right-width: 1px; } 118 | .ui-layout-resizer-east-sliding-hover { border-left-width: 1px; } 119 | 120 | /* 121 | * TOGGLER-BUTTONS 122 | */ 123 | .ui-layout-toggler { 124 | border: 1px solid #BBB; /* match pane-border */ 125 | background-color: #BBB; 126 | } 127 | .ui-layout-resizer-hover .ui-layout-toggler { 128 | opacity: .60; 129 | filter: alpha(opacity=60); 130 | } 131 | .ui-layout-toggler-hover , /* need when NOT resizable */ 132 | .ui-layout-resizer-hover .ui-layout-toggler-hover { /* need specificity when IS resizable */ 133 | background-color: #FC6; 134 | opacity: 1.00; 135 | filter: alpha(opacity=100); 136 | } 137 | .ui-layout-toggler-north , 138 | .ui-layout-toggler-south { 139 | border-width: 0 1px; /* left/right borders */ 140 | } 141 | .ui-layout-toggler-west , 142 | .ui-layout-toggler-east { 143 | border-width: 1px 0; /* top/bottom borders */ 144 | } 145 | /* hide the toggler-button when the pane is 'slid open' */ 146 | .ui-layout-resizer-sliding .ui-layout-toggler { 147 | display: none; 148 | } 149 | /* 150 | * style the text we put INSIDE the togglers 151 | */ 152 | .ui-layout-toggler .content { 153 | color: #666; 154 | font-size: 12px; 155 | font-weight: bold; 156 | width: 100%; 157 | padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */ 158 | } 159 | 160 | /* 161 | * PANE-MASKS 162 | * these styles are hard-coded on mask elems, but are also 163 | * included here as !important to ensure will overrides any generic styles 164 | */ 165 | .ui-layout-mask { 166 | border: none !important; 167 | padding: 0 !important; 168 | margin: 0 !important; 169 | overflow: hidden !important; 170 | position: absolute !important; 171 | opacity: 0 !important; 172 | filter: Alpha(Opacity="0") !important; 173 | } 174 | .ui-layout-mask-inside-pane { /* masks always inside pane EXCEPT when pane is an iframe */ 175 | top: 0 !important; 176 | left: 0 !important; 177 | width: 100% !important; 178 | height: 100% !important; 179 | } 180 | div.ui-layout-mask {} /* standard mask for iframes */ 181 | iframe.ui-layout-mask {} /* extra mask for objects/applets */ 182 | 183 | /* 184 | * Default printing styles 185 | */ 186 | @media print { 187 | /* 188 | * Unless you want to print the layout as it appears onscreen, 189 | * these html/body styles are needed to allow the content to 'flow' 190 | */ 191 | html { 192 | height: auto !important; 193 | overflow: visible !important; 194 | } 195 | body.ui-layout-container { 196 | position: static !important; 197 | top: auto !important; 198 | bottom: auto !important; 199 | left: auto !important; 200 | right: auto !important; 201 | /* only IE6 has container width & height set by Layout */ 202 | _width: auto !important; 203 | _height: auto !important; 204 | } 205 | .ui-layout-resizer, .ui-layout-toggler { 206 | display: none !important; 207 | } 208 | /* 209 | * Default pane print styles disables positioning, borders and backgrounds. 210 | * You can modify these styles however it suit your needs. 211 | */ 212 | .ui-layout-pane { 213 | border: none !important; 214 | background: transparent !important; 215 | position: relative !important; 216 | top: auto !important; 217 | bottom: auto !important; 218 | left: auto !important; 219 | right: auto !important; 220 | width: auto !important; 221 | height: auto !important; 222 | overflow: visible !important; 223 | } 224 | } -------------------------------------------------------------------------------- /less/style.less: -------------------------------------------------------------------------------- 1 | @import "all.css"; 2 | 3 | body { 4 | color: #333; 5 | font-size:13px; 6 | font-family: 'Open Sans', sans-serif; 7 | background-color: white; 8 | margin: 0px; 9 | overflow: hidden; 10 | 11 | -webkit-touch-callout: none; 12 | -webkit-user-select: none; 13 | -khtml-user-select: none; 14 | -moz-user-select: none; 15 | -ms-user-select: none; 16 | user-select: none; 17 | } 18 | 19 | #messages { 20 | position: absolute; 21 | left: 10px; 22 | bottom: 10px; 23 | font-size: 12px; 24 | color: #999; 25 | font-family: 'Consolas', 'Menlo', 'Monaco', Monospace; 26 | } 27 | 28 | #container { 29 | position: absolute; 30 | left: 0px; 31 | top: 0px; 32 | width: 100%; 33 | bottom: 0px; 34 | overflow: hidden; 35 | } 36 | 37 | #control-panel { 38 | position: absolute; 39 | font-family: sans-serif; 40 | left: 0px; 41 | top: 0px; 42 | height: 200px; 43 | width: 100%; 44 | background-color: #444444; 45 | padding: 10px; 46 | box-sizing: border-box; 47 | } 48 | #control-panel .title { 49 | text-transform: uppercase; 50 | padding-bottom: 5px; 51 | } 52 | 53 | #progressBar { 54 | position: absolute; 55 | top: 0px; 56 | height: 10px; 57 | background-color: rgb(63, 184, 175); 58 | z-index: 10000 !important; 59 | box-shadow: 0px 3px 3px black; 60 | -moz-box-shadow: 0px 3px 3px black; 61 | -webkit-box-shadow: 0px 3px 3px black; 62 | } 63 | 64 | /* format the text inside the toggler */ 65 | .ui-layout-toggler .content { 66 | font-size: 12px; /* IMPORTANT: default = 1px */ 67 | font-weight: bold; 68 | text-align: center; 69 | color: green; 70 | } 71 | 72 | // 'important' required ONLY when applyDefaultStyles=true 73 | .ui-layout-resizer { 74 | background-color: #666 !important; 75 | } 76 | 77 | .ui-layout-east { 78 | background-color: #666; 79 | padding: 0px; 80 | margin: 0px; 81 | } 82 | 83 | #mainActions { 84 | width: 100%; 85 | box-sizing: border-box; 86 | } 87 | 88 | .section { 89 | margin-bottom: 20px; 90 | } 91 | 92 | .section h3 { 93 | color: #666; 94 | font-weight: bold; 95 | text-transform: uppercase; 96 | font-size: 18px; 97 | padding: 0px; 98 | margin: 0px; 99 | } 100 | 101 | .p-head { 102 | border-bottom: 1px solid #666; 103 | padding: 5px; 104 | margin: 0 0 10px 0; 105 | box-sizing: border-box; 106 | } 107 | 108 | .props { 109 | table-layout: fixed; 110 | width: 100%; 111 | max-width: 100%; 112 | box-sizing: border-box; 113 | word-wrap: break-word; 114 | } 115 | 116 | .props tr td:last-child { 117 | text-align: right; 118 | font-weight: bold; 119 | } 120 | 121 | .btn-file { 122 | position: relative; 123 | overflow: hidden; 124 | } 125 | .btn-file input[type=file] { 126 | position: absolute; 127 | top: 0; 128 | right: 0; 129 | min-width: 100%; 130 | min-height: 100%; 131 | font-size: 999px; 132 | text-align: right; 133 | filter: alpha(opacity=0); 134 | opacity: 0; 135 | outline: none; 136 | background: white; 137 | cursor: inherit; 138 | display: block; 139 | } 140 | 141 | .labeled-controls { 142 | position: relative; 143 | margin-bottom: 20px; 144 | background-color: #eee; 145 | padding: 15px 10px; 146 | } 147 | .labeled-controls h4 { 148 | color: #3E754E; 149 | text-transform: uppercase; 150 | font-weight: bold; 151 | font-size: 15px; 152 | margin: 0px; 153 | } 154 | 155 | .labeled-controls h5 { 156 | margin-top: 5px; 157 | margin-bottom: 15px; 158 | color: #aaa; 159 | font-size: 12px; 160 | line-height: 14px; 161 | letter-spacing: 0px; 162 | } 163 | .map-picker { 164 | text-align: center; 165 | } 166 | 167 | .map-picker img { 168 | height: 10px; 169 | width: 75%; 170 | } 171 | 172 | #browse .dropdown-lead{ 173 | width: 92%; 174 | box-sizing: border-box; 175 | } 176 | #browse .dropdown-toggle{ 177 | width: 8%; 178 | box-sizing: border-box; 179 | } 180 | 181 | #browseCancel { 182 | margin-top: 5px; 183 | button { 184 | width: 100%; 185 | box-sizing: border-box; 186 | } 187 | } 188 | 189 | .blend-factor { 190 | margin-top: 10px; 191 | } 192 | .blend-factor div { 193 | color: #aaa; 194 | font-size: 10px; 195 | text-transform: uppercase; 196 | } 197 | 198 | .title { 199 | margin-bottom: 50px; 200 | } 201 | 202 | .title h1{ 203 | margin: 0px; 204 | font-size: 70px; 205 | opacity: 0.7; 206 | font-family: 'Archivo Black', sans-serif; 207 | color: rgb(63, 115, 10); 208 | letter-spacing: -3px; 209 | } 210 | 211 | .fullscreen .title .name { 212 | margin-top: 200px; 213 | width: 100%; 214 | text-align: center; 215 | font-size: 70px; 216 | font-family: 'Archivo Black', sans-serif; 217 | color: #777; 218 | text-shadow: 0 1px 2px #fff; 219 | letter-spacing: -3px; 220 | } 221 | 222 | .fullscreen { 223 | position: absolute; 224 | z-index: 10000 !important; 225 | left: 0px; 226 | width: 100%; 227 | top: 0px; 228 | height: 100%; 229 | background-color: #ddd; 230 | text-align: center; 231 | background: rgb(229,229,229); /* Old browsers */ 232 | background: -moz-linear-gradient(top, rgba(229,229,229,1) 0%, rgba(255,255,255,1) 100%); /* FF3.6+ */ 233 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(229,229,229,1)), color-stop(100%,rgba(255,255,255,1))); /* Chrome,Safari4+ */ 234 | background: -webkit-linear-gradient(top, rgba(229,229,229,1) 0%,rgba(255,255,255,1) 100%); /* Chrome10+,Safari5.1+ */ 235 | background: -o-linear-gradient(top, rgba(229,229,229,1) 0%,rgba(255,255,255,1) 100%); /* Opera 11.10+ */ 236 | background: -ms-linear-gradient(top, rgba(229,229,229,1) 0%,rgba(255,255,255,1) 100%); /* IE10+ */ 237 | background: linear-gradient(to bottom, rgba(229,229,229,1) 0%,rgba(255,255,255,1) 100%); /* W3C */ 238 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e5e5e5', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */ 239 | } 240 | 241 | .drag-and-drop { 242 | position: absolute; 243 | left: 0px; 244 | top: 0px; 245 | width: 100%; 246 | height: 100%; 247 | z-index: 5000 !important; 248 | border: 15px dashed #484; 249 | box-sizing: border-box; 250 | background:transparent; 251 | } 252 | .drag-and-drop .title { 253 | position: absolute; 254 | top: 50%; 255 | width: 100%; 256 | color: #484; 257 | font-size: 50px; 258 | height: 60px; 259 | margin-top: -30px; 260 | font-weight: bold; 261 | text-align: center; 262 | left: 0px; 263 | vertical-align: middle; 264 | text-shadow: 1px -1px white, 1px 1px white, -1px 1px white, -1px -1px white; 265 | } 266 | 267 | #no-support { 268 | font-size: 15px; 269 | font-weight: bold; 270 | color: #733; 271 | opacity: 0; 272 | } 273 | 274 | .toggle-control { 275 | float: right; 276 | } 277 | 278 | .p-collapse-close { 279 | border: none; 280 | } 281 | 282 | #camera-type-group .btn { 283 | width: 33%; 284 | } 285 | 286 | #creditsLink { 287 | width: 100%; 288 | text-transform: uppercase; 289 | padding-top: 5px; 290 | font-size: 12px; 291 | text-align: right; 292 | 293 | a { 294 | color: #999; 295 | } 296 | } 297 | 298 | #loadingStatus { 299 | text-align: center; 300 | width: 100%; 301 | color: #aaa; 302 | text-transform: uppercase; 303 | font-size: 12px; 304 | padding: 5px; 305 | box-sizing: border-box; 306 | } 307 | 308 | .modal-title { 309 | font-weight: 700; 310 | text-transform: uppercase; 311 | color: #3FB8AF; 312 | } 313 | 314 | .auto-play { 315 | margin-top: 20px; 316 | } 317 | 318 | #playback-fps { 319 | color: #999; 320 | padding: 10px; 321 | text-align: center; 322 | width: 100%; 323 | } 324 | 325 | #colorCanvas { 326 | margin: 10px 0px; 327 | 328 | canvas { 329 | height: 10px; 330 | width: 100%; 331 | } 332 | 333 | box-sizing: border-box; 334 | } 335 | 336 | .noun { 337 | font-style: italic; 338 | font-weight: bold; 339 | } 340 | 341 | h5.not-first { 342 | margin-top: 20px; 343 | } 344 | 345 | h4.not-first { 346 | margin-top: 20px; 347 | } 348 | 349 | #points-list-table { 350 | width: 100%; 351 | table { 352 | width: 100%; 353 | 354 | td { 355 | padding: 5px; 356 | } 357 | 358 | td:last-child { 359 | text-align: right; 360 | width: 20px; 361 | } 362 | } 363 | } 364 | 365 | 366 | .its-empty { 367 | padding-top: 5px; 368 | width: 100%; 369 | text-align: center; 370 | font-style: italic; 371 | color: #999; 372 | } 373 | 374 | .doc-tag { 375 | position: absolute; 376 | top: 10px; 377 | right: 10px; 378 | } 379 | 380 | #docsPage { 381 | p { 382 | margin: 0 0 10px 0; 383 | padding: 0px; 384 | } 385 | 386 | video { 387 | border: 1px solid #333; 388 | box-shadow: 0px 5px 5px #888888; 389 | } 390 | 391 | .tags { 392 | p { 393 | font-weight: bold; 394 | text-transform: uppercase; 395 | padding: 5px; 396 | color: #999; 397 | margin: 10px 0px 0px 0px; 398 | } 399 | 400 | button { 401 | margin-right: 5px; 402 | } 403 | } 404 | } 405 | 406 | #credits { 407 | background: rgba(255,255,255,0.8); 408 | padding: 5px; 409 | border-radius: 3px; 410 | position: absolute; 411 | right: 5px; 412 | bottom: 5px; 413 | color: black; 414 | 415 | &:before { 416 | content: 'Data Credits: '; 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plasio", 3 | "version": "0.0.1", 4 | "description": "Online LAZ/LAS file viewer", 5 | "devDependencies": { 6 | "browserify": "^14.5.0", 7 | "browserify-shim": "^3.8.14", 8 | "chai": "^4.1.2", 9 | "classnames": "^2.2.5", 10 | "connect": "^3.6.5", 11 | "create-react-class": "^15.6.2", 12 | "envify": "^4.1.0", 13 | "greyhound.js": "0.0.8", 14 | "gulp": "^3.9.1", 15 | "gulp-awspublish": "^3.3.0", 16 | "gulp-browserify": "^0.5.1", 17 | "gulp-clean": "^0.3.2", 18 | "gulp-closure-compiler": "^0.4.0", 19 | "gulp-concat": "^2.6.1", 20 | "gulp-html-replace": "^1.6.2", 21 | "gulp-jshint": "^2.0.4", 22 | "gulp-less": "^3.3.2", 23 | "gulp-livereload": "^3.8.1", 24 | "gulp-mocha": "^4.3.1", 25 | "gulp-nodemon": "^2.2.1", 26 | "gulp-react": "^3.1.0", 27 | "gulp-rename": "^1.2.2", 28 | "gulp-uglify": "^3.0.0", 29 | "gulp-util": "^3.0.8", 30 | "gulp-watch": "^4.3.11", 31 | "jshint": "^2.9.5", 32 | "jshint-jsx": "^0.5.0", 33 | "mochify": "^4.0.0", 34 | "morgan": "^1.9.0", 35 | "mori": "^0.3.2", 36 | "open": "0.0.5", 37 | "react": "^16.2.0", 38 | "react-bootstrap": "^0.31.5", 39 | "react-dom": "^16.2.0", 40 | "reactify": "^1.1.1", 41 | "serve-static": "^1.13.1" 42 | }, 43 | "scripts": { 44 | "test": "echo \"Error: no test specified\" && exit 1" 45 | }, 46 | "repository": { 47 | "type": "git", 48 | "url": "git@github.com:verma/plasio.git" 49 | }, 50 | "author": "Uday Verma & Howard Butler", 51 | "license": "MIT", 52 | "browserify": { 53 | "transform": [ 54 | "browserify-shim" 55 | ] 56 | }, 57 | "browser": { 58 | "jquery": "./vendor/jquery.js", 59 | "three": "./vendor/three.js", 60 | "bluebird": "./vendor/bluebird.js", 61 | "jqueryui": "./vendor/jquery.ui.js", 62 | "jquery-nouislider": "./vendor/jquery.nouislider.min.js", 63 | "jquery-layout": "./vendor/jquery.layout.js", 64 | "bootstrap": "./vendor/bootstrap.min.js", 65 | "trackball-controls": "./vendor/controls/TrackballControls.js", 66 | "binary-loader": "./vendor/loaders/BinaryLoader.js", 67 | "lodash": "./vendor/lodash.min.js" 68 | }, 69 | "browserify-shim": { 70 | "bluebird": "global:Promise", 71 | "jquery": "$", 72 | "jqueryui": { 73 | "depends": "jquery:$" 74 | }, 75 | "jquery-layout": { 76 | "depends": "jquery:$" 77 | }, 78 | "jquery-nouislider": { 79 | "depends": "jquery:$" 80 | }, 81 | "three": "THREE", 82 | "trackball-controls": { 83 | "depends": "three:THREE" 84 | }, 85 | "binary-loader": { 86 | "depends": "three:THREE" 87 | }, 88 | "bootstrap": { 89 | "depends": "jquery:$" 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /resources/assets/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/assets/circle.png -------------------------------------------------------------------------------- /resources/colormaps/awesome-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/awesome-green.png -------------------------------------------------------------------------------- /resources/colormaps/black-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/black-orange.png -------------------------------------------------------------------------------- /resources/colormaps/blue-hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/blue-hue.png -------------------------------------------------------------------------------- /resources/colormaps/blue-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/blue-orange.png -------------------------------------------------------------------------------- /resources/colormaps/blue-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/blue-red.png -------------------------------------------------------------------------------- /resources/colormaps/heat-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/heat-map.png -------------------------------------------------------------------------------- /resources/colormaps/pestel-shades.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/colormaps/pestel-shades.png -------------------------------------------------------------------------------- /resources/data/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /resources/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /resources/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /resources/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /resources/iowa/css/style.css: -------------------------------------------------------------------------------- 1 | /* some style */ 2 | 3 | body { 4 | background: #333; 5 | margin: 0px; 6 | padding: 0px; 7 | } 8 | 9 | #slider-area { 10 | height: 150px; 11 | position: absolute; 12 | bottom: 0px; 13 | left: 15px; 14 | right: 15px; 15 | } 16 | 17 | .intro-page { 18 | font-family: 'Century Gothic', 'Arial', sans-serif; 19 | } 20 | 21 | .intro-page h1 { 22 | text-align: center; 23 | color: #999; 24 | font-size: 5em; 25 | padding: 0px; 26 | margin: 2em 0 0 0; 27 | } 28 | 29 | .intro-page h2 { 30 | padding:0px; 31 | font-size: 1em; 32 | color: RGBA(252, 101, 246, 1); 33 | text-transform: uppercase; 34 | font-weight: 100; 35 | text-align: center; 36 | opacity: 0.5; 37 | } 38 | 39 | .intro-page .form { 40 | margin-top: 2em; 41 | } 42 | 43 | .intro-page .form { 44 | text-align: center; 45 | } 46 | 47 | .intro-page .form input[type="text"] { 48 | font-family: 'Century Gothic', 'Arial', sans-serif; 49 | display: inline-block; 50 | width: 50%; 51 | background-color: transparent; 52 | border-top: none; 53 | border-left: none; 54 | border-right: none; 55 | border-bottom: 1px solid #999; 56 | font-size: 1em; 57 | line-height: 1.1em; 58 | box-sizing: border-box; 59 | padding: 0.5em; 60 | margin: 0.5em; 61 | color: RGBA(252, 101, 246, 1); 62 | } 63 | 64 | .intro-page .form input[type="text"]:focus { 65 | outline: none; 66 | border-bottom: 1px solid RGBA(252, 101, 246, 1); 67 | } 68 | 69 | .intro-page .form .controls { 70 | margin-top: 1em; 71 | } 72 | 73 | .intro-page .form button { 74 | font-family: 'Century Gothic', 'Arial', sans-serif; 75 | display: inline-block; 76 | font-size: 1em; 77 | background-color: transparent; 78 | border: 1px solid #999; 79 | color: RGBA(252, 101, 246, 1); 80 | padding: 0.5em; 81 | margin: 0.5em; 82 | width: 20%; 83 | } 84 | 85 | .intro-page .form button:focus { 86 | outline: none; 87 | } 88 | 89 | .intro-page .form button:hover { 90 | background-color: RGBA(252, 101, 246, 1); 91 | color: black; 92 | } 93 | 94 | .intro-page .form button:disabled { 95 | background-color: #999; 96 | color: #555; 97 | } 98 | 99 | .peers { 100 | position: absolute; 101 | right: 10px; 102 | top: 10px; 103 | width: 300px; 104 | padding: 10px; 105 | font-family: 'Century Gothic', 'Arial', sans-serif; 106 | text-align: center; 107 | border-radius: 3px; 108 | color: #eee; 109 | background-color: RGBA(252, 101, 246, 0.2); 110 | } 111 | 112 | .peers a { 113 | color: #eee; 114 | text-decoration: none; 115 | } 116 | 117 | .peers a:hover { 118 | text-decoration: underline; 119 | } 120 | 121 | .peers .no-peers { 122 | font-style: italic; 123 | font-size: 0.8em; 124 | opacity: 0.7; 125 | } 126 | 127 | .peers .session-name { 128 | text-transform: uppercase; 129 | font-size: 1.5em; 130 | } 131 | 132 | 133 | .owner-mode .released { 134 | color: #999; 135 | font-size: small; 136 | } 137 | 138 | .owner-mode button { 139 | font-family: 'Century Gothic', 'Arial', sans-serif; 140 | display: inline-block; 141 | font-size: 0.7em; 142 | background-color: transparent; 143 | border: 1px solid #999; 144 | color: RGBA(252, 101, 246, 1); 145 | margin-top: 0.3em; 146 | } 147 | 148 | .owner-mode button:focus { 149 | outline: none; 150 | } 151 | 152 | .owner-mode button:hover { 153 | background-color: RGBA(252, 101, 246, 1); 154 | color: black; 155 | } 156 | 157 | .status { 158 | font-family: 'Century Gothic', 'Arial', sans-serif; 159 | position: absolute; 160 | width: 300px; 161 | margin-left: -150px; 162 | left: 50%; 163 | top: 100px; 164 | font-size: 1.5em; 165 | background-color: RGBA(252, 101, 246, 0.2); 166 | color: #aaa; 167 | padding: 1em; 168 | text-align: center; 169 | border-radius: 3px; 170 | } -------------------------------------------------------------------------------- /resources/iowa/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/jslaz/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/nepal/hobu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/nepal/hobu.png -------------------------------------------------------------------------------- /resources/nepal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 43 | 44 | Nepal 45 | 46 | 47 | 48 |
49 |
50 |
51 | 52 | 53 | 54 |
55 | Global DIRT 56 | 57 |
58 | Double click to center view, click and drag to rotate around, right click and drag to pan. 59 |
60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | 209 | 210 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /resources/nepal/workers/decompress.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o", numPoints * pointSize, "saved:", totalSaved); 34 | */ 35 | 36 | var out = Module._malloc(numPoints * pointSize); 37 | 38 | for (var i = 0 ; i < numPoints ; i ++) { 39 | x.getPoint(out + i * pointSize); 40 | } 41 | 42 | var ret = new Uint8Array(numPoints * pointSize); 43 | ret.set(Module.HEAPU8.subarray(out, out + numPoints * pointSize)); 44 | 45 | Module._free(out); 46 | Module._free(buf); 47 | 48 | var b = new Float32Array(ret.buffer); 49 | 50 | return b; 51 | }; 52 | 53 | self.onmessage = function(e) { 54 | var data = e.data; 55 | 56 | var schema = data.schema; 57 | var ab = data.buffer; 58 | var numPoints = data.pointsCount; 59 | 60 | var res = decompressBuffer(schema, ab, numPoints); 61 | postMessage({result: res}, [res.buffer]); 62 | }; 63 | 64 | },{}]},{},[1]) -------------------------------------------------------------------------------- /resources/plasio_laszip.nmf: -------------------------------------------------------------------------------- 1 | { 2 | "program": { 3 | "portable": { 4 | "pnacl-translate": { 5 | "url": "plasio_laszip.pexe" 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /resources/plasio_laszip.pexe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/plasio_laszip.pexe -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Brick_Antique.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Brick_Antique.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Brick_Colored_Blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Brick_Colored_Blue.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Color_000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Color_000.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Color_001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Color_001.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Color_001_1_.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Color_001_1_.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Color_001_2_.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Color_001_2_.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/Color_006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/Color_006.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/EmpireStateBuilding.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/EmpireStateBuilding.bin -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/EmpireStateBuilding.js: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "metadata" : 4 | { 5 | "formatVersion" : 3.1, 6 | "sourceFile" : "EmpireStateBuilding.obj", 7 | "generatedBy" : "OBJConverter", 8 | "vertices" : 24761, 9 | "faces" : 109314, 10 | "normals" : 18802, 11 | "uvs" : 71442, 12 | "materials" : 17 13 | }, 14 | 15 | "materials": [ { 16 | "DbgColor" : 15658734, 17 | "DbgIndex" : 0, 18 | "DbgName" : "_Brick_Colored_Blue_2", 19 | "colorAmbient" : [0.0, 0.0, 0.0], 20 | "colorDiffuse" : [0.513725, 0.513725, 0.505882], 21 | "colorSpecular" : [0.33, 0.33, 0.33], 22 | "mapDiffuse" : "_Brick_Colored_Blue_2.jpg" 23 | }, 24 | 25 | { 26 | "DbgColor" : 15597568, 27 | "DbgIndex" : 1, 28 | "DbgName" : "_Color_001_1", 29 | "colorAmbient" : [0.0, 0.0, 0.0], 30 | "colorDiffuse" : [0.192157, 0.192157, 0.192157], 31 | "colorSpecular" : [0.33, 0.33, 0.33], 32 | "mapDiffuse" : "_Color_001_1.jpg" 33 | }, 34 | 35 | { 36 | "DbgColor" : 60928, 37 | "DbgIndex" : 2, 38 | "DbgName" : "_Color_005_3", 39 | "colorAmbient" : [0.0, 0.0, 0.0], 40 | "colorDiffuse" : [0.133333, 0.133333, 0.133333], 41 | "colorSpecular" : [0.33, 0.33, 0.33], 42 | "mapDiffuse" : "_Color_005_3.jpg" 43 | }, 44 | 45 | { 46 | "DbgColor" : 238, 47 | "DbgIndex" : 3, 48 | "DbgName" : "Color_001", 49 | "colorAmbient" : [0.0, 0.0, 0.0], 50 | "colorDiffuse" : [0.270588, 0.270588, 0.27451], 51 | "colorSpecular" : [0.33, 0.33, 0.33], 52 | "mapDiffuse" : "Color_001.jpg" 53 | }, 54 | 55 | { 56 | "DbgColor" : 15658496, 57 | "DbgIndex" : 4, 58 | "DbgName" : "Brick_Antique", 59 | "colorAmbient" : [0.0, 0.0, 0.0], 60 | "colorDiffuse" : [0.486275, 0.466667, 0.45098], 61 | "colorSpecular" : [0.33, 0.33, 0.33], 62 | "mapDiffuse" : "Brick_Antique.jpg" 63 | }, 64 | 65 | { 66 | "DbgColor" : 61166, 67 | "DbgIndex" : 5, 68 | "DbgName" : "Color_006", 69 | "colorAmbient" : [0.0, 0.0, 0.0], 70 | "colorDiffuse" : [0.482353, 0.458824, 0.443137], 71 | "colorSpecular" : [0.33, 0.33, 0.33], 72 | "mapDiffuse" : "Color_006.jpg" 73 | }, 74 | 75 | { 76 | "DbgColor" : 15597806, 77 | "DbgIndex" : 6, 78 | "DbgName" : "_Brick_Colored_Blue_3", 79 | "colorAmbient" : [0.0, 0.0, 0.0], 80 | "colorDiffuse" : [0.243137, 0.243137, 0.243137], 81 | "colorSpecular" : [0.33, 0.33, 0.33], 82 | "mapDiffuse" : "_Brick_Colored_Blue_3.jpg" 83 | }, 84 | 85 | { 86 | "DbgColor" : 13579988, 87 | "DbgIndex" : 7, 88 | "DbgName" : "Color_000", 89 | "colorAmbient" : [0.0, 0.0, 0.0], 90 | "colorDiffuse" : [0.572549, 0.572549, 0.572549], 91 | "colorSpecular" : [0.33, 0.33, 0.33], 92 | "mapDiffuse" : "Color_000.jpg" 93 | }, 94 | 95 | { 96 | "DbgColor" : 9886237, 97 | "DbgIndex" : 8, 98 | "DbgName" : "_Brick_Rough_Dark_1", 99 | "colorAmbient" : [0.0, 0.0, 0.0], 100 | "colorDiffuse" : [0.541176, 0.509804, 0.494118], 101 | "colorSpecular" : [0.33, 0.33, 0.33], 102 | "mapDiffuse" : "_Brick_Rough_Dark_1.jpg" 103 | }, 104 | 105 | { 106 | "DbgColor" : 9142600, 107 | "DbgIndex" : 9, 108 | "DbgName" : "_Color_009_1", 109 | "colorAmbient" : [0.0, 0.0, 0.0], 110 | "colorDiffuse" : [0.576471, 0.580392, 0.572549], 111 | "colorSpecular" : [0.33, 0.33, 0.33], 112 | "mapDiffuse" : "_Color_009_1.jpg" 113 | }, 114 | 115 | { 116 | "DbgColor" : 109031, 117 | "DbgIndex" : 10, 118 | "DbgName" : "Brick_Colored_Blue", 119 | "colorAmbient" : [0.0, 0.0, 0.0], 120 | "colorDiffuse" : [0.133333, 0.133333, 0.133333], 121 | "colorSpecular" : [0.33, 0.33, 0.33], 122 | "mapDiffuse" : "Brick_Colored_Blue.jpg" 123 | }, 124 | 125 | { 126 | "DbgColor" : 3668136, 127 | "DbgIndex" : 11, 128 | "DbgName" : "_Color_005_2", 129 | "colorAmbient" : [0.0, 0.0, 0.0], 130 | "colorDiffuse" : [0.14902, 0.14902, 0.14902], 131 | "colorSpecular" : [0.33, 0.33, 0.33], 132 | "mapDiffuse" : "_Color_005_2.jpg" 133 | }, 134 | 135 | { 136 | "DbgColor" : 10903250, 137 | "DbgIndex" : 12, 138 | "DbgName" : "_Color_006_3", 139 | "colorAmbient" : [0.0, 0.0, 0.0], 140 | "colorDiffuse" : [0.043137, 0.043137, 0.043137], 141 | "colorSpecular" : [0.33, 0.33, 0.33], 142 | "mapDiffuse" : "_Color_006_3.jpg" 143 | }, 144 | 145 | { 146 | "DbgColor" : 445199, 147 | "DbgIndex" : 13, 148 | "DbgName" : "_Brick_Antique_1", 149 | "colorAmbient" : [0.0, 0.0, 0.0], 150 | "colorDiffuse" : [0.745098, 0.694118, 0.639216], 151 | "colorSpecular" : [0.33, 0.33, 0.33], 152 | "mapDiffuse" : "_Brick_Antique_1.jpg" 153 | }, 154 | 155 | { 156 | "DbgColor" : 3698379, 157 | "DbgIndex" : 14, 158 | "DbgName" : "Color_001_1_", 159 | "colorAmbient" : [0.0, 0.0, 0.0], 160 | "colorDiffuse" : [0.270588, 0.270588, 0.27451], 161 | "colorSpecular" : [0.33, 0.33, 0.33], 162 | "mapDiffuse" : "Color_001_1_.jpg" 163 | }, 164 | 165 | { 166 | "DbgColor" : 3335942, 167 | "DbgIndex" : 15, 168 | "DbgName" : "Color_001_2_", 169 | "colorAmbient" : [0.0, 0.0, 0.0], 170 | "colorDiffuse" : [0.270588, 0.270588, 0.27451], 171 | "colorSpecular" : [0.33, 0.33, 0.33], 172 | "mapDiffuse" : "Color_001_2_.jpg" 173 | }, 174 | 175 | { 176 | "DbgColor" : 8478454, 177 | "DbgIndex" : 16, 178 | "DbgName" : "_Color_005_5", 179 | "colorAmbient" : [0.0, 0.0, 0.0], 180 | "colorDiffuse" : [0.215686, 0.215686, 0.215686], 181 | "colorSpecular" : [0.33, 0.33, 0.33], 182 | "mapDiffuse" : "_Color_005_5.jpg" 183 | }], 184 | 185 | "buffers": "EmpireStateBuilding.bin" 186 | 187 | } 188 | -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Brick_Antique_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Brick_Antique_1.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Brick_Colored_Blue_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Brick_Colored_Blue_2.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Brick_Colored_Blue_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Brick_Colored_Blue_3.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Brick_Rough_Dark_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Brick_Rough_Dark_1.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Color_001_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Color_001_1.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Color_005_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Color_005_2.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Color_005_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Color_005_3.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Color_005_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Color_005_5.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Color_006_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Color_006_3.jpg -------------------------------------------------------------------------------- /resources/scale-objects/EmpireStateBuilding/_Color_009_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/resources/scale-objects/EmpireStateBuilding/_Color_009_1.jpg -------------------------------------------------------------------------------- /test/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2014 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jasmine Spec Runner v2.0.3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/lib/jasmine-2.0.3/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. 3 | 4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. 5 | 6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. 7 | 8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem 9 | */ 10 | 11 | (function() { 12 | 13 | /** 14 | * ## Require & Instantiate 15 | * 16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. 17 | */ 18 | window.jasmine = jasmineRequire.core(jasmineRequire); 19 | 20 | /** 21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. 22 | */ 23 | jasmineRequire.html(jasmine); 24 | 25 | /** 26 | * Create the Jasmine environment. This is used to run all specs in a project. 27 | */ 28 | var env = jasmine.getEnv(); 29 | 30 | /** 31 | * ## The Global Interface 32 | * 33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. 34 | */ 35 | var jasmineInterface = jasmineRequire.interface(jasmine, env); 36 | 37 | /** 38 | * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. 39 | */ 40 | if (typeof window == "undefined" && typeof exports == "object") { 41 | extend(exports, jasmineInterface); 42 | } else { 43 | extend(window, jasmineInterface); 44 | } 45 | 46 | /** 47 | * ## Runner Parameters 48 | * 49 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. 50 | */ 51 | 52 | var queryString = new jasmine.QueryString({ 53 | getWindowLocation: function() { return window.location; } 54 | }); 55 | 56 | var catchingExceptions = queryString.getParam("catch"); 57 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions); 58 | 59 | /** 60 | * ## Reporters 61 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). 62 | */ 63 | var htmlReporter = new jasmine.HtmlReporter({ 64 | env: env, 65 | onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, 66 | getContainer: function() { return document.body; }, 67 | createElement: function() { return document.createElement.apply(document, arguments); }, 68 | createTextNode: function() { return document.createTextNode.apply(document, arguments); }, 69 | timer: new jasmine.Timer() 70 | }); 71 | 72 | /** 73 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. 74 | */ 75 | env.addReporter(jasmineInterface.jsApiReporter); 76 | env.addReporter(htmlReporter); 77 | 78 | /** 79 | * Filter which specs will be run by matching the start of the full name against the `spec` query param. 80 | */ 81 | var specFilter = new jasmine.HtmlSpecFilter({ 82 | filterString: function() { return queryString.getParam("spec"); } 83 | }); 84 | 85 | env.specFilter = function(spec) { 86 | return specFilter.matches(spec.getFullName()); 87 | }; 88 | 89 | /** 90 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. 91 | */ 92 | window.setTimeout = window.setTimeout; 93 | window.setInterval = window.setInterval; 94 | window.clearTimeout = window.clearTimeout; 95 | window.clearInterval = window.clearInterval; 96 | 97 | /** 98 | * ## Execution 99 | * 100 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 101 | */ 102 | var currentWindowOnload = window.onload; 103 | 104 | window.onload = function() { 105 | if (currentWindowOnload) { 106 | currentWindowOnload(); 107 | } 108 | htmlReporter.initialize(); 109 | env.execute(); 110 | }; 111 | 112 | /** 113 | * Helper function for readability above. 114 | */ 115 | function extend(destination, source) { 116 | for (var property in source) destination[property] = source[property]; 117 | return destination; 118 | } 119 | 120 | }()); 121 | -------------------------------------------------------------------------------- /test/lib/jasmine-2.0.3/console.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | function getJasmineRequireObj() { 24 | if (typeof module !== 'undefined' && module.exports) { 25 | return exports; 26 | } else { 27 | window.jasmineRequire = window.jasmineRequire || {}; 28 | return window.jasmineRequire; 29 | } 30 | } 31 | 32 | getJasmineRequireObj().console = function(jRequire, j$) { 33 | j$.ConsoleReporter = jRequire.ConsoleReporter(); 34 | }; 35 | 36 | getJasmineRequireObj().ConsoleReporter = function() { 37 | 38 | var noopTimer = { 39 | start: function(){}, 40 | elapsed: function(){ return 0; } 41 | }; 42 | 43 | function ConsoleReporter(options) { 44 | var print = options.print, 45 | showColors = options.showColors || false, 46 | onComplete = options.onComplete || function() {}, 47 | timer = options.timer || noopTimer, 48 | specCount, 49 | failureCount, 50 | failedSpecs = [], 51 | pendingCount, 52 | ansi = { 53 | green: '\x1B[32m', 54 | red: '\x1B[31m', 55 | yellow: '\x1B[33m', 56 | none: '\x1B[0m' 57 | }; 58 | 59 | this.jasmineStarted = function() { 60 | specCount = 0; 61 | failureCount = 0; 62 | pendingCount = 0; 63 | print('Started'); 64 | printNewline(); 65 | timer.start(); 66 | }; 67 | 68 | this.jasmineDone = function() { 69 | printNewline(); 70 | for (var i = 0; i < failedSpecs.length; i++) { 71 | specFailureDetails(failedSpecs[i]); 72 | } 73 | 74 | if(specCount > 0) { 75 | printNewline(); 76 | 77 | var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' + 78 | failureCount + ' ' + plural('failure', failureCount); 79 | 80 | if (pendingCount) { 81 | specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount); 82 | } 83 | 84 | print(specCounts); 85 | } else { 86 | print('No specs found'); 87 | } 88 | 89 | printNewline(); 90 | var seconds = timer.elapsed() / 1000; 91 | print('Finished in ' + seconds + ' ' + plural('second', seconds)); 92 | 93 | printNewline(); 94 | 95 | onComplete(failureCount === 0); 96 | }; 97 | 98 | this.specDone = function(result) { 99 | specCount++; 100 | 101 | if (result.status == 'pending') { 102 | pendingCount++; 103 | print(colored('yellow', '*')); 104 | return; 105 | } 106 | 107 | if (result.status == 'passed') { 108 | print(colored('green', '.')); 109 | return; 110 | } 111 | 112 | if (result.status == 'failed') { 113 | failureCount++; 114 | failedSpecs.push(result); 115 | print(colored('red', 'F')); 116 | } 117 | }; 118 | 119 | return this; 120 | 121 | function printNewline() { 122 | print('\n'); 123 | } 124 | 125 | function colored(color, str) { 126 | return showColors ? (ansi[color] + str + ansi.none) : str; 127 | } 128 | 129 | function plural(str, count) { 130 | return count == 1 ? str : str + 's'; 131 | } 132 | 133 | function repeat(thing, times) { 134 | var arr = []; 135 | for (var i = 0; i < times; i++) { 136 | arr.push(thing); 137 | } 138 | return arr; 139 | } 140 | 141 | function indent(str, spaces) { 142 | var lines = (str || '').split('\n'); 143 | var newArr = []; 144 | for (var i = 0; i < lines.length; i++) { 145 | newArr.push(repeat(' ', spaces).join('') + lines[i]); 146 | } 147 | return newArr.join('\n'); 148 | } 149 | 150 | function specFailureDetails(result) { 151 | printNewline(); 152 | print(result.fullName); 153 | 154 | for (var i = 0; i < result.failedExpectations.length; i++) { 155 | var failedExpectation = result.failedExpectations[i]; 156 | printNewline(); 157 | print(indent(failedExpectation.message, 2)); 158 | print(indent(failedExpectation.stack, 2)); 159 | } 160 | 161 | printNewline(); 162 | } 163 | } 164 | 165 | return ConsoleReporter; 166 | }; 167 | -------------------------------------------------------------------------------- /test/lib/jasmine-2.0.3/jasmine-html.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | jasmineRequire.html = function(j$) { 24 | j$.ResultsNode = jasmineRequire.ResultsNode(); 25 | j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); 26 | j$.QueryString = jasmineRequire.QueryString(); 27 | j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); 28 | }; 29 | 30 | jasmineRequire.HtmlReporter = function(j$) { 31 | 32 | var noopTimer = { 33 | start: function() {}, 34 | elapsed: function() { return 0; } 35 | }; 36 | 37 | function HtmlReporter(options) { 38 | var env = options.env || {}, 39 | getContainer = options.getContainer, 40 | createElement = options.createElement, 41 | createTextNode = options.createTextNode, 42 | onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {}, 43 | timer = options.timer || noopTimer, 44 | results = [], 45 | specsExecuted = 0, 46 | failureCount = 0, 47 | pendingSpecCount = 0, 48 | htmlReporterMain, 49 | symbols; 50 | 51 | this.initialize = function() { 52 | clearPrior(); 53 | htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'}, 54 | createDom('div', {className: 'banner'}, 55 | createDom('a', {className: 'title', href: 'http://jasmine.github.io/', target: '_blank'}), 56 | createDom('span', {className: 'version'}, j$.version) 57 | ), 58 | createDom('ul', {className: 'symbol-summary'}), 59 | createDom('div', {className: 'alert'}), 60 | createDom('div', {className: 'results'}, 61 | createDom('div', {className: 'failures'}) 62 | ) 63 | ); 64 | getContainer().appendChild(htmlReporterMain); 65 | 66 | symbols = find('.symbol-summary'); 67 | }; 68 | 69 | var totalSpecsDefined; 70 | this.jasmineStarted = function(options) { 71 | totalSpecsDefined = options.totalSpecsDefined || 0; 72 | timer.start(); 73 | }; 74 | 75 | var summary = createDom('div', {className: 'summary'}); 76 | 77 | var topResults = new j$.ResultsNode({}, '', null), 78 | currentParent = topResults; 79 | 80 | this.suiteStarted = function(result) { 81 | currentParent.addChild(result, 'suite'); 82 | currentParent = currentParent.last(); 83 | }; 84 | 85 | this.suiteDone = function(result) { 86 | if (currentParent == topResults) { 87 | return; 88 | } 89 | 90 | currentParent = currentParent.parent; 91 | }; 92 | 93 | this.specStarted = function(result) { 94 | currentParent.addChild(result, 'spec'); 95 | }; 96 | 97 | var failures = []; 98 | this.specDone = function(result) { 99 | if(noExpectations(result) && console && console.error) { 100 | console.error('Spec \'' + result.fullName + '\' has no expectations.'); 101 | } 102 | 103 | if (result.status != 'disabled') { 104 | specsExecuted++; 105 | } 106 | 107 | symbols.appendChild(createDom('li', { 108 | className: noExpectations(result) ? 'empty' : result.status, 109 | id: 'spec_' + result.id, 110 | title: result.fullName 111 | } 112 | )); 113 | 114 | if (result.status == 'failed') { 115 | failureCount++; 116 | 117 | var failure = 118 | createDom('div', {className: 'spec-detail failed'}, 119 | createDom('div', {className: 'description'}, 120 | createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName) 121 | ), 122 | createDom('div', {className: 'messages'}) 123 | ); 124 | var messages = failure.childNodes[1]; 125 | 126 | for (var i = 0; i < result.failedExpectations.length; i++) { 127 | var expectation = result.failedExpectations[i]; 128 | messages.appendChild(createDom('div', {className: 'result-message'}, expectation.message)); 129 | messages.appendChild(createDom('div', {className: 'stack-trace'}, expectation.stack)); 130 | } 131 | 132 | failures.push(failure); 133 | } 134 | 135 | if (result.status == 'pending') { 136 | pendingSpecCount++; 137 | } 138 | }; 139 | 140 | this.jasmineDone = function() { 141 | var banner = find('.banner'); 142 | banner.appendChild(createDom('span', {className: 'duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); 143 | 144 | var alert = find('.alert'); 145 | 146 | alert.appendChild(createDom('span', { className: 'exceptions' }, 147 | createDom('label', { className: 'label', 'for': 'raise-exceptions' }, 'raise exceptions'), 148 | createDom('input', { 149 | className: 'raise', 150 | id: 'raise-exceptions', 151 | type: 'checkbox' 152 | }) 153 | )); 154 | var checkbox = find('#raise-exceptions'); 155 | 156 | checkbox.checked = !env.catchingExceptions(); 157 | checkbox.onclick = onRaiseExceptionsClick; 158 | 159 | if (specsExecuted < totalSpecsDefined) { 160 | var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; 161 | alert.appendChild( 162 | createDom('span', {className: 'bar skipped'}, 163 | createDom('a', {href: '?', title: 'Run all specs'}, skippedMessage) 164 | ) 165 | ); 166 | } 167 | var statusBarMessage = ''; 168 | var statusBarClassName = 'bar '; 169 | 170 | if (totalSpecsDefined > 0) { 171 | statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount); 172 | if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); } 173 | statusBarClassName += (failureCount > 0) ? 'failed' : 'passed'; 174 | } else { 175 | statusBarClassName += 'skipped'; 176 | statusBarMessage += 'No specs found'; 177 | } 178 | 179 | alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage)); 180 | 181 | var results = find('.results'); 182 | results.appendChild(summary); 183 | 184 | summaryList(topResults, summary); 185 | 186 | function summaryList(resultsTree, domParent) { 187 | var specListNode; 188 | for (var i = 0; i < resultsTree.children.length; i++) { 189 | var resultNode = resultsTree.children[i]; 190 | if (resultNode.type == 'suite') { 191 | var suiteListNode = createDom('ul', {className: 'suite', id: 'suite-' + resultNode.result.id}, 192 | createDom('li', {className: 'suite-detail'}, 193 | createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description) 194 | ) 195 | ); 196 | 197 | summaryList(resultNode, suiteListNode); 198 | domParent.appendChild(suiteListNode); 199 | } 200 | if (resultNode.type == 'spec') { 201 | if (domParent.getAttribute('class') != 'specs') { 202 | specListNode = createDom('ul', {className: 'specs'}); 203 | domParent.appendChild(specListNode); 204 | } 205 | var specDescription = resultNode.result.description; 206 | if(noExpectations(resultNode.result)) { 207 | specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; 208 | } 209 | specListNode.appendChild( 210 | createDom('li', { 211 | className: resultNode.result.status, 212 | id: 'spec-' + resultNode.result.id 213 | }, 214 | createDom('a', {href: specHref(resultNode.result)}, specDescription) 215 | ) 216 | ); 217 | } 218 | } 219 | } 220 | 221 | if (failures.length) { 222 | alert.appendChild( 223 | createDom('span', {className: 'menu bar spec-list'}, 224 | createDom('span', {}, 'Spec List | '), 225 | createDom('a', {className: 'failures-menu', href: '#'}, 'Failures'))); 226 | alert.appendChild( 227 | createDom('span', {className: 'menu bar failure-list'}, 228 | createDom('a', {className: 'spec-list-menu', href: '#'}, 'Spec List'), 229 | createDom('span', {}, ' | Failures '))); 230 | 231 | find('.failures-menu').onclick = function() { 232 | setMenuModeTo('failure-list'); 233 | }; 234 | find('.spec-list-menu').onclick = function() { 235 | setMenuModeTo('spec-list'); 236 | }; 237 | 238 | setMenuModeTo('failure-list'); 239 | 240 | var failureNode = find('.failures'); 241 | for (var i = 0; i < failures.length; i++) { 242 | failureNode.appendChild(failures[i]); 243 | } 244 | } 245 | }; 246 | 247 | return this; 248 | 249 | function find(selector) { 250 | return getContainer().querySelector('.jasmine_html-reporter ' + selector); 251 | } 252 | 253 | function clearPrior() { 254 | // return the reporter 255 | var oldReporter = find(''); 256 | 257 | if(oldReporter) { 258 | getContainer().removeChild(oldReporter); 259 | } 260 | } 261 | 262 | function createDom(type, attrs, childrenVarArgs) { 263 | var el = createElement(type); 264 | 265 | for (var i = 2; i < arguments.length; i++) { 266 | var child = arguments[i]; 267 | 268 | if (typeof child === 'string') { 269 | el.appendChild(createTextNode(child)); 270 | } else { 271 | if (child) { 272 | el.appendChild(child); 273 | } 274 | } 275 | } 276 | 277 | for (var attr in attrs) { 278 | if (attr == 'className') { 279 | el[attr] = attrs[attr]; 280 | } else { 281 | el.setAttribute(attr, attrs[attr]); 282 | } 283 | } 284 | 285 | return el; 286 | } 287 | 288 | function pluralize(singular, count) { 289 | var word = (count == 1 ? singular : singular + 's'); 290 | 291 | return '' + count + ' ' + word; 292 | } 293 | 294 | function specHref(result) { 295 | return '?spec=' + encodeURIComponent(result.fullName); 296 | } 297 | 298 | function setMenuModeTo(mode) { 299 | htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode); 300 | } 301 | 302 | function noExpectations(result) { 303 | return (result.failedExpectations.length + result.passedExpectations.length) === 0 && 304 | result.status === 'passed'; 305 | } 306 | } 307 | 308 | return HtmlReporter; 309 | }; 310 | 311 | jasmineRequire.HtmlSpecFilter = function() { 312 | function HtmlSpecFilter(options) { 313 | var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); 314 | var filterPattern = new RegExp(filterString); 315 | 316 | this.matches = function(specName) { 317 | return filterPattern.test(specName); 318 | }; 319 | } 320 | 321 | return HtmlSpecFilter; 322 | }; 323 | 324 | jasmineRequire.ResultsNode = function() { 325 | function ResultsNode(result, type, parent) { 326 | this.result = result; 327 | this.type = type; 328 | this.parent = parent; 329 | 330 | this.children = []; 331 | 332 | this.addChild = function(result, type) { 333 | this.children.push(new ResultsNode(result, type, this)); 334 | }; 335 | 336 | this.last = function() { 337 | return this.children[this.children.length - 1]; 338 | }; 339 | } 340 | 341 | return ResultsNode; 342 | }; 343 | 344 | jasmineRequire.QueryString = function() { 345 | function QueryString(options) { 346 | 347 | this.setParam = function(key, value) { 348 | var paramMap = queryStringToParamMap(); 349 | paramMap[key] = value; 350 | options.getWindowLocation().search = toQueryString(paramMap); 351 | }; 352 | 353 | this.getParam = function(key) { 354 | return queryStringToParamMap()[key]; 355 | }; 356 | 357 | return this; 358 | 359 | function toQueryString(paramMap) { 360 | var qStrPairs = []; 361 | for (var prop in paramMap) { 362 | qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])); 363 | } 364 | return '?' + qStrPairs.join('&'); 365 | } 366 | 367 | function queryStringToParamMap() { 368 | var paramStr = options.getWindowLocation().search.substring(1), 369 | params = [], 370 | paramMap = {}; 371 | 372 | if (paramStr.length > 0) { 373 | params = paramStr.split('&'); 374 | for (var i = 0; i < params.length; i++) { 375 | var p = params[i].split('='); 376 | var value = decodeURIComponent(p[1]); 377 | if (value === 'true' || value === 'false') { 378 | value = JSON.parse(value); 379 | } 380 | paramMap[decodeURIComponent(p[0])] = value; 381 | } 382 | } 383 | 384 | return paramMap; 385 | } 386 | 387 | } 388 | 389 | return QueryString; 390 | }; 391 | -------------------------------------------------------------------------------- /test/lib/jasmine-2.0.3/jasmine.css: -------------------------------------------------------------------------------- 1 | body { overflow-y: scroll; } 2 | 3 | .jasmine_html-reporter { background-color: #eeeeee; padding: 5px; margin: -8px; font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | .jasmine_html-reporter a { text-decoration: none; } 5 | .jasmine_html-reporter a:hover { text-decoration: underline; } 6 | .jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 { margin: 0; line-height: 14px; } 7 | .jasmine_html-reporter .banner, .jasmine_html-reporter .symbol-summary, .jasmine_html-reporter .summary, .jasmine_html-reporter .result-message, .jasmine_html-reporter .spec .description, .jasmine_html-reporter .spec-detail .description, .jasmine_html-reporter .alert .bar, .jasmine_html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; } 8 | .jasmine_html-reporter .banner { position: relative; } 9 | .jasmine_html-reporter .banner .title { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==') no-repeat; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=') no-repeat, none; -webkit-background-size: 100%; -moz-background-size: 100%; -o-background-size: 100%; background-size: 100%; display: block; float: left; width: 90px; height: 25px; } 10 | .jasmine_html-reporter .banner .version { margin-left: 14px; position: relative; top: 6px; } 11 | .jasmine_html-reporter .banner .duration { position: absolute; right: 14px; top: 6px; } 12 | .jasmine_html-reporter #jasmine_content { position: fixed; right: 100%; } 13 | .jasmine_html-reporter .version { color: #aaaaaa; } 14 | .jasmine_html-reporter .banner { margin-top: 14px; } 15 | .jasmine_html-reporter .duration { color: #aaaaaa; float: right; } 16 | .jasmine_html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } 17 | .jasmine_html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; } 18 | .jasmine_html-reporter .symbol-summary li.passed { font-size: 14px; } 19 | .jasmine_html-reporter .symbol-summary li.passed:before { color: #007069; content: "\02022"; } 20 | .jasmine_html-reporter .symbol-summary li.failed { line-height: 9px; } 21 | .jasmine_html-reporter .symbol-summary li.failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; } 22 | .jasmine_html-reporter .symbol-summary li.disabled { font-size: 14px; } 23 | .jasmine_html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; } 24 | .jasmine_html-reporter .symbol-summary li.pending { line-height: 17px; } 25 | .jasmine_html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; } 26 | .jasmine_html-reporter .symbol-summary li.empty { font-size: 14px; } 27 | .jasmine_html-reporter .symbol-summary li.empty:before { color: #ba9d37; content: "\02022"; } 28 | .jasmine_html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 29 | .jasmine_html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 30 | .jasmine_html-reporter .bar.failed { background-color: #ca3a11; } 31 | .jasmine_html-reporter .bar.passed { background-color: #007069; } 32 | .jasmine_html-reporter .bar.skipped { background-color: #bababa; } 33 | .jasmine_html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } 34 | .jasmine_html-reporter .bar.menu a { color: #333333; } 35 | .jasmine_html-reporter .bar a { color: white; } 36 | .jasmine_html-reporter.spec-list .bar.menu.failure-list, .jasmine_html-reporter.spec-list .results .failures { display: none; } 37 | .jasmine_html-reporter.failure-list .bar.menu.spec-list, .jasmine_html-reporter.failure-list .summary { display: none; } 38 | .jasmine_html-reporter .running-alert { background-color: #666666; } 39 | .jasmine_html-reporter .results { margin-top: 14px; } 40 | .jasmine_html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 41 | .jasmine_html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 42 | .jasmine_html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 43 | .jasmine_html-reporter.showDetails .summary { display: none; } 44 | .jasmine_html-reporter.showDetails #details { display: block; } 45 | .jasmine_html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 46 | .jasmine_html-reporter .summary { margin-top: 14px; } 47 | .jasmine_html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } 48 | .jasmine_html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; } 49 | .jasmine_html-reporter .summary li.passed a { color: #007069; } 50 | .jasmine_html-reporter .summary li.failed a { color: #ca3a11; } 51 | .jasmine_html-reporter .summary li.empty a { color: #ba9d37; } 52 | .jasmine_html-reporter .summary li.pending a { color: #ba9d37; } 53 | .jasmine_html-reporter .description + .suite { margin-top: 0; } 54 | .jasmine_html-reporter .suite { margin-top: 14px; } 55 | .jasmine_html-reporter .suite a { color: #333333; } 56 | .jasmine_html-reporter .failures .spec-detail { margin-bottom: 28px; } 57 | .jasmine_html-reporter .failures .spec-detail .description { background-color: #ca3a11; } 58 | .jasmine_html-reporter .failures .spec-detail .description a { color: white; } 59 | .jasmine_html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; } 60 | .jasmine_html-reporter .result-message span.result { display: block; } 61 | .jasmine_html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 62 | -------------------------------------------------------------------------------- /test/lib/jasmine-2.0.3/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/test/lib/jasmine-2.0.3/jasmine_favicon.png -------------------------------------------------------------------------------- /test/spec/gh-reader-test.js: -------------------------------------------------------------------------------- 1 | var gh = require('../../js/greyhound'); 2 | 3 | 4 | describe("Schema", function() { 5 | it("should be empty by itself", function() { 6 | expect(gh.Schema()).toEqual([]); 7 | }); 8 | 9 | it("should have correct items in added order", function() { 10 | var s = gh.Schema().X().Y().Z(); 11 | expect(s.length).toBe(3); 12 | expect(s[0]).toEqual({name: "X", type:"floating", size: 4}); 13 | expect(s[1]).toEqual({name: "Y", type:"floating", size: 4}); 14 | expect(s[2]).toEqual({name: "Z", type:"floating", size: 4}); 15 | }); 16 | 17 | it("should add using the correct type and size", function() { 18 | var s = gh.Schema().X("unsigned", 2).Red("floating", 8); 19 | 20 | expect(s.length).toBe(2); 21 | expect(s[0]).toEqual({name: "X", type: "unsigned", size: 2}); 22 | expect(s[1]).toEqual({name: "Red", type: "floating", size: 8}); 23 | }); 24 | 25 | it("should have a standard layout with default fields", function() { 26 | var s = gh.Schema.standard(); 27 | 28 | expect(s.length).toBe(7); 29 | expect(s[0]).toEqual({name: "X", type:"floating", size: 4}); 30 | expect(s[1]).toEqual({name: "Y", type:"floating", size: 4}); 31 | expect(s[2]).toEqual({name: "Z", type:"floating", size: 4}); 32 | expect(s[3]).toEqual({name: "Intensity", type:"unsigned", size: 2}); 33 | expect(s[4]).toEqual({name: "Red", type:"unsigned", size: 2}); 34 | expect(s[5]).toEqual({name: "Green", type:"unsigned", size: 2}); 35 | expect(s[6]).toEqual({name: "Blue", type:"unsigned", size: 2}); 36 | }); 37 | 38 | it("should have a XYZ only schema", function() { 39 | var s = gh.Schema.XYZ(); 40 | 41 | expect(s.length).toBe(3); 42 | expect(s[0]).toEqual({name: "X", type:"floating", size: 4}); 43 | expect(s[1]).toEqual({name: "Y", type:"floating", size: 4}); 44 | expect(s[2]).toEqual({name: "Z", type:"floating", size: 4}); 45 | }); 46 | }); 47 | 48 | describe("GreyhoundReader", function() { 49 | it("should error if no host is provided", function() { 50 | var f = function() { 51 | new gh.GreyhoundReader(); 52 | }; 53 | 54 | expect(f).toThrowError('Need hostname to initialize reader'); 55 | }); 56 | 57 | it("should correctly store passed hostname", function() { 58 | var s = new gh.GreyhoundReader("localhost"); 59 | 60 | expect(s.getHost()).toBe("localhost"); 61 | }); 62 | 63 | it("should not accept hostname if it specified protocol", function() { 64 | var f1 = function() { 65 | var s = new gh.GreyhoundReader("ws://localhost"); 66 | }; 67 | 68 | var f2 = function() { 69 | var s = new gh.GreyhoundReader("http://localhost"); 70 | }; 71 | 72 | expect(f1).toThrowError("Protocol specified, need bare hostname"); 73 | expect(f2).toThrowError("Protocol specified, need bare hostname"); 74 | }); 75 | 76 | it("should correctly decipher port", function() { 77 | var s = new gh.GreyhoundReader("localhost"); 78 | expect(s.getPort()).toBe(80); 79 | 80 | var s1 = new gh.GreyhoundReader("localhost:9822"); 81 | expect(s1.getPort()).toBe(9822); 82 | }); 83 | 84 | it("should handle host name and port correctly if invalid port is specified", function() { 85 | var s = new gh.GreyhoundReader("localhost:hello"); 86 | 87 | expect(s.getHost()).toBe("localhost"); 88 | expect(s.getPort()).toBe(80); 89 | }); 90 | 91 | describe(".createSession", function() { 92 | it("should fail inline when no pipeline is specified", function() { 93 | var f = function() { 94 | var s = new gh.GreyhoundReader("localhost"); 95 | s.createSession(); 96 | }; 97 | 98 | expect(f).toThrowError('Invalid pipeline'); 99 | }); 100 | 101 | it("should come back with an error when the host was invalid", function(done) { 102 | var s = new gh.GreyhoundReader("localhost.greyhound"); 103 | s.createSession("1234", function(err) { 104 | expect(err).toBeTruthy(); 105 | done(); 106 | }); 107 | }); 108 | 109 | it("should successfully open a valid pipeline", function(done) { 110 | var s = new gh.GreyhoundReader("localhost:8080"); 111 | s.createSession("58a6ee2c990ba94db936d56bd42aa703", function(err, session) { 112 | expect(err).toBeFalsy(); 113 | expect(session.length).toBeGreaterThan(0); 114 | done(); 115 | }); 116 | }); 117 | }); 118 | 119 | var withSession = function(cb, final_cb) { 120 | var s = new gh.GreyhoundReader("localhost:8080"); 121 | s.createSession("58a6ee2c990ba94db936d56bd42aa703", function(err, session) { 122 | if (err) return cb(err); 123 | var done = function() { 124 | s.destroy(session, final_cb); 125 | }; 126 | 127 | cb(null, s, session, done); 128 | }); 129 | }; 130 | 131 | describe(".read", function() { 132 | it("should throw an exception inline if invalid pipeline is supplied", function() { 133 | var f = function() { 134 | var s = new gh.GreyhoundReader("localhost:8080"); 135 | s.read(); 136 | }; 137 | 138 | var f1 = function() { 139 | var s = new gh.GreyhoundReader("localhost:8080"); 140 | s.read(function() {}); 141 | }; 142 | 143 | expect(f).toThrowError("Invalid session parameter"); 144 | expect(f1).toThrowError("Invalid session parameter"); 145 | }); 146 | 147 | it("should handle invalid pipeline in the callback", function(done) { 148 | var s = new gh.GreyhoundReader("localhost:8080"); 149 | s.read("invalid-pipeline", function(err) { 150 | expect(err.message).toBe("Affinity not found"); 151 | done(); 152 | }); 153 | }); 154 | 155 | it("should correctly read default state data", function(done) { 156 | var s = new gh.GreyhoundReader("localhost:8080"); 157 | s.createSession("58a6ee2c990ba94db936d56bd42aa703", function(err, session) { 158 | expect(err).toBeFalsy(); 159 | 160 | s.read(session, function(err, data) { 161 | expect(err).toBeFalsy(); 162 | expect(data.numPoints).toBe(10653); 163 | expect(data.numBytes).toBe(20 * data.numPoints); 164 | expect(data.data.length).toBeGreaterThan(0); 165 | done(); 166 | }); 167 | }); 168 | }); 169 | 170 | it("should regard the schema specification", function(done) { 171 | withSession(function(err, s, sessionId, finish) { 172 | s.read(sessionId, { 173 | schema: gh.Schema.XYZ() 174 | }, function(err, res) { 175 | expect(err).toBeFalsy(); 176 | expect(res.numPoints * 12).toBe(res.numBytes); 177 | expect(res.data.length).toBe(res.numBytes); 178 | finish(); 179 | }); 180 | }, done); 181 | 182 | }); 183 | }); 184 | 185 | describe(".destroy", function() { 186 | it("should report error inline if invalid session parameter is passed", function() { 187 | var s = new gh.GreyhoundReader("localhost:8080") 188 | var f = function() { 189 | s.destroy(); 190 | } 191 | var f1 = function() { 192 | s.destroy(function(){}); 193 | }; 194 | 195 | expect(f).toThrowError("Invalid session parameter"); 196 | expect(f1).toThrowError("Invalid session parameter"); 197 | }); 198 | 199 | it("should correctly report an error if the provided session is invalid", function(done) { 200 | var s = new gh.GreyhoundReader("localhost:8080"); 201 | s.destroy("junk", function(err) { 202 | expect(err).toBeTruthy(); 203 | done(); 204 | }); 205 | }); 206 | }); 207 | }); 208 | -------------------------------------------------------------------------------- /test/spec/specs.js: -------------------------------------------------------------------------------- 1 | require('./gh-reader-test.js'); 2 | -------------------------------------------------------------------------------- /vendor/closure-compiler/compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/verma/plasio/f7a7ada3c3aef111695944215a9a3c188318271f/vendor/closure-compiler/compiler.jar -------------------------------------------------------------------------------- /vendor/controls/TrackballControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Eberhard Graether / http://egraether.com/ 3 | * @author Mark Lundin / http://mark-lundin.com 4 | */ 5 | 6 | THREE.TrackballControls = function ( object, domElement ) { 7 | 8 | var _this = this; 9 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 }; 10 | 11 | this.object = object; 12 | this.domElement = ( domElement !== undefined ) ? domElement : document; 13 | 14 | // API 15 | 16 | this.enabled = true; 17 | 18 | this.screen = { left: 0, top: 0, width: 0, height: 0 }; 19 | 20 | this.rotateSpeed = 1.0; 21 | this.zoomSpeed = 1.2; 22 | this.panSpeed = 0.3; 23 | 24 | this.noRotate = false; 25 | this.noZoom = false; 26 | this.noPan = false; 27 | this.noRoll = false; 28 | 29 | this.staticMoving = true; 30 | this.dynamicDampingFactor = 0.2; 31 | 32 | this.minDistance = 0; 33 | this.maxDistance = Infinity; 34 | 35 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 36 | 37 | // internals 38 | 39 | this.target = new THREE.Vector3(); 40 | 41 | var lastPosition = new THREE.Vector3(); 42 | 43 | var _state = STATE.NONE, 44 | _prevState = STATE.NONE, 45 | 46 | _eye = new THREE.Vector3(), 47 | 48 | _rotateStart = new THREE.Vector3(), 49 | _rotateEnd = new THREE.Vector3(), 50 | 51 | _zoomStart = new THREE.Vector2(), 52 | _zoomEnd = new THREE.Vector2(), 53 | 54 | _touchZoomDistanceStart = 0, 55 | _touchZoomDistanceEnd = 0, 56 | 57 | _panStart = new THREE.Vector2(), 58 | _panEnd = new THREE.Vector2(); 59 | 60 | // for reset 61 | 62 | this.target0 = this.target.clone(); 63 | this.position0 = this.object.position.clone(); 64 | this.up0 = this.object.up.clone(); 65 | 66 | // events 67 | 68 | var changeEvent = { type: 'change' }; 69 | var startEvent = { type: 'start'}; 70 | var endEvent = { type: 'end'}; 71 | 72 | 73 | // methods 74 | 75 | this.handleResize = function () { 76 | 77 | if ( this.domElement === document ) { 78 | 79 | this.screen.left = 0; 80 | this.screen.top = 0; 81 | this.screen.width = window.innerWidth; 82 | this.screen.height = window.innerHeight; 83 | 84 | } else { 85 | 86 | this.screen = this.domElement.getBoundingClientRect(); 87 | // adjustments come from similar code in the jquery offset() function 88 | var d = this.domElement.ownerDocument.documentElement 89 | this.screen.left += window.pageXOffset - d.clientLeft 90 | this.screen.top += window.pageYOffset - d.clientTop 91 | 92 | } 93 | 94 | }; 95 | 96 | this.handleEvent = function ( event ) { 97 | 98 | if ( typeof this[ event.type ] == 'function' ) { 99 | 100 | this[ event.type ]( event ); 101 | 102 | } 103 | 104 | }; 105 | 106 | this.getMouseOnScreen = function ( pageX, pageY, optionalTarget ) { 107 | 108 | return ( optionalTarget || new THREE.Vector2() ).set( 109 | ( pageX - _this.screen.left ) / _this.screen.width, 110 | ( pageY - _this.screen.top ) / _this.screen.height 111 | ); 112 | 113 | }; 114 | 115 | this.getMouseProjectionOnBall = (function(){ 116 | 117 | var objectUp = new THREE.Vector3(); 118 | 119 | 120 | return function ( pageX, pageY, projection ) { 121 | 122 | var mouseOnBall = new THREE.Vector3( 123 | ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5), 124 | ( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5), 125 | 0.0 126 | ); 127 | 128 | var length = mouseOnBall.length(); 129 | 130 | if ( _this.noRoll ) { 131 | 132 | if ( length < Math.SQRT1_2 ) { 133 | 134 | mouseOnBall.z = Math.sqrt( 1.0 - length*length ); 135 | 136 | } else { 137 | 138 | mouseOnBall.z = .5 / length; 139 | 140 | } 141 | 142 | } else if ( length > 1.0 ) { 143 | 144 | mouseOnBall.normalize(); 145 | 146 | } else { 147 | 148 | mouseOnBall.z = Math.sqrt( 1.0 - length * length ); 149 | 150 | } 151 | 152 | _eye.copy( _this.object.position ).sub( _this.target ); 153 | 154 | projection.copy( _this.object.up ).setLength( mouseOnBall.y ) 155 | projection.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) ); 156 | projection.add( _eye.setLength( mouseOnBall.z ) ); 157 | 158 | return projection; 159 | } 160 | 161 | }()); 162 | 163 | this.rotateCamera = (function(){ 164 | 165 | var axis = new THREE.Vector3(), 166 | quaternion = new THREE.Quaternion(); 167 | 168 | 169 | return function () { 170 | 171 | var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); 172 | 173 | if ( angle ) { 174 | 175 | axis.crossVectors( _rotateStart, _rotateEnd ).normalize(); 176 | 177 | angle *= _this.rotateSpeed; 178 | 179 | quaternion.setFromAxisAngle( axis, -angle ); 180 | 181 | _eye.applyQuaternion( quaternion ); 182 | _this.object.up.applyQuaternion( quaternion ); 183 | 184 | _rotateEnd.applyQuaternion( quaternion ); 185 | 186 | if ( _this.staticMoving ) { 187 | 188 | _rotateStart.copy( _rotateEnd ); 189 | 190 | } else { 191 | 192 | quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); 193 | _rotateStart.applyQuaternion( quaternion ); 194 | 195 | } 196 | 197 | } 198 | } 199 | 200 | }()); 201 | 202 | this.zoomCamera = function () { 203 | 204 | if ( _state === STATE.TOUCH_ZOOM ) { 205 | 206 | var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; 207 | _touchZoomDistanceStart = _touchZoomDistanceEnd; 208 | _eye.multiplyScalar( factor ); 209 | 210 | } else { 211 | 212 | var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; 213 | 214 | if ( factor !== 1.0 && factor > 0.0 ) { 215 | 216 | _eye.multiplyScalar( factor ); 217 | 218 | if ( _this.staticMoving ) { 219 | 220 | _zoomStart.copy( _zoomEnd ); 221 | 222 | } else { 223 | 224 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 225 | 226 | } 227 | 228 | } 229 | 230 | } 231 | 232 | }; 233 | 234 | this.panCamera = (function(){ 235 | 236 | var mouseChange = new THREE.Vector2(), 237 | objectUp = new THREE.Vector3(), 238 | pan = new THREE.Vector3(); 239 | 240 | return function () { 241 | 242 | mouseChange.copy( _panEnd ).sub( _panStart ); 243 | 244 | if ( mouseChange.lengthSq() ) { 245 | 246 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); 247 | 248 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); 249 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); 250 | 251 | _this.object.position.add( pan ); 252 | _this.target.add( pan ); 253 | 254 | if ( _this.staticMoving ) { 255 | 256 | _panStart.copy( _panEnd ); 257 | 258 | } else { 259 | 260 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); 261 | 262 | } 263 | 264 | } 265 | } 266 | 267 | }()); 268 | 269 | this.checkDistances = function () { 270 | 271 | if ( !_this.noZoom || !_this.noPan ) { 272 | 273 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) { 274 | 275 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) ); 276 | 277 | } 278 | 279 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { 280 | 281 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); 282 | 283 | } 284 | 285 | } 286 | 287 | }; 288 | 289 | this.update = function () { 290 | 291 | _eye.subVectors( _this.object.position, _this.target ); 292 | 293 | if ( !_this.noRotate ) { 294 | 295 | _this.rotateCamera(); 296 | 297 | } 298 | 299 | if ( !_this.noZoom ) { 300 | 301 | _this.zoomCamera(); 302 | 303 | } 304 | 305 | if ( !_this.noPan ) { 306 | 307 | _this.panCamera(); 308 | 309 | } 310 | 311 | _this.object.position.addVectors( _this.target, _eye ); 312 | 313 | _this.checkDistances(); 314 | 315 | _this.object.lookAt( _this.target ); 316 | 317 | if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) { 318 | 319 | _this.dispatchEvent( changeEvent ); 320 | 321 | lastPosition.copy( _this.object.position ); 322 | 323 | } 324 | 325 | }; 326 | 327 | this.reset = function () { 328 | 329 | _state = STATE.NONE; 330 | _prevState = STATE.NONE; 331 | 332 | _this.target.copy( _this.target0 ); 333 | _this.object.position.copy( _this.position0 ); 334 | _this.object.up.copy( _this.up0 ); 335 | 336 | _eye.subVectors( _this.object.position, _this.target ); 337 | 338 | _this.object.lookAt( _this.target ); 339 | 340 | _this.dispatchEvent( changeEvent ); 341 | 342 | lastPosition.copy( _this.object.position ); 343 | 344 | }; 345 | 346 | // listeners 347 | 348 | function keydown( event ) { 349 | 350 | if ( _this.enabled === false ) return; 351 | 352 | window.removeEventListener( 'keydown', keydown ); 353 | 354 | _prevState = _state; 355 | 356 | if ( _state !== STATE.NONE ) { 357 | 358 | return; 359 | 360 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) { 361 | 362 | _state = STATE.ROTATE; 363 | 364 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) { 365 | 366 | _state = STATE.ZOOM; 367 | 368 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) { 369 | 370 | _state = STATE.PAN; 371 | 372 | } 373 | 374 | } 375 | 376 | function keyup( event ) { 377 | 378 | if ( _this.enabled === false ) return; 379 | 380 | _state = _prevState; 381 | 382 | window.addEventListener( 'keydown', keydown, false ); 383 | 384 | } 385 | 386 | function mousedown( event ) { 387 | 388 | if ( _this.enabled === false ) return; 389 | 390 | event.preventDefault(); 391 | event.stopPropagation(); 392 | 393 | if ( _state === STATE.NONE ) { 394 | 395 | _state = event.button; 396 | 397 | } 398 | 399 | if ( _state === STATE.ROTATE && !_this.noRotate ) { 400 | 401 | _rotateStart = _this.getMouseProjectionOnBall( event.pageX, event.pageY, _rotateStart ); 402 | _rotateEnd.copy(_rotateStart) 403 | 404 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) { 405 | 406 | _zoomStart = _this.getMouseOnScreen( event.pageX, event.pageY, _zoomStart ); 407 | _zoomEnd.copy(_zoomStart); 408 | 409 | } else if ( _state === STATE.PAN && !_this.noPan ) { 410 | 411 | _panStart = _this.getMouseOnScreen( event.pageX, event.pageY, _panStart); 412 | _panEnd.copy(_panStart) 413 | 414 | } 415 | 416 | document.addEventListener( 'mousemove', mousemove, false ); 417 | document.addEventListener( 'mouseup', mouseup, false ); 418 | _this.dispatchEvent( startEvent ); 419 | 420 | 421 | } 422 | 423 | function mousemove( event ) { 424 | 425 | if ( _this.enabled === false ) return; 426 | 427 | event.preventDefault(); 428 | event.stopPropagation(); 429 | 430 | if ( _state === STATE.ROTATE && !_this.noRotate ) { 431 | 432 | _rotateEnd = _this.getMouseProjectionOnBall( event.pageX, event.pageY, _rotateEnd ); 433 | 434 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) { 435 | 436 | _zoomEnd = _this.getMouseOnScreen( event.pageX, event.pageY, _zoomEnd ); 437 | 438 | } else if ( _state === STATE.PAN && !_this.noPan ) { 439 | 440 | _panEnd = _this.getMouseOnScreen( event.pageX, event.pageY, _panEnd ); 441 | 442 | } 443 | 444 | } 445 | 446 | function mouseup( event ) { 447 | 448 | if ( _this.enabled === false ) return; 449 | 450 | event.preventDefault(); 451 | event.stopPropagation(); 452 | 453 | _state = STATE.NONE; 454 | 455 | document.removeEventListener( 'mousemove', mousemove ); 456 | document.removeEventListener( 'mouseup', mouseup ); 457 | _this.dispatchEvent( endEvent ); 458 | 459 | } 460 | 461 | function mousewheel( event ) { 462 | 463 | if ( _this.enabled === false ) return; 464 | 465 | event.preventDefault(); 466 | event.stopPropagation(); 467 | 468 | var delta = 0; 469 | 470 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 471 | 472 | delta = event.wheelDelta / 40; 473 | 474 | } else if ( event.detail ) { // Firefox 475 | 476 | delta = - event.detail / 3; 477 | 478 | } 479 | 480 | _zoomStart.y += delta * 0.01; 481 | _this.dispatchEvent( startEvent ); 482 | _this.dispatchEvent( endEvent ); 483 | 484 | } 485 | 486 | function touchstart( event ) { 487 | 488 | if ( _this.enabled === false ) return; 489 | 490 | switch ( event.touches.length ) { 491 | 492 | case 1: 493 | _state = STATE.TOUCH_ROTATE; 494 | _rotateEnd.copy( _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _rotateStart )); 495 | break; 496 | 497 | case 2: 498 | _state = STATE.TOUCH_ZOOM; 499 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 500 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 501 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 502 | break; 503 | 504 | case 3: 505 | _state = STATE.TOUCH_PAN; 506 | _panEnd.copy( _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _panStart )); 507 | break; 508 | 509 | default: 510 | _state = STATE.NONE; 511 | 512 | } 513 | _this.dispatchEvent( startEvent ); 514 | 515 | 516 | } 517 | 518 | function touchmove( event ) { 519 | 520 | if ( _this.enabled === false ) return; 521 | 522 | event.preventDefault(); 523 | event.stopPropagation(); 524 | 525 | switch ( event.touches.length ) { 526 | 527 | case 1: 528 | _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _rotateEnd ); 529 | break; 530 | 531 | case 2: 532 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 533 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 534 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ) 535 | break; 536 | 537 | case 3: 538 | _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _panEnd ); 539 | break; 540 | 541 | default: 542 | _state = STATE.NONE; 543 | 544 | } 545 | 546 | } 547 | 548 | function touchend( event ) { 549 | 550 | if ( _this.enabled === false ) return; 551 | 552 | switch ( event.touches.length ) { 553 | 554 | case 1: 555 | _rotateStart.copy( _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _rotateEnd )); 556 | break; 557 | 558 | case 2: 559 | _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; 560 | break; 561 | 562 | case 3: 563 | _panStart.copy( _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _panEnd )); 564 | break; 565 | 566 | } 567 | 568 | _state = STATE.NONE; 569 | _this.dispatchEvent( endEvent ); 570 | 571 | } 572 | 573 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); 574 | 575 | this.domElement.addEventListener( 'mousedown', mousedown, false ); 576 | 577 | this.domElement.addEventListener( 'mousewheel', mousewheel, false ); 578 | this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox 579 | 580 | this.domElement.addEventListener( 'touchstart', touchstart, false ); 581 | this.domElement.addEventListener( 'touchend', touchend, false ); 582 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 583 | 584 | window.addEventListener( 'keydown', keydown, false ); 585 | window.addEventListener( 'keyup', keyup, false ); 586 | 587 | this.handleResize(); 588 | 589 | }; 590 | 591 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 592 | -------------------------------------------------------------------------------- /vendor/jquery.nouislider.min.js: -------------------------------------------------------------------------------- 1 | (function(f){if(f.zepto&&!f.fn.removeData)throw new ReferenceError("Zepto is loaded without the data module.");f.fn.noUiSlider=function(C,D){function s(a,b){return 100*b/(a[1]-a[0])}function E(a,b){return b*(a[1]-a[0])/100+a[0]}function t(a){return a instanceof f||f.zepto&&f.zepto.isZ(a)}function n(a){return!isNaN(parseFloat(a))&&isFinite(a)}function r(a,b){f.isArray(a)||(a=[a]);f.each(a,function(){"function"===typeof this&&this.call(b)})}function F(a,b){return function(){var c=[null,null];c[b]=f(this).val(); 2 | a.val(c,!0)}}function G(a,b){a=a.toFixed(b.decimals);0===parseFloat(a)&&(a=a.replace("-0","0"));return a.replace(".",b.serialization.mark)}function u(a){return parseFloat(a.toFixed(7))}function p(a,b,c,d){var e=d.target;a=a.replace(/\s/g,h+" ")+h;b.on(a,function(a){var b=e.attr("disabled");if(e.hasClass("noUi-state-tap")||void 0!==b&&null!==b)return!1;var g;a.preventDefault();var b=0===a.type.indexOf("touch"),h=0===a.type.indexOf("mouse"),l=0===a.type.indexOf("pointer"),v,H=a;0===a.type.indexOf("MSPointer")&& 3 | (l=!0);a.originalEvent&&(a=a.originalEvent);b&&(g=a.changedTouches[0].pageX,v=a.changedTouches[0].pageY);if(h||l)l||void 0!==window.pageXOffset||(window.pageXOffset=document.documentElement.scrollLeft,window.pageYOffset=document.documentElement.scrollTop),g=a.clientX+window.pageXOffset,v=a.clientY+window.pageYOffset;g=f.extend(H,{pointX:g,pointY:v,cursor:h});c(g,d,e.data("base").data("options"))})}function I(a){var b=this.target;if(void 0===a)return this.element.data("value");!0===a?a=this.element.data("value"): 4 | this.element.data("value",a);void 0!==a&&f.each(this.elements,function(){if("function"===typeof this)this.call(b,a);else this[0][this[1]](a)})}function J(a,b,c){if(t(b)){var d=[],e=a.data("target");a.data("options").direction&&(c=c?0:1);b.each(function(){f(this).on("change"+h,F(e,c));d.push([f(this),"val"])});return d}"string"===typeof b&&(b=[f('').appendTo(a).addClass(g[3]).change(function(a){a.stopPropagation()}),"val"]);return[b]}function K(a,b,c){var d=[];f.each(c.to[b], 5 | function(e){d=d.concat(J(a,c.to[b][e],b))});return{element:a,elements:d,target:a.data("target"),val:I}}function L(a,b){var c=a.data("target");c.hasClass(g[14])||(b||(c.addClass(g[15]),setTimeout(function(){c.removeClass(g[15])},450)),c.addClass(g[14]),r(a.data("options").h,c))}function w(a,b){var c=a.data("options");b=u(b);a.data("target").removeClass(g[14]);a.css(c.style,b+"%").data("pct",b);a.is(":first-child")&&a.toggleClass(g[13],50k?100:k);if(b===a.data("pct"))return[e?e:!1,100===k?!1:k];w(a,b);return!0}function A(a,b,c,d){a.addClass(g[5]);setTimeout(function(){a.removeClass(g[5])},300);x(b,c);r(d,a.data("target"));a.data("target").change()}function M(a,b,c){var d= 7 | b.a,e=a[b.d]-b.start[b.d],e=100*e/b.size;if(1===d.length){if(a=x(d[0],b.c[0]+e),!0!==a){0<=f.inArray(d[0].data("pct"),a)&&L(b.b,!c.margin);return}}else{var k,m;c.step&&(a=c.step,e=Math.round(e/a)*a);a=k=b.c[0]+e;e=m=b.c[1]+e;0>a?(e+=-1*a,a=0):100k&&!a&&!d[0].data("pct")||100===e&&100").appendTo(b);if(b.data("base"))throw Error("Slider was already initialized.");b.data("base",k).addClass([g[6],g[16+a.direction],g[10+a.orientation]].join(" "));for(c=0;c
").appendTo(k),e.addClass(g[1]),e.children().addClass([g[2], 16 | g[2]+g[7+a.direction+(a.direction?-1*c:c)]].join(" ")),e.data({base:k,target:b,options:a,grab:e.children(),pct:-1}).attr("data-style",a.style),e.data({store:K(e,c,a.serialization)}),d.push(e);switch(a.connect){case 1:b.addClass(g[9]);d[0].addClass(g[12]);break;case 3:d[1].addClass(g[12]);case 2:d[0].addClass(g[9]);case 0:b.addClass(g[12])}k.addClass(g[0]).data({target:b,options:a,handles:d});b.val(a.start);if(!a.behaviour.fixed)for(c=0;ch[0]?d+Math.abs(h[0]):d-h[0]);g.direction&&(d=100-d);!0!==x(e[c],d)&&e[c].data("store").val(!0);!0===b&&r(g.set,f(this))}})}function U(a){var b=[[a,""]];f.each(a.data("base").data("handles"), 19 | function(){b=b.concat(f(this).data("store").elements)});f.each(b,function(){1