├── img
├── favicon.ico
├── led-icons
│ ├── 1license.txt
│ ├── connect.png
│ ├── disconnect.png
│ └── page_white_text.png
└── bootstrap
│ ├── glyphicons-halflings.png
│ └── glyphicons-halflings-white.png
├── js
├── sorttable.js
├── gcodeviewer
│ ├── ui.js
│ ├── gcode-parser.js
│ ├── Three.OrbitControls.js
│ ├── gcode-model.js
│ └── Three.TrackballControls.js
├── thingiview
│ ├── plane.js
│ ├── binaryReader.js
│ ├── thingiloader.js
│ └── thingiview.js
├── jquery.mousewheel.js
├── bootbox.js
├── modernizr.js
├── bootstrap.js
└── sugar.js
├── testfiles
└── demo_file.stl
├── .gitignore
├── makedist.sh
├── package.json
├── css
├── style.css
├── layout-default-latest.css
└── bootstrap
│ └── bootstrap-responsive.css
├── README.md
├── index.html
└── main.js
/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/favicon.ico
--------------------------------------------------------------------------------
/js/sorttable.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/js/sorttable.js
--------------------------------------------------------------------------------
/testfiles/demo_file.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/testfiles/demo_file.stl
--------------------------------------------------------------------------------
/img/led-icons/1license.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/led-icons/1license.txt
--------------------------------------------------------------------------------
/img/led-icons/connect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/led-icons/connect.png
--------------------------------------------------------------------------------
/img/led-icons/disconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/led-icons/disconnect.png
--------------------------------------------------------------------------------
/img/led-icons/page_white_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/led-icons/page_white_text.png
--------------------------------------------------------------------------------
/img/bootstrap/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/bootstrap/glyphicons-halflings.png
--------------------------------------------------------------------------------
/img/bootstrap/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/garyhodgson/3D-Printroom/HEAD/img/bootstrap/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules/nstore
3 | node_modules/jade
4 | node_modules/underscore
5 | node_modules/humanize
6 | node_modules/moment
7 | node_modules/.bin
8 |
--------------------------------------------------------------------------------
/makedist.sh:
--------------------------------------------------------------------------------
1 | # Packages the app into a windows binary.
2 |
3 | if [ ! -d "dist" ]; then
4 | echo "This script expects a dist directory which contains the node-webkit files for packaging to exist."
5 | echo "See also: https://github.com/rogerwang/node-webkit/wiki/How-to-package-and-distribute-your-apps"
6 | echo ""
7 | echo "Aborting."
8 | exit -1
9 | fi
10 |
11 | zip -r dist/3D-printroom.nw index.html js css img node_modules package.json README.md testfiles main.js
12 | cat dist/nw.exe dist/3D-printroom.nw > dist/3D-Printroom.exe
13 | chmod +x dist/3D-Printroom.exe
14 | cd dist
15 | zip -r 3D-Printroom-distribution.zip 3D-Printroom.exe *.dll nw.pak
16 | cd ..
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "3d-Printroom",
3 | "description": "3D printer file explorer.",
4 | "version": "0.1",
5 | "maintainers":[{
6 | "name": "Gary Hodgson",
7 | "email": "contact@garyhodgson.com",
8 | "web": "http://garyhodgson.com"
9 | }],
10 | "licenses": [{
11 | "type": "GPLv3",
12 | "url": "http://www.example.com/licenses/gpl.html"
13 | }],
14 | "repositories": [{
15 | "type": "git",
16 | "url": "https://github.com/garyhodgson/3D-Printroom"
17 | }],
18 | "main": "index.html",
19 | "window": {
20 | "toolbar": false,
21 | "width": 800,
22 | "height": 600
23 | },
24 | "dependencies": {
25 | "filestat.js": "*",
26 | "humanize": "0.0.x",
27 | "jade": "0.28.x",
28 | "moment": "1.7.x",
29 | "nstore": "0.5.x",
30 | "sourcefolder_view.js": "*",
31 | "targetfolder_view.js": "*",
32 | "underscore": "1.4.x"
33 | }
34 | }
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-user-select: none;
3 | }
4 |
5 | html, body {
6 | background: #fff;
7 | width: 100%;
8 | height: 100%;
9 | padding: 0;
10 | margin: 0;
11 | overflow: auto; /* when page gets too small */
12 | }
13 |
14 |
15 | #container {
16 | height: 100%;
17 | width: 100%;
18 | }
19 |
20 | #sourceviewer {
21 | width: 100%;
22 | height: 100%;
23 | min-height: 300px;
24 | }
25 |
26 | #gcodeviewer {
27 | width: 100%;
28 | height: 100%;
29 | background-color: #000000;
30 | }
31 |
32 | #sourcedircontainer {
33 | width: 100%;
34 | height: 100%;
35 | }
36 |
37 | .over {
38 | border: 2px dashed #000;
39 | }
40 |
41 |
42 |
43 | .filepath {
44 | cursor: default;
45 | }
46 |
47 | .filepath.focus {
48 | background-color: #A7CADB;
49 | color: white;
50 | }
51 |
52 | .filepath .filename {
53 | width: 80px;
54 | word-wrap: break-word;
55 | }
56 |
57 | table.sortable thead {
58 | cursor: default;
59 | }
60 |
61 | .ui-layout-resizer-west { border-width: 0 1px; }
62 | .ui-layout-toggler-west { border-width: 0; }
63 | .ui-layout-toggler-west div {
64 | width: 8px;
65 | height: 35px; /* 3x 35 = 105 total height */
66 | }
67 |
68 | .ui-layout-toggler-west .btnTogglerRight { background: #999; }
69 | .ui-layout-toggler-west .btnTogglerCenter { background: #000; }
70 | .ui-layout-toggler-west .btnTogglerLeft { background: #999; }
71 |
--------------------------------------------------------------------------------
/js/gcodeviewer/ui.js:
--------------------------------------------------------------------------------
1 | unction error(msg) {
2 | alert('Error: ' + msg);
3 | }
4 |
5 | function loadFile(path, callback /* function(contents) */) {
6 | $.get(path, null, callback, 'text').error(function() { error("loading file") });
7 | }
8 |
9 | var scene = null;
10 | var object = new THREE.Object3D();
11 |
12 | function openGCodeFromPath(path) {
13 | if (object) {
14 | scene.remove(object);
15 | }
16 | loadFile(path, function(gcode) {
17 | object = createObjectFromGCode(gcode);
18 | scene.add(object);
19 | });
20 | }
21 |
22 | function openGCodeFromText(gcode) {
23 | if (object) {
24 | scene.remove(object);
25 | }
26 | object = createObjectFromGCode(gcode);
27 | scene.add(object);
28 | }
29 |
30 |
31 | $(function() {
32 |
33 | // Drop files from desktop onto main page to import them.
34 | $('#gcodeviewer').on('dragover', function(event) {
35 | event.stopPropagation();
36 | event.preventDefault();
37 | event.originalEvent.dataTransfer.dropEffect = 'copy'
38 | }).on('drop', function(event) {
39 | event.stopPropagation();
40 | event.preventDefault();
41 | var files = event.originalEvent.dataTransfer.files;
42 | if (files.length > 0) {
43 | var reader = new FileReader();
44 | reader.onload = function() {
45 | openGCodeFromText(reader.result);
46 | };
47 | reader.readAsText(files[0]);
48 | }
49 | });
50 |
51 | scene = createScene($('#gcodeviewer'));
52 |
53 | scene.add(object);
54 |
55 | });
56 |
--------------------------------------------------------------------------------
/js/thingiview/plane.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mr.doob / http://mrdoob.com/
3 | * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
4 | */
5 |
6 | var Plane = function ( width, height, segments_width, segments_height ) {
7 |
8 | THREE_32.Geometry.call( this );
9 |
10 | var ix, iy,
11 | width_half = width / 2,
12 | height_half = height / 2,
13 | gridX = segments_width || 1,
14 | gridY = segments_height || 1,
15 | gridX1 = gridX + 1,
16 | gridY1 = gridY + 1,
17 | segment_width = width / gridX,
18 | segment_height = height / gridY;
19 |
20 |
21 | for( iy = 0; iy < gridY1; iy++ ) {
22 |
23 | for( ix = 0; ix < gridX1; ix++ ) {
24 |
25 | var x = ix * segment_width - width_half;
26 | var y = iy * segment_height - height_half;
27 |
28 | this.vertices.push( new THREE_32.Vertex( new THREE_32.Vector3( x, - y, 0 ) ) );
29 |
30 | }
31 |
32 | }
33 |
34 | for( iy = 0; iy < gridY; iy++ ) {
35 |
36 | for( ix = 0; ix < gridX; ix++ ) {
37 |
38 | var a = ix + gridX1 * iy;
39 | var b = ix + gridX1 * ( iy + 1 );
40 | var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
41 | var d = ( ix + 1 ) + gridX1 * iy;
42 |
43 | this.faces.push( new THREE_32.Face4( a, b, c, d ) );
44 | this.uvs.push( [
45 | new THREE_32.UV( ix / gridX, iy / gridY ),
46 | new THREE_32.UV( ix / gridX, ( iy + 1 ) / gridY ),
47 | new THREE_32.UV( ( ix + 1 ) / gridX, ( iy + 1 ) / gridY ),
48 | new THREE_32.UV( ( ix + 1 ) / gridX, iy / gridY )
49 | ] );
50 |
51 | }
52 |
53 | }
54 |
55 | this.computeCentroids();
56 | this.computeFaceNormals();
57 | this.sortFacesByMaterial();
58 |
59 | };
60 |
61 | Plane.prototype = new THREE_32.Geometry();
62 | Plane.prototype.constructor = Plane;
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 3D Printroom
2 |
3 | **Warning: Work in Progress!**
4 |
5 | ## Synopsis
6 | A [node-webkit](https://github.com/rogerwang/node-webkit) application that acts as a simple 3D printer file explorer.
7 |
8 | ## Grand Plan
9 |
10 | Using file explorers to manage 3D printer files is a bit clunky. There are no previews and the metadata held in most gcode files is not visible. This leads to long filenames consisting of some key attributes, e.g. ```directdrive_bowden_holder.PLA.slow_PLA_prusa.0.24.gcode```. Once a folder contains more than a few files it becomes tricky to manage.
11 |
12 | This app is a little side project which attempts to address this problem, inspired by Adobe Lightroom (which does an admirable job of organising photos). Rather than attempt a modification of Windows Explorer to handle 3D printer files I decided to make something more portable. I chose node-webkit so I could develop with web tech and still use node.js in order to access local filesystems.
13 |
14 | ## Screen shot
15 |
16 | 
17 |
18 | ## Features
19 |
20 | * STL preview
21 | * Gcode preview
22 | * Gcode attribute display (Slic3r only)
23 |
24 | ## Future Features
25 |
26 | * Ad-hoc collections
27 | * Remember & browse folders
28 | * Folder sync
29 | * Additional metadata, e.g. ratings, comments
30 | * Send to slicer
31 | * Send to printer host
32 |
33 |
34 | ## Running
35 | At this stage the best bet is to follow the hacking instructions below and run the latest version using node-webkit directly. If you want to simply play with a version there is a Windows binary here: [3D-Printroom-distribution.zip](https://dl.dropbox.com/u/22464622/3D-Printroom/3D-Printroom-distribution.zip). (Linux and Mac will have to sadly follow the hacking instructions below.)
36 |
37 | * Download and extract zip file.
38 | * Double click 3D-Printroom.exe.
39 | * An example folder is already included.
40 | * Drag and Drop a folder containing your STL and Gcode files to the top left window.
41 |
42 | ## Hacking
43 | * Clone the project.
44 | * Install node-webkit.
45 | * Install the node dependencies.
46 | * humanize
47 | * jade
48 | * moment
49 | * nstore
50 | * underscore
51 | * Run with ```nw.exe --disable-application-cache 3D-Printroom``` (where '3D-Printroom' is the project folder)
52 |
53 | ## Credits
54 | * [Thingiview.js](https://github.com/tbuser/thingiview.js)
55 | * [Gcode-Viewer](https://github.com/joewalnes/gcode-viewer)
56 | * [Node-webkit](https://github.com/rogerwang/node-webkit)
57 |
58 | ## License
59 | [GPLv3](http://www.example.com/licenses/gpl.html)
--------------------------------------------------------------------------------
/js/jquery.mousewheel.js:
--------------------------------------------------------------------------------
1 | /*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
2 | * Licensed under the MIT License (LICENSE.txt).
3 | *
4 | * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
5 | * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6 | * Thanks to: Seamus Leahy for adding deltaX and deltaY
7 | *
8 | * Version: 3.0.6
9 | *
10 | * Requires: 1.2.2+
11 | */
12 |
13 | (function($) {
14 |
15 | var types = ['DOMMouseScroll', 'mousewheel'];
16 |
17 | if ($.event.fixHooks) {
18 | for ( var i=types.length; i; ) {
19 | $.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
20 | }
21 | }
22 |
23 | $.event.special.mousewheel = {
24 | setup: function() {
25 | if ( this.addEventListener ) {
26 | for ( var i=types.length; i; ) {
27 | this.addEventListener( types[--i], handler, false );
28 | }
29 | } else {
30 | this.onmousewheel = handler;
31 | }
32 | },
33 |
34 | teardown: function() {
35 | if ( this.removeEventListener ) {
36 | for ( var i=types.length; i; ) {
37 | this.removeEventListener( types[--i], handler, false );
38 | }
39 | } else {
40 | this.onmousewheel = null;
41 | }
42 | }
43 | };
44 |
45 | $.fn.extend({
46 | mousewheel: function(fn) {
47 | return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
48 | },
49 |
50 | unmousewheel: function(fn) {
51 | return this.unbind("mousewheel", fn);
52 | }
53 | });
54 |
55 |
56 | function handler(event) {
57 | var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
58 | event = $.event.fix(orgEvent);
59 | event.type = "mousewheel";
60 |
61 | // Old school scrollwheel delta
62 | if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
63 | if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
64 |
65 | // New school multidimensional scroll (touchpads) deltas
66 | deltaY = delta;
67 |
68 | // Gecko
69 | if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
70 | deltaY = 0;
71 | deltaX = -1*delta;
72 | }
73 |
74 | // Webkit
75 | if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
76 | if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
77 |
78 | // Add event and delta to the front of the arguments
79 | args.unshift(event, delta, deltaX, deltaY);
80 |
81 | return ($.event.dispatch || $.event.handle).apply(this, args);
82 | }
83 |
84 | })(jQuery);
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 3D Printroom
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | | |
29 | Name |
30 | Size |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | | |
45 | Name |
46 | Size |
47 | Created |
48 | Modified |
49 | Bottom Solid Layers |
50 | Extrusion Multiplier |
51 | Filament Diameter |
52 | Fill Density |
53 | First Layer Extrusion Width |
54 | Infill Extrusion Width |
55 | Infill Speed |
56 | Layer Height |
57 | Nozzle Diameter |
58 | Perimeter Speed |
59 | Perimeters |
60 | Perimeters Extrusion Width |
61 | Scale |
62 | Top Solid Layers |
63 | Travel Speed |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/js/gcodeviewer/gcode-parser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Parses a string of gcode instructions, and invokes handlers for
3 | * each type of command.
4 | *
5 | * Special handler:
6 | * 'default': Called if no other handler matches.
7 | */
8 | function GCodeParser(handlers) {
9 | this.handlers = handlers || {};
10 | }
11 |
12 | GCodeParser.prototype.parseLine = function(text, info) {
13 | text = text.replace(/;.*$/, '').trim(); // Remove ; style comments
14 | if (text) {
15 | var tokens = text.split(' ');
16 | if (tokens) {
17 | var cmd = tokens[0];
18 | var args = {
19 | 'cmd': cmd
20 | };
21 | tokens.splice(1).forEach(function(token) {
22 | var key = token[0].toLowerCase();
23 | var value = parseFloat(token.substring(1));
24 | args[key] = value;
25 | });
26 | var handler = this.handlers[tokens[0]] || this.handlers['default'];
27 | if (handler) {
28 | return handler(args, info);
29 | }
30 | }
31 | }
32 | };
33 |
34 | GCodeParser.prototype.parse = function(gcode) {
35 | var lines = gcode.split('\n');
36 | for (var i = 0; i < lines.length; i++) {
37 | if (this.parseLine(lines[i], i) === false) {
38 | break;
39 | }
40 | }
41 | };
42 |
43 | GCodeParser.prototype.parseLineBjd = function(gcode, info) {
44 | var params = "G|M|E|F|H|I|J|K|P|R|S|T|X|Y|Z"; // supported command parameters
45 | var i = 0, index = 0;
46 |
47 |
48 | while (i < gcode.length) {
49 | if (gcode.substring(i, i+1).search(params) == 0) {
50 | index = gcode.substring(i+1).search(params);
51 | if (index != -1) {
52 | gcodeParam = gcode.substring(i, i+index+1);
53 | i++;
54 | }
55 | else {
56 | gcodeParam = gcode.substring(i);
57 | i = gcode.length; //this will end the while loop
58 | }
59 |
60 | if (! args) { // must be the first parameter
61 | var args = {
62 | 'cmdType': gcodeParam[0], // typically G or M
63 | 'cmdNumber': parseFloat(gcodeParam.substring(1)) // this make G1 and G01 equivelent
64 | };
65 | }
66 | else {
67 | var key = gcodeParam[0].toLowerCase();
68 | var value = parseFloat(gcodeParam.substring(1));
69 | args[key] = value;
70 | }
71 | }
72 | i++;
73 | }
74 | //console.log(args);
75 | var handler = this.handlers['parsLine'];
76 | if (handler) {
77 | return handler(args, info);
78 | }
79 | };
80 |
81 | GCodeParser.prototype.parseBjd = function(gcode) {
82 |
83 | //Fugly but valid g-code N110G17M03(start motor)G0X0Y0Z0
84 |
85 | //var gcode = testForm.output.value //"; comment\nN100G1X1Y1Z1\nN200g2X46 (Hmmm)\n;comm 2\nm03G12G1x5y5z5";
86 | var commands = "G|M|S";
87 | var index;
88 | var gcodeLine = "";
89 |
90 |
91 |
92 | // clean up gcode
93 | gcode = gcode.toUpperCase();
94 | gcode = gcode.replace(/;.*\n/g,""); //remove semicolon style comments
95 | gcode = gcode.replace(/\(.*\)/g,""); //remove parenthesis style comments
96 | gcode = gcode.replace(/%/g,""); //remove percent signs ..used as end of file??
97 | gcode = gcode.replace(/N[0-9]*/g,""); // remove line numbers
98 | gcode = gcode.replace(/\s+/g,""); // remove white space
99 |
100 | var i = 0;
101 |
102 | while (i < gcode.length -1) {
103 | if (gcode.substring(i, i+1).search(commands) == 0)
104 | {
105 | index = gcode.substring(i+1).search(commands);
106 | if (index != -1)
107 | {
108 | gcodeLine = gcode.substring(i, i+index+1);
109 | i++;
110 | }
111 | else
112 | {
113 | gcodeLine = gcode.substring(i);
114 | i = gcode.length;
115 | }
116 | this.parseLineBjd(gcodeLine,0);
117 | }
118 | else
119 | i++;
120 | }
121 |
122 | };
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/js/thingiview/binaryReader.js:
--------------------------------------------------------------------------------
1 | // BinaryReader
2 | // Refactored by Vjeux
3 | // http://blog.vjeux.com/2010/javascript/javascript-binary-reader.html
4 |
5 | // Original
6 | //+ Jonas Raoni Soares Silva
7 | //@ http://jsfromhell.com/classes/binary-parser [rev. #1]
8 |
9 | BinaryReader = function (data) {
10 | this._buffer = data;
11 | this._pos = 0;
12 | };
13 |
14 | BinaryReader.prototype = {
15 |
16 | /* Public */
17 |
18 | readInt8: function (){ return this._decodeInt(8, true); },
19 | readUInt8: function (){ return this._decodeInt(8, false); },
20 | readInt16: function (){ return this._decodeInt(16, true); },
21 | readUInt16: function (){ return this._decodeInt(16, false); },
22 | readInt32: function (){ return this._decodeInt(32, true); },
23 | readUInt32: function (){ return this._decodeInt(32, false); },
24 |
25 | readFloat: function (){ return this._decodeFloat(23, 8); },
26 | readDouble: function (){ return this._decodeFloat(52, 11); },
27 |
28 | readChar: function () { return this.readString(1); },
29 | readString: function (length) {
30 | this._checkSize(length * 8);
31 | var result = this._buffer.substr(this._pos, length);
32 | this._pos += length;
33 | return result;
34 | },
35 |
36 | seek: function (pos) {
37 | this._pos = pos;
38 | this._checkSize(0);
39 | },
40 |
41 | getPosition: function () {
42 | return this._pos;
43 | },
44 |
45 | getSize: function () {
46 | return this._buffer.length;
47 | },
48 |
49 |
50 | /* Private */
51 |
52 | _decodeFloat: function(precisionBits, exponentBits){
53 | var length = precisionBits + exponentBits + 1;
54 | var size = length >> 3;
55 | this._checkSize(length);
56 |
57 | var bias = Math.pow(2, exponentBits - 1) - 1;
58 | var signal = this._readBits(precisionBits + exponentBits, 1, size);
59 | var exponent = this._readBits(precisionBits, exponentBits, size);
60 | var significand = 0;
61 | var divisor = 2;
62 | // var curByte = length + (-precisionBits >> 3) - 1;
63 | var curByte = 0;
64 | do {
65 | var byteValue = this._readByte(++curByte, size);
66 | var startBit = precisionBits % 8 || 8;
67 | var mask = 1 << startBit;
68 | while (mask >>= 1) {
69 | if (byteValue & mask) {
70 | significand += 1 / divisor;
71 | }
72 | divisor *= 2;
73 | }
74 | } while (precisionBits -= startBit);
75 |
76 | this._pos += size;
77 |
78 | return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity
79 | : (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand
80 | : Math.pow(2, exponent - bias) * (1 + significand) : 0);
81 | },
82 |
83 | _decodeInt: function(bits, signed){
84 | var x = this._readBits(0, bits, bits / 8), max = Math.pow(2, bits);
85 | var result = signed && x >= max / 2 ? x - max : x;
86 |
87 | this._pos += bits / 8;
88 | return result;
89 | },
90 |
91 | //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
92 | _shl: function (a, b){
93 | for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
94 | return a;
95 | },
96 |
97 | _readByte: function (i, size) {
98 | return this._buffer.charCodeAt(this._pos + size - i - 1) & 0xff;
99 | },
100 |
101 | _readBits: function (start, length, size) {
102 | var offsetLeft = (start + length) % 8;
103 | var offsetRight = start % 8;
104 | var curByte = size - (start >> 3) - 1;
105 | var lastByte = size + (-(start + length) >> 3);
106 | var diff = curByte - lastByte;
107 |
108 | var sum = (this._readByte(curByte, size) >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1);
109 |
110 | if (diff && offsetLeft) {
111 | sum += (this._readByte(lastByte++, size) & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight;
112 | }
113 |
114 | while (diff) {
115 | sum += this._shl(this._readByte(lastByte++, size), (diff-- << 3) - offsetRight);
116 | }
117 |
118 | return sum;
119 | },
120 |
121 | _checkSize: function (neededBits) {
122 | if (!(this._pos + Math.ceil(neededBits / 8) < this._buffer.length)) {
123 | throw new Error("Index out of bound");
124 | }
125 | }
126 | };
--------------------------------------------------------------------------------
/js/bootbox.js:
--------------------------------------------------------------------------------
1 | /**
2 | * bootbox.js v2.5.0
3 | *
4 | * http://bootboxjs.com/license.txt
5 | */
6 | var bootbox=window.bootbox||function(k){function h(b,a){null==a&&(a=m);return"string"==typeof i[a][b]?i[a][b]:a!=n?h(b,n):b}var m="en",n="en",s=!0,r="static",t="",j={},e={},i={en:{OK:"OK",CANCEL:"Cancel",CONFIRM:"OK"},fr:{OK:"OK",CANCEL:"Annuler",CONFIRM:"D'accord"},de:{OK:"OK",CANCEL:"Abbrechen",CONFIRM:"Akzeptieren"},es:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Aceptar"},br:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Sim"},nl:{OK:"OK",CANCEL:"Annuleren",CONFIRM:"Accepteren"},ru:{OK:"OK",CANCEL:"\u041e\u0442\u043c\u0435\u043d\u0430",
7 | CONFIRM:"\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c"},it:{OK:"OK",CANCEL:"Annulla",CONFIRM:"Conferma"}};e.setLocale=function(b){for(var a in i)if(a==b){m=b;return}throw Error("Invalid locale: "+b);};e.addLocale=function(b,a){"undefined"==typeof i[b]&&(i[b]={});for(var c in a)i[b][c]=a[c]};e.setIcons=function(b){j=b;if("object"!==typeof j||null==j)j={}};e.alert=function(){var b="",a=h("OK"),c=null;switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"function"==typeof arguments[1]?
8 | c=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];c=arguments[2];break;default:throw Error("Incorrect number of arguments: expected 1-3");}return e.dialog(b,{label:a,icon:j.OK,callback:c},{onEscape:c})};e.confirm=function(){var b="",a=h("CANCEL"),c=h("CONFIRM"),f=null;switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"function"==typeof arguments[1]?f=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];"function"==typeof arguments[2]?
9 | f=arguments[2]:c=arguments[2];break;case 4:b=arguments[0];a=arguments[1];c=arguments[2];f=arguments[3];break;default:throw Error("Incorrect number of arguments: expected 1-4");}return e.dialog(b,[{label:a,icon:j.CANCEL,callback:function(){"function"==typeof f&&f(!1)}},{label:c,icon:j.CONFIRM,callback:function(){"function"==typeof f&&f(!0)}}])};e.prompt=function(){var b="",a=h("CANCEL"),c=h("CONFIRM"),f=null,u="";switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"function"==
10 | typeof arguments[1]?f=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];"function"==typeof arguments[2]?f=arguments[2]:c=arguments[2];break;case 4:b=arguments[0];a=arguments[1];c=arguments[2];f=arguments[3];break;case 5:b=arguments[0];a=arguments[1];c=arguments[2];f=arguments[3];u=arguments[4];break;default:throw Error("Incorrect number of arguments: expected 1-5");}var p=k("");p.append("");var d=e.dialog(p,[{label:a,
11 | icon:j.CANCEL,callback:function(){"function"==typeof f&&f(null)}},{label:c,icon:j.CONFIRM,callback:function(){"function"==typeof f&&f(p.find("input[type=text]").val())}}],{header:b});d.on("shown",function(){p.find("input[type=text]").focus();p.on("submit",function(a){a.preventDefault();d.find(".btn-primary").click()})});return d};e.modal=function(){var b,a,c,f={onEscape:null,keyboard:!0,backdrop:r};switch(arguments.length){case 1:b=arguments[0];break;case 2:b=arguments[0];"object"==typeof arguments[1]?
12 | c=arguments[1]:a=arguments[1];break;case 3:b=arguments[0];a=arguments[1];c=arguments[2];break;default:throw Error("Incorrect number of arguments: expected 1-3");}f.header=a;c="object"==typeof c?k.extend(f,c):f;return e.dialog(b,[],c)};e.dialog=function(b,a,c){var f=null,e="",j=[],c=c||{};null==a?a=[]:"undefined"==typeof a.length&&(a=[a]);for(var d=a.length;d--;){var h=null,i=null,l=null,m="",n=null;if("undefined"==typeof a[d].label&&"undefined"==typeof a[d]["class"]&&"undefined"==typeof a[d].callback){var h=
13 | 0,i=null,q;for(q in a[d])if(i=q,1<++h)break;1==h&&"function"==typeof a[d][q]&&(a[d].label=i,a[d].callback=a[d][q])}"function"==typeof a[d].callback&&(n=a[d].callback);a[d]["class"]?l=a[d]["class"]:d==a.length-1&&2>=a.length&&(l="btn-primary");h=a[d].label?a[d].label:"Option "+(d+1);a[d].icon&&(m=" ");i=a[d].href?a[d].href:"javascript:;";e+=""+m+""+h+"";j[d]=n}d=[""];
14 | if(c.header){l="";if("undefined"==typeof c.headerCloseButton||c.headerCloseButton)l="
×";d.push("")}d.push("
");e&&d.push("");d.push("
");var g=k(d.join("\n"));("undefined"===typeof c.animate?s:c.animate)&&g.addClass("fade");(e="undefined"===typeof c.classes?t:c.classes)&&g.addClass(e);k(".modal-body",g).html(b);g.bind("hidden",
15 | function(){g.remove()});g.bind("hide",function(){if("escape"==f&&"function"==typeof c.onEscape)c.onEscape()});k(document).bind("keyup.modal",function(a){27==a.which&&(f="escape")});g.bind("shown",function(){k("a.btn-primary:last",g).focus()});g.on("click",".modal-footer a, a.close",function(b){var c=k(this).data("handler"),d=j[c],e=null;"undefined"!==typeof c&&"undefined"!==typeof a[c].href||(b.preventDefault(),"function"==typeof d&&(e=d()),!1!==e&&(f="button",g.modal("hide")))});null==c.keyboard&&
16 | (c.keyboard="function"==typeof c.onEscape);k("body").append(g);g.modal({backdrop:"undefined"===typeof c.backdrop?r:c.backdrop,keyboard:c.keyboard});return g};e.hideAll=function(){k(".bootbox").modal("hide")};e.animate=function(b){s=b};e.backdrop=function(b){r=b};e.classes=function(b){t=b};return e}(window.jQuery);
17 |
--------------------------------------------------------------------------------
/css/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 | * PANES & CONTENT-DIVs
19 | */
20 | .ui-layout-pane { /* all 'panes' */
21 | background: #FFF;
22 | border: 1px solid #BBB;
23 | padding: 10px;
24 | overflow: auto;
25 | /* DO NOT add scrolling (or padding) to 'panes' that have a content-div,
26 | otherwise you may get double-scrollbars - on the pane AND on the content-div
27 | - use ui-layout-wrapper class if pane has a content-div
28 | - use ui-layout-container if pane has an inner-layout
29 | */
30 | }
31 | /* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */
32 | .ui-layout-content {
33 | padding: 10px;
34 | position: relative; /* contain floated or positioned elements */
35 | overflow: auto; /* add scrolling to content-div */
36 | }
37 |
38 | /*
39 | * UTILITY CLASSES
40 | * Must come AFTER pane-class above so will override
41 | * These classes are NOT auto-generated and are NOT used by Layout
42 | */
43 | .layout-child-container,
44 | .layout-content-container {
45 | padding: 0;
46 | overflow: hidden;
47 | }
48 | .layout-child-container {
49 | border: 0; /* remove border because inner-layout-panes probably have borders */
50 | }
51 | .layout-scroll {
52 | overflow: auto;
53 | }
54 | .layout-hide {
55 | display: none;
56 | }
57 |
58 | /*
59 | * RESIZER-BARS
60 | */
61 | .ui-layout-resizer { /* all 'resizer-bars' */
62 | background: #DDD;
63 | border: 1px solid #BBB;
64 | border-width: 0;
65 | }
66 | .ui-layout-resizer-drag { /* REAL resizer while resize in progress */
67 | }
68 | .ui-layout-resizer-hover { /* affects both open and closed states */
69 | }
70 | /* NOTE: It looks best when 'hover' and 'dragging' are set to the same color,
71 | otherwise color shifts while dragging when bar can't keep up with mouse */
72 | .ui-layout-resizer-open-hover , /* hover-color to 'resize' */
73 | .ui-layout-resizer-dragging { /* resizer beging 'dragging' */
74 | background: #C4E1A4;
75 | }
76 | .ui-layout-resizer-dragging { /* CLONED resizer being dragged */
77 | border: 1px solid #BBB;
78 | }
79 | .ui-layout-resizer-north-dragging,
80 | .ui-layout-resizer-south-dragging {
81 | border-width: 1px 0;
82 | }
83 | .ui-layout-resizer-west-dragging,
84 | .ui-layout-resizer-east-dragging {
85 | border-width: 0 1px;
86 | }
87 | /* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */
88 | .ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */
89 | background: #E1A4A4; /* red */
90 | }
91 |
92 | .ui-layout-resizer-closed-hover { /* hover-color to 'slide open' */
93 | background: #EBD5AA;
94 | }
95 | .ui-layout-resizer-sliding { /* resizer when pane is 'slid open' */
96 | opacity: .10; /* show only a slight shadow */
97 | filter: alpha(opacity=10);
98 | }
99 | .ui-layout-resizer-sliding-hover { /* sliding resizer - hover */
100 | opacity: 1.00; /* on-hover, show the resizer-bar normally */
101 | filter: alpha(opacity=100);
102 | }
103 | /* sliding resizer - add 'outside-border' to resizer on-hover
104 | * this sample illustrates how to target specific panes and states */
105 | .ui-layout-resizer-north-sliding-hover { border-bottom-width: 1px; }
106 | .ui-layout-resizer-south-sliding-hover { border-top-width: 1px; }
107 | .ui-layout-resizer-west-sliding-hover { border-right-width: 1px; }
108 | .ui-layout-resizer-east-sliding-hover { border-left-width: 1px; }
109 |
110 | /*
111 | * TOGGLER-BUTTONS
112 | */
113 | .ui-layout-toggler {
114 | border: 1px solid #BBB; /* match pane-border */
115 | background-color: #BBB;
116 | }
117 | .ui-layout-resizer-hover .ui-layout-toggler {
118 | opacity: .60;
119 | filter: alpha(opacity=60);
120 | }
121 | .ui-layout-toggler-hover , /* need when NOT resizable */
122 | .ui-layout-resizer-hover .ui-layout-toggler-hover { /* need specificity when IS resizable */
123 | background-color: #FC6;
124 | opacity: 1.00;
125 | filter: alpha(opacity=100);
126 | }
127 | .ui-layout-toggler-north ,
128 | .ui-layout-toggler-south {
129 | border-width: 0 1px; /* left/right borders */
130 | }
131 | .ui-layout-toggler-west ,
132 | .ui-layout-toggler-east {
133 | border-width: 1px 0; /* top/bottom borders */
134 | }
135 | /* hide the toggler-button when the pane is 'slid open' */
136 | .ui-layout-resizer-sliding .ui-layout-toggler {
137 | display: none;
138 | }
139 | /*
140 | * style the text we put INSIDE the togglers
141 | */
142 | .ui-layout-toggler .content {
143 | color: #666;
144 | font-size: 12px;
145 | font-weight: bold;
146 | width: 100%;
147 | padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */
148 | }
149 |
150 | /*
151 | * PANE-MASKS
152 | * these styles are hard-coded on mask elems, but are also
153 | * included here as !important to ensure will overrides any generic styles
154 | */
155 | .ui-layout-mask {
156 | border: none !important;
157 | padding: 0 !important;
158 | margin: 0 !important;
159 | overflow: hidden !important;
160 | position: absolute !important;
161 | opacity: 0 !important;
162 | filter: Alpha(Opacity="0") !important;
163 | }
164 | .ui-layout-mask-inside-pane { /* masks always inside pane EXCEPT when pane is an iframe */
165 | top: 0 !important;
166 | left: 0 !important;
167 | width: 100% !important;
168 | height: 100% !important;
169 | }
170 | div.ui-layout-mask {} /* standard mask for iframes */
171 | iframe.ui-layout-mask {} /* extra mask for objects/applets */
172 |
173 |
--------------------------------------------------------------------------------
/js/modernizr.js:
--------------------------------------------------------------------------------
1 | /* Modernizr 2.5.3 (Custom Build) | MIT & BSD
2 | * Build: http://modernizr.com/download/#-draganddrop-shiv-cssclasses-hasevent-load
3 | */
4 | ;window.Modernizr=function(a,b,c){function v(a){j.cssText=a}function w(a,b){return v(prefixes.join(a+";")+(b||""))}function x(a,b){return typeof a===b}function y(a,b){return!!~(""+a).indexOf(b)}function z(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:x(f,"function")?f.bind(d||b):f}return!1}var d="2.5.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m={},n={},o={},p=[],q=p.slice,r,s=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=x(e[d],"function"),x(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),t={}.hasOwnProperty,u;!x(t,"undefined")&&!x(t.call,"undefined")?u=function(a,b){return t.call(a,b)}:u=function(a,b){return b in a&&x(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=q.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(q.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(q.call(arguments)))};return e}),m.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a};for(var A in m)u(m,A)&&(r=A.toLowerCase(),e[r]=m[A](),p.push((e[r]?"":"no-")+r));return v(""),i=k=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){var b={},c=a.createElement,e=a.createDocumentFragment,f=e();a.createElement=function(a){var e=(b[a]||(b[a]=c(a))).cloneNode();return k.shivMethods&&e.canHaveChildren&&!d.test(a)?f.appendChild(e):e},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+h().join().replace(/\w+/g,function(a){return b[a]=c(a),f.createElement(a),'c("'+a+'")'})+");return n}")(k,f)}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),f||(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea)$/i,e,f;(function(){var a=b.createElement("a");a.innerHTML="",e="hidden"in a,f=a.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e.hasEvent=s,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+p.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f 0 ) {
181 |
182 | this.dispatchEvent( changeEvent );
183 |
184 | lastPosition.copy( this.object.position );
185 |
186 | }
187 |
188 | };
189 |
190 |
191 | function getAutoRotationAngle() {
192 |
193 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
194 |
195 | }
196 |
197 | function getZoomScale() {
198 |
199 | return Math.pow( 0.95, scope.userZoomSpeed );
200 |
201 | }
202 |
203 | function onMouseDown( event ) {
204 |
205 | if ( !scope.userRotate ) return;
206 |
207 | event.preventDefault();
208 |
209 | if ( event.button === 0 || event.button === 2 ) {
210 |
211 | state = STATE.ROTATE;
212 |
213 | rotateStart.set( event.clientX, event.clientY );
214 |
215 | } else if ( event.button === 1 ) {
216 |
217 | state = STATE.ZOOM;
218 |
219 | zoomStart.set( event.clientX, event.clientY );
220 |
221 | }
222 |
223 | document.addEventListener( 'mousemove', onMouseMove, false );
224 | document.addEventListener( 'mouseup', onMouseUp, false );
225 |
226 | }
227 |
228 | function onMouseMove( event ) {
229 |
230 | event.preventDefault();
231 |
232 | if ( state === STATE.ROTATE ) {
233 |
234 | rotateEnd.set( event.clientX, event.clientY );
235 | rotateDelta.subVectors( rotateEnd, rotateStart );
236 |
237 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed );
238 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed );
239 |
240 | rotateStart.copy( rotateEnd );
241 |
242 | } else if ( state === STATE.ZOOM ) {
243 |
244 | zoomEnd.set( event.clientX, event.clientY );
245 | zoomDelta.subVectors( zoomEnd, zoomStart );
246 |
247 | if ( zoomDelta.y > 0 ) {
248 |
249 | scope.zoomIn();
250 |
251 | } else {
252 |
253 | scope.zoomOut();
254 |
255 | }
256 |
257 | zoomStart.copy( zoomEnd );
258 |
259 | }
260 |
261 | }
262 |
263 | function onMouseUp( event ) {
264 |
265 | if ( ! scope.userRotate ) return;
266 |
267 | document.removeEventListener( 'mousemove', onMouseMove, false );
268 | document.removeEventListener( 'mouseup', onMouseUp, false );
269 |
270 | state = STATE.NONE;
271 |
272 | }
273 |
274 | function onMouseWheel( event ) {
275 |
276 | if ( ! scope.userZoom ) return;
277 |
278 | var delta = 0;
279 |
280 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
281 |
282 | delta = event.wheelDelta;
283 |
284 | } else if ( event.detail ) { // Firefox
285 |
286 | delta = - event.detail;
287 |
288 | }
289 |
290 | if ( delta > 0 ) {
291 |
292 | scope.zoomOut();
293 |
294 | } else {
295 |
296 | scope.zoomIn();
297 |
298 | }
299 |
300 | }
301 |
302 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
303 | this.domElement.addEventListener( 'mousedown', onMouseDown, false );
304 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
305 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
306 |
307 | };
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | global.$ = $;
2 |
3 | //TODO Globals OUT!!
4 | thingiurlbase = "js/thingiview";
5 |
6 | var sourcefolder_view = require('sourcefolder_view');
7 | var targetfolder_view = require('targetfolder_view');
8 | var path = require('path');
9 | var fs = require('fs');
10 | var _ = require('underscore');
11 | var events = require('events');
12 | var util = require('util');
13 |
14 | global.fileCache = global.fileCache || [];
15 |
16 | $(document).ready(function() {
17 |
18 | if (!Modernizr.draganddrop) {
19 | $('#message').html("Your browser cannot handle drag and drop.");
20 | }
21 |
22 | var ui = new UI();
23 |
24 |
25 | var toggleButtons = ''
26 | + ''
27 | + '';
28 |
29 |
30 | var uiLayout = $('#container').layout({
31 | minSize: 100,
32 | //stateManagement__enabled: true,
33 | west__size: .5,
34 | west__childOptions: {
35 | minSize: 50,
36 | south__size: .5
37 | },
38 | spacing_open: 0,
39 | spacing_closed: 0,
40 | west__spacing_closed: 8,
41 | west__spacing_open: 8,
42 | west__togglerLength_closed: 105,
43 | west__togglerLength_open: 105,
44 | west__togglerContent_closed: toggleButtons,
45 | west__togglerContent_open: toggleButtons,
46 |
47 |
48 | center__childOptions: {
49 | center__onresize_end: $.proxy(ui.resizeViewers, ui),
50 | minSize: 50,
51 | south__size: .5
52 | }
53 | });
54 |
55 | uiLayout.togglers.west
56 | // UN-BIND DEFAULT TOGGLER FUNCTIONALITY
57 | .unbind("click")
58 | // BIND CUSTOM WEST METHODS
59 | .find(".btnTogglerLeft") .click( maximizeCenter ).attr("title", "Maximize Left").end()
60 | .find(".btnTogglerCenter") .click( maximizeBoth ).attr("title", "Maximize Center").end()
61 | .find(".btnTogglerRight").click( maximizeWest ).attr("title", "Maximize Right").end()
62 | ;
63 |
64 | function maximizeCenter (evt) { uiLayout.close("west"); evt.stopPropagation(); };
65 | function maximizeBoth (evt) { uiLayout.sizePane("west", "50%"); uiLayout.open("west"); evt.stopPropagation(); };
66 | function maximizeWest (evt) { uiLayout.sizePane("west", "100%"); uiLayout.open("west"); evt.stopPropagation(); };
67 |
68 | viewsLayout = $("#views-container").layout({
69 | center__paneSelector: ".ui-layout-center"
70 | });
71 |
72 | foldersLayout = $("#folders-container").layout({
73 | center__paneSelector: ".ui-layout-center"
74 | });
75 |
76 | ui.setUiLayout(uiLayout);
77 | ui.setViewsLayout(viewsLayout);
78 | ui.setFoldersLayout(foldersLayout);
79 |
80 | var sourceFolder = new sourcefolder_view.SourceFolder($('#sourcefilelist'));
81 | var targetFolder = new targetfolder_view.TargetFolder($('#derivativefilelist'));
82 |
83 | var folderDropZone = document.getElementById("sourcedircontainer");
84 |
85 | sourceFolder.on('clickFile', _.bind(targetFolder.showDerivatives, targetFolder) );
86 |
87 | sourceFolder.on('dblclickFile', function(filePath){
88 | fs.readFile(filePath, function(err, fileContents) {
89 | if (err) throw err;
90 |
91 | ui.viewSource(filePath, fileContents);
92 |
93 | });
94 | });
95 |
96 | targetFolder.on('dblclickFile', function(filename,filePath){
97 | fs.readFile(filePath, function(err, fileContents) {
98 | if (err) throw err;
99 |
100 | ui.viewGcode(fileContents.toString());
101 | });
102 | });
103 |
104 |
105 | function handleDragEnter(e) {
106 | folderDropZone.classList.add('over');
107 | }
108 |
109 | function handleDragLeave(e) {
110 | folderDropZone.classList.remove('over');
111 | }
112 |
113 | function handleFolderDrop(e) {
114 | if (e.stopPropagation) {
115 | e.stopPropagation();
116 | }
117 | e.preventDefault();
118 | folderDropZone.classList.remove('over');
119 |
120 | var path = e.dataTransfer.files[0].path;
121 |
122 | sourceFolder.open(path);
123 |
124 | return false;
125 | };
126 |
127 |
128 | folderDropZone.addEventListener('drop', handleFolderDrop, false);
129 | folderDropZone.addEventListener('dragenter', handleDragEnter, false)
130 | folderDropZone.addEventListener('dragleave', handleDragLeave, false);
131 |
132 | folderDropZone.ondragover = function(e) {
133 | e.preventDefault();
134 | };
135 |
136 | folderDropZone.ondragend = function(e) {
137 | folderDropZone.classList.remove('over');
138 | };
139 |
140 | //testing
141 | sourceFolder.open("testfiles");
142 | ui.resizeViewers();
143 |
144 | });
145 |
146 | function UI(){
147 | events.EventEmitter.call(this);
148 | this.gcodeView = new GcodeView($('#gcodeviewer'));
149 | this.sourceView = new SourceView($('#sourceviewer'));
150 | var self = this;
151 |
152 | this.sourceView.on('toggleSourceView', function(e){
153 | self.uiLayout.toggle("west");
154 | self.viewsLayout.toggle("south");
155 | });
156 |
157 | this.gcodeView.on('toggleGcodeView', function(e){
158 | asd = self.viewsLayout
159 | self.uiLayout.toggle("west");
160 | self.viewsLayout.toggle("south");
161 | });
162 | }
163 |
164 | util.inherits(UI, events.EventEmitter);
165 |
166 |
167 | UI.prototype.setUiLayout = function(layout){
168 | this.uiLayout = layout;
169 | }
170 | UI.prototype.setViewsLayout = function(layout){
171 | this.viewsLayout = layout;
172 | }
173 | UI.prototype.setFoldersLayout = function(layout){
174 | this.foldersLayout = layout;
175 | }
176 |
177 | UI.prototype.viewGcode = function(text){
178 | $.proxy(this.gcodeView.display, this.gcodeView, text)();
179 | }
180 |
181 | UI.prototype.viewSource = function(filename, text){
182 | $.proxy(this.sourceView.display, this.sourceView, filename, text)();
183 | }
184 |
185 |
186 | UI.prototype.resizeViewers = function(){
187 | this.gcodeView.resize();
188 | this.sourceView.resize();
189 | }
190 |
191 | function GcodeView(jquery_element){
192 | events.EventEmitter.call(this);
193 | this.element = jquery_element;
194 | this.scene = this.createGcodeScene(this.element);
195 | this.gcodeObject = new THREE.Object3D();
196 |
197 | var self = this;
198 |
199 | this.element.dblclick(function(e){
200 | self.emit('toggleGcodeView');
201 | })
202 | }
203 |
204 | util.inherits(GcodeView, events.EventEmitter);
205 |
206 | GcodeView.prototype.display = function(gcodeText){
207 | if (this.gcodeObject) {
208 | this.scene.remove(this.gcodeObject);
209 | }
210 | this.gcodeObject = createObjectFromGCode(gcodeText);
211 | this.scene.add(this.gcodeObject);
212 | };
213 |
214 | GcodeView.prototype.resize = function(gcodeText){
215 | var w = this.element.width();
216 | var h = this.element.height();
217 | this.gcodeRenderer.setSize(w, h);
218 | this.camera.aspect = w / h;
219 | this.camera.updateProjectionMatrix();
220 | this.controls.handleResize();
221 | };
222 |
223 | GcodeView.prototype.createGcodeScene = function(element) {
224 |
225 | var _gcodeView = this;
226 |
227 | // Renderer
228 | this.gcodeRenderer = new THREE.WebGLRenderer({clearColor:0x000000, clearAlpha: 1});
229 |
230 | this.gcodeRenderer.setSize(element.width(), element.height());
231 | element.append(this.gcodeRenderer.domElement);
232 | this.gcodeRenderer.clear();
233 |
234 | // Scene
235 | this.scene = new THREE.Scene();
236 |
237 | // Lights...
238 | [[0,0,1, 0xFFFFCC],
239 | [0,1,0, 0xFFCCFF],
240 | [1,0,0, 0xCCFFFF],
241 | [0,0,-1, 0xCCCCFF],
242 | [0,-1,0, 0xCCFFCC],
243 | [-1,0,0, 0xFFCCCC]].forEach(function(position) {
244 | var light = new THREE.DirectionalLight(position[3]);
245 | light.position.set(position[0], position[1], position[2]).normalize();
246 | _gcodeView.scene.add(light);
247 | });
248 |
249 | // Camera...
250 | var fov = 45,
251 | aspect = element.width() / element.height(),
252 | near = 1,
253 | far = 10000;
254 | this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
255 |
256 | this.camera.position.z = 300;
257 | this.scene.add(this.camera);
258 | this.controls = new THREE.TrackballControls(this.camera, element.get(0));
259 |
260 | // Action!
261 | function render() {
262 | _gcodeView.controls.update();
263 | _gcodeView.gcodeRenderer.render(_gcodeView.scene, _gcodeView.camera);
264 |
265 | requestAnimationFrame(render); // And repeat...
266 | }
267 | render();
268 | return this.scene;
269 | }
270 |
271 |
272 |
273 | function SourceView(container){
274 | events.EventEmitter.call(this);
275 |
276 | this.thingiview = new Thingiview(container.get(0).id);
277 | this.thingiview.setObjectColor('#C0D8F0');
278 | this.thingiview.setBackgroundColor('#000');
279 | this.thingiview.initScene();
280 | this.thingiview.setCameraView('iso');
281 |
282 | var self = this;
283 |
284 | container.dblclick(function(e){
285 | self.emit('toggleSourceView');
286 | })
287 | }
288 |
289 | util.inherits(SourceView, events.EventEmitter);
290 |
291 | SourceView.prototype.display = function(filename, fileContents){
292 |
293 | if (fileContents.slice(0,5).toString().match(/^solid/)) {
294 | this.thingiview.loadSTLString(fileContents.toString());
295 | } else {
296 | this.thingiview.loadSTLBinary(fileContents.toString('binary'));
297 | }
298 | };
299 |
300 | SourceView.prototype.resize = function(gcodeText){
301 | this.thingiview.onContainerResize();
302 | };
--------------------------------------------------------------------------------
/js/thingiview/thingiloader.js:
--------------------------------------------------------------------------------
1 | Thingiloader = function(event) {
2 | // Code from https://developer.mozilla.org/En/Using_XMLHttpRequest#Receiving_binary_data
3 | this.load_binary_resource = function(url) {
4 | var req = new XMLHttpRequest();
5 | req.open('GET', url, false);
6 | // The following line says we want to receive data as Binary and not as Unicode
7 | req.overrideMimeType('text/plain; charset=x-user-defined');
8 | req.send(null);
9 | if (req.status != 200) return '';
10 |
11 | return req.responseText;
12 | };
13 |
14 | this.loadSTL = function(url) {
15 | var looksLikeBinary = function(reader) {
16 | // STL files don't specify a way to distinguish ASCII from binary.
17 | // The usual way is checking for "solid" at the start of the file --
18 | // but Thingiverse has seen at least one binary STL file in the wild
19 | // that breaks this.
20 |
21 | // The approach here is different: binary STL files contain a triangle
22 | // count early in the file. If this correctly predicts the file's length,
23 | // it is most probably a binary STL file.
24 |
25 | reader.seek(80); // skip the header
26 | var count = reader.readUInt32();
27 |
28 | var predictedSize = 80 /* header */ + 4 /* count */ + 50 * count;
29 | return reader.getSize() == predictedSize;
30 | };
31 |
32 | workerFacadeMessage({'status':'message', 'content':'Downloading ' + url});
33 | var file = this.load_binary_resource(url);
34 | var reader = new BinaryReader(file);
35 |
36 | if (looksLikeBinary(reader)) {
37 | this.loadSTLBinary(reader);
38 | } else {
39 | this.loadSTLString(file);
40 | }
41 | };
42 |
43 | this.loadOBJ = function(url) {
44 | workerFacadeMessage({'status':'message', 'content':'Downloading ' + url});
45 | var file = this.load_binary_resource(url);
46 | this.loadOBJString(file);
47 | };
48 |
49 | this.loadJSON = function(url) {
50 | workerFacadeMessage({'status':'message', 'content':'Downloading ' + url});
51 | var file = this.load_binary_resource(url);
52 | this.loadJSONString(file);
53 | };
54 |
55 | this.loadPLY = function(url) {
56 | workerFacadeMessage({'status':'message', 'content':'Downloading ' + url});
57 |
58 | var file = this.load_binary_resource(url);
59 |
60 | if (file.match(/format ascii/i)) {
61 | this.loadPLYString(file);
62 | } else {
63 | this.loadPLYBinary(file);
64 | }
65 | };
66 |
67 | this.loadSTLString = function(STLString) {
68 | workerFacadeMessage({'status':'message', 'content':'Parsing STL String...'});
69 | workerFacadeMessage({'status':'complete', 'content':this.ParseSTLString(STLString)});
70 | };
71 |
72 | this.loadSTLBinary = function(STLBinary) {
73 | workerFacadeMessage({'status':'message', 'content':'Parsing STL Binary...'});
74 |
75 | if (STLBinary instanceof BinaryReader){
76 | workerFacadeMessage({'status':'complete', 'content':this.ParseSTLBinary(STLBinary)});
77 | } else {
78 | workerFacadeMessage({'status':'complete', 'content':this.ParseSTLBinary(new BinaryReader(STLBinary))});
79 | }
80 | };
81 |
82 | this.loadOBJString = function(OBJString) {
83 | workerFacadeMessage({'status':'message', 'content':'Parsing OBJ String...'});
84 | workerFacadeMessage({'status':'complete', 'content':this.ParseOBJString(OBJString)});
85 | };
86 |
87 | this.loadJSONString = function(JSONString) {
88 | workerFacadeMessage({'status':'message', 'content':'Parsing JSON String...'});
89 | workerFacadeMessage({'status':'complete', 'content':eval(JSONString)});
90 | };
91 |
92 | this.loadPLYString = function(PLYString) {
93 | workerFacadeMessage({'status':'message', 'content':'Parsing PLY String...'});
94 | workerFacadeMessage({'status':'complete_points', 'content':this.ParsePLYString(PLYString)});
95 | };
96 |
97 | this.loadPLYBinary = function(PLYBinary) {
98 | workerFacadeMessage({'status':'message', 'content':'Parsing PLY Binary...'});
99 | workerFacadeMessage({'status':'complete_points', 'content':this.ParsePLYBinary(PLYBinary)});
100 | };
101 |
102 | this.ParsePLYString = function(input) {
103 | var properties = [];
104 | var vertices = [];
105 | var colors = [];
106 |
107 | var vertex_count = 0;
108 |
109 | var header = /ply\n([\s\S]+)\nend_header/ig.exec(input)[1];
110 | var data = /end_header\n([\s\S]+)$/ig.exec(input)[1];
111 |
112 | // workerFacadeMessage({'status':'message', 'content':'header:\n' + header});
113 | // workerFacadeMessage({'status':'message', 'content':'data:\n' + data});
114 |
115 | header_parts = header.split("\n");
116 |
117 | for (i in header_parts) {
118 | if (/element vertex/i.test(header_parts[i])) {
119 | vertex_count = /element vertex (\d+)/i.exec(header_parts[i])[1];
120 | } else if (/property/i.test(header_parts[i])) {
121 | properties.push(/property (.*) (.*)/i.exec(header_parts[i])[2]);
122 | }
123 | }
124 |
125 | // workerFacadeMessage({'status':'message', 'content':'properties: ' + properties});
126 |
127 | data_parts = data.split("\n");
128 |
129 | for (i in data_parts) {
130 | data_line = data_parts[i];
131 | data_line_parts = data_line.split(" ");
132 |
133 | vertices.push([
134 | parseFloat(data_line_parts[properties.indexOf("x")]),
135 | parseFloat(data_line_parts[properties.indexOf("y")]),
136 | parseFloat(data_line_parts[properties.indexOf("z")])
137 | ]);
138 |
139 | colors.push([
140 | parseInt(data_line_parts[properties.indexOf("red")]),
141 | parseInt(data_line_parts[properties.indexOf("green")]),
142 | parseInt(data_line_parts[properties.indexOf("blue")])
143 | ]);
144 | }
145 |
146 | // workerFacadeMessage({'status':'message', 'content':'vertices: ' + vertices});
147 |
148 | return [vertices, colors];
149 | };
150 |
151 | this.ParsePLYBinary = function(input) {
152 | return false;
153 | };
154 |
155 | this.ParseSTLBinary = function(input) {
156 | // Skip the header.
157 | input.seek(80);
158 |
159 | // Load the number of vertices.
160 | var count = input.readUInt32();
161 |
162 | // During the parse loop we maintain the following data structures:
163 | var vertices = []; // Append-only list of all unique vertices.
164 | var vert_hash = {}; // Mapping from vertex to index in 'vertices', above.
165 | var faces = []; // List of triangle descriptions, each a three-element
166 | // list of indices in 'vertices', above.
167 |
168 | for (var i = 0; i < count; i++) {
169 | if (i % 100 == 0) {
170 | workerFacadeMessage({
171 | 'status':'message',
172 | 'content':'Parsing ' + (i+1) + ' of ' + count + ' polygons...'
173 | });
174 | workerFacadeMessage({
175 | 'status':'progress',
176 | 'content':parseInt(i / count * 100) + '%'
177 | });
178 | }
179 |
180 | // Skip the normal (3 single-precision floats)
181 | input.seek(input.getPosition() + 12);
182 |
183 | var face_indices = [];
184 | for (var x = 0; x < 3; x++) {
185 | var vertex = [input.readFloat(), input.readFloat(), input.readFloat()];
186 |
187 | var vertexIndex = vert_hash[vertex];
188 | if (vertexIndex == null) {
189 | vertexIndex = vertices.length;
190 | vertices.push(vertex);
191 | vert_hash[vertex] = vertexIndex;
192 | }
193 |
194 | face_indices.push(vertexIndex);
195 | }
196 | faces.push(face_indices);
197 |
198 | // Skip the "attribute" field (unused in common models)
199 | input.readUInt16();
200 | }
201 |
202 | return [vertices, faces];
203 | };
204 |
205 | // build stl's vertex and face arrays
206 | this.ParseSTLString = function(STLString) {
207 | var vertexes = [];
208 | var faces = [];
209 |
210 | var face_vertexes = [];
211 | var vert_hash = {}
212 |
213 | // console.log(STLString);
214 |
215 | // strip out extraneous stuff
216 | STLString = STLString.replace(/\r/, "\n");
217 | STLString = STLString.replace(/^solid[^\n]*/, "");
218 | STLString = STLString.replace(/\n/g, " ");
219 | STLString = STLString.replace(/facet normal /g,"");
220 | STLString = STLString.replace(/outer loop/g,"");
221 | STLString = STLString.replace(/vertex /g,"");
222 | STLString = STLString.replace(/endloop/g,"");
223 | STLString = STLString.replace(/endfacet/g,"");
224 | STLString = STLString.replace(/endsolid[^\n]*/, "");
225 | STLString = STLString.replace(/\s+/g, " ");
226 | STLString = STLString.replace(/^\s+/, "");
227 |
228 | // console.log(STLString);
229 |
230 | var facet_count = 0;
231 | var block_start = 0;
232 |
233 | var points = STLString.split(" ");
234 |
235 | workerFacadeMessage({'status':'message', 'content':'Parsing vertices...'});
236 | for (var i=0; i 0 && deltaY >= 0) // 0 - 90
25 | return Math.atan(deltaY/deltaX);
26 | else if (deltaX < 0 && deltaY >= 0) // 90 to 180
27 | return Math.PI - Math.abs(Math.atan(deltaY/deltaX));
28 | else if (deltaX < 0 && deltaY < 0) // 180 - 270
29 | return Math.PI + Math.abs(Math.atan(deltaY/deltaX));
30 | else if (deltaX > 0 && deltaY < 0) // 270 - 360
31 | return Math.PI * 2 - Math.abs(Math.atan(deltaY/deltaX));
32 | }
33 | else {
34 | //
35 | if (deltaY > 0) { // 90 deg
36 | return Math.PI / 2.0;
37 | }
38 | else { // 270 deg
39 | return Math.PI * 3.0 / 2.0;
40 | }
41 | }
42 |
43 | }
44 |
45 | var lastLine = {x:0, y:0, z:0, e:0, f:0, extruding:false};
46 |
47 |
48 | var bbbox = { min: { x:100000,y:100000,z:100000 }, max: { x:-100000,y:-100000,z:-100000 } };
49 | var cutMaterial = new THREE.LineBasicMaterial({
50 | opacity: 0.8,
51 | transparent: true,
52 | linewidth: 10,
53 | vertexColors: THREE.FaceColors });
54 | var rapidMaterial = new THREE.LineBasicMaterial({
55 | opacity: 0.8,
56 | transparent: true,
57 | linewidth: 10,
58 | vertexColors: THREE.FaceColors });
59 | var cutColor = new THREE.Color(0xffffff );
60 | var rapidColor = new THREE.Color(0x0000ff );
61 | var arcColor = new THREE.Color(0xff0000 );
62 |
63 |
64 | function addSegment(p1, p2) {
65 |
66 | geometry.vertices.push(new THREE.Vector3(p1.x, p1.y, p1.z));
67 | geometry.vertices.push(new THREE.Vector3(p2.x, p2.y, p2.z));
68 | geometry.colors.push(p2.extruding ? cutColor : rapidColor);
69 | geometry.colors.push(p2.extruding ? cutColor : rapidColor);
70 |
71 | if (p2.extruding) {
72 | bbbox.min.x = Math.min(bbbox.min.x, p2.x);
73 | bbbox.min.y = Math.min(bbbox.min.y, p2.y);
74 | bbbox.min.z = Math.min(bbbox.min.z, p2.z);
75 | bbbox.max.x = Math.max(bbbox.max.x, p2.x);
76 | bbbox.max.y = Math.max(bbbox.max.y, p2.y);
77 | bbbox.max.z = Math.max(bbbox.max.z, p2.z);
78 | }
79 |
80 | }
81 |
82 | function addArc(p1, p2, center, isCw) {
83 |
84 | var numPoints = 24; // TO DO....could this be dynamic or user selectable?
85 | var radius;
86 | var lineStart = p1;
87 | var lineEnd = p2;
88 | var sweep;
89 |
90 | //use pythag theorum...to get the radius
91 | radius = Math.pow(Math.pow(p1.x - center.x, 2.0) + Math.pow(p1.y - center.y, 2.0), 0.5);
92 |
93 | var startAngle = getAngle(center, p1);
94 | //console.log("strt", startAngle);
95 | var endAngle = getAngle(center, p2);
96 | //console.log("end", endAngle);
97 |
98 | // if it ends at 0 it really should end at 360
99 | if (endAngle == 0)
100 | endAngle = Math.PI * 2;
101 |
102 | if (!isCw && endAngle < startAngle)
103 | sweep = ((Math.PI * 2 - startAngle) + endAngle);
104 | else if (isCw && endAngle > startAngle)
105 | sweep = ((Math.PI * 2 - endAngle) + startAngle);
106 | else
107 | sweep = Math.abs(endAngle - startAngle);
108 |
109 | //console.log("sweep",sweep);
110 | //console.log("end ang",endAngle);
111 |
112 | for(i=0; i<=numPoints; i++)
113 | {
114 |
115 | if (isCw)
116 | var angle = (startAngle - i * sweep/numPoints);
117 | else
118 | var angle = (startAngle + i * sweep/numPoints);
119 |
120 | //console.log("ang",angle);
121 |
122 | if (angle >= Math.PI * 2)
123 | angle = angle - Math.PI * 2;
124 |
125 | var x = Math.cos(angle) * radius;
126 | var y = Math.sin(angle) * radius;
127 |
128 | lineEnd.x = center.x + x;
129 | lineEnd.y = center.y + y;
130 |
131 | geometry.vertices.push(new THREE.Vector3(lineStart.x, lineStart.y, lineStart.z));
132 |
133 | if (i == numPoints) { // last point goes to the end
134 | geometry.vertices.push(new THREE.Vector3(p2.x, p2.y, p2.z));
135 |
136 | }
137 | else {
138 | geometry.vertices.push(new THREE.Vector3(lineEnd.x, lineEnd.y, lineEnd.z));
139 |
140 | }
141 |
142 | geometry.colors.push(arcColor);
143 | geometry.colors.push(arcColor);
144 |
145 | lineStart.x = lineEnd.x;
146 | lineStart.y = lineEnd.y;
147 |
148 | }
149 |
150 |
151 | //TO DO: deal with bounding box
152 |
153 | }
154 |
155 | // add counter clockwise arc
156 | function addCcwArc(p1, p2, center) {
157 |
158 | var numPoints = 24; // TO DO....could this be dynamic or user selectable?
159 | var radius;
160 | var lineStart = p1;
161 | var lineEnd = p2;
162 |
163 | //use pythag theorum...to get the radius
164 | radius = Math.pow(Math.pow(p1.x - center.x, 2.0) + Math.pow(p1.y - center.y, 2.0), 0.5);
165 |
166 | var startAngle = getAngle(center, p1);
167 | var endAngle = getAngle(center, p2);
168 |
169 | // if it ends at 0 it really should end at 360
170 | if (endAngle == 0)
171 | endAngle = Math.PI * 2;
172 |
173 | var sweep = endAngle - startAngle;
174 |
175 | for(i=0; i<=numPoints; i++)
176 | {
177 | var angle = (startAngle + i * sweep/numPoints);
178 |
179 | if (angle >= Math.PI *2)
180 | angle = angle - Math.PI * 2;
181 | else if (angle < 0)
182 | angle = angle + Math.PI * 2; // angle is less than 0 so it subtracts
183 |
184 |
185 | var x = Math.cos(angle) * radius;
186 | var y = Math.sin(angle) * radius;
187 |
188 | lineEnd.x = center.x + x;
189 | lineEnd.y = center.y + y;
190 |
191 | geometry.vertices.push(new THREE.Vector3(lineStart.x, lineStart.y, lineStart.z));
192 |
193 | if (i == numPoints) { // last point goes to the end
194 | geometry.vertices.push(new THREE.Vector3(p2.x, p2.y, p2.z));
195 |
196 | }
197 | else {
198 | geometry.vertices.push(new THREE.Vector3(lineEnd.x, lineEnd.y, lineEnd.z));
199 |
200 | }
201 |
202 | geometry.colors.push(arcColor);
203 | geometry.colors.push(arcColor);
204 |
205 | lineStart.x = lineEnd.x;
206 | lineStart.y = lineEnd.y;
207 |
208 | }
209 |
210 |
211 | //TO DO: deal with bounding box
212 |
213 | }
214 |
215 | var relative = false;
216 | function delta(v1, v2) {
217 | return relative ? v2 : v2 - v1;
218 | }
219 | function absolute (v1, v2) {
220 | return relative ? v1 + v2 : v2;
221 | }
222 |
223 |
224 |
225 | var parser = new GCodeParser({
226 |
227 | 'default': function(args, info) {
228 | console.error('Unknown command:', args.cmd, args, info);
229 | },
230 |
231 | 'parsLine': function (args) {
232 | if (args.cmdType == "G") {
233 | switch (args.cmdNumber) {
234 | case 0: // G0 rapid linear move
235 | case 1: // G1 cut move
236 | var newLine = {
237 | x: args.x !== undefined ? absolute(lastLine.x, args.x) : lastLine.x,
238 | y: args.y !== undefined ? absolute(lastLine.y, args.y) : lastLine.y,
239 | z: args.z !== undefined ? absolute(lastLine.z, args.z) : lastLine.z,
240 | e: args.e !== undefined ? args.e : 0,
241 | f: args.f !== undefined ? absolute(lastLine.f, args.f) : lastLine.f,
242 | };
243 |
244 | if (args.cmdNumber == 0)
245 | newLine.extruding = false;
246 | else
247 | if (isPrinterGcode)
248 | {
249 | newLine.extruding = (args.e > 0);
250 | }
251 | else
252 | {
253 | newLine.extruding = true;
254 | }
255 |
256 |
257 |
258 | addSegment(lastLine, newLine);
259 | lastLine = newLine;
260 |
261 | break;
262 | case 2: // CW Arc
263 | case 3: // CCW Arc
264 | //console.log("Do G2");
265 | var endPoint = {
266 | x: args.x !== undefined ? args.x : lastLine.x,
267 | y: args.y !== undefined ? args.y : lastLine.y,
268 | z: args.z !== undefined ? args.z : lastLine.z,
269 | };
270 |
271 | // the center point is offset from the start point by args I and J
272 | var center = {
273 | x: lastLine.x + args.i,
274 | y: lastLine.y + args.j,
275 | z: lastLine.z,
276 | };
277 |
278 | //addArc(lastLine, endPoint, center, true);
279 | addArc(lastLine, endPoint, center, (args.cmdNumber == "2") ? true : false);
280 | lastLine = endPoint;
281 | break;
282 | case 20: // units inch
283 | units = "inch"
284 | break;
285 | case 21: // units mm
286 | units = "mm"
287 | break;
288 | case 90:
289 | relative = false;
290 | break;
291 | case 91:
292 | relative = true;
293 | break;
294 | case 92: // zero machine coordinates
295 |
296 | if (args.e !== undefined && args.e == 0) {
297 | isPrinterGcode = true;
298 | }
299 | break;
300 | default:
301 | //console.log("do unknown command G" + args.cmdNumber);
302 | break;
303 |
304 | }
305 | }
306 | else if (args.cmdType == "M") {
307 | }
308 | else if (args.cmdType == "S") {
309 | }
310 | else {
311 | console.log("Unknown cmd type: " + args.cmdType);
312 | }
313 |
314 |
315 | },
316 |
317 | });
318 |
319 | parser.parseBjd(gcode); // in gcode-parser.js
320 |
321 | //console.log("Layer Count", layers.count());
322 |
323 | var object = new THREE.Object3D();
324 |
325 | object.add(new THREE.Line(geometry, cutMaterial, THREE.LinePieces));
326 |
327 |
328 | var radius = 1,
329 | segments = 16,
330 | rings = 16;
331 |
332 |
333 | if (units == "mm")
334 | radius = 1;
335 | else
336 | radius = .039;
337 | //radius = (units == "mm") ? 1 : 2;
338 |
339 | var sphereMaterial =
340 | new THREE.MeshLambertMaterial(
341 | {
342 | color: 0x00CC00
343 | });
344 |
345 | // put a sphere at 0,0,0
346 | var sphere = new THREE.Mesh(
347 |
348 | new THREE.SphereGeometry(
349 | radius,
350 | segments,
351 | rings),
352 |
353 | sphereMaterial);
354 |
355 | sphere.position.x = 0;
356 | sphere.position.y = 0;
357 | sphere.position.z = 0;
358 |
359 | // add the sphere to the scene
360 | object.add(sphere);
361 |
362 | //console.log("bbox ", bbbox);
363 |
364 | // Center
365 | var scale = 3; // TODO: Auto size
366 |
367 | var center = new THREE.Vector3(
368 | bbbox.min.x + ((bbbox.max.x - bbbox.min.x) / 2),
369 | bbbox.min.y + ((bbbox.max.y - bbbox.min.y) / 2),
370 | bbbox.min.z + ((bbbox.max.z - bbbox.min.z) / 2));
371 | //console.log("center ", center);
372 |
373 | object.position = center.multiplyScalar(-scale);
374 |
375 | object.scale.multiplyScalar(scale);
376 |
377 | return object;
378 | }
--------------------------------------------------------------------------------
/js/gcodeviewer/Three.TrackballControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eberhard Graether / http://egraether.com/
3 | */
4 |
5 | THREE.TrackballControls = function ( object, domElement ) {
6 |
7 | THREE.EventDispatcher.call( this );
8 |
9 | var _this = this;
10 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 };
11 |
12 | this.object = object;
13 | this.domElement = ( domElement !== undefined ) ? domElement : document;
14 |
15 | // API
16 |
17 | this.enabled = true;
18 |
19 | this.screen = { width: 0, height: 0, offsetLeft: 0, offsetTop: 0 };
20 | this.radius = ( this.screen.width + this.screen.height ) / 4;
21 |
22 | this.rotateSpeed = 1.0;
23 | this.zoomSpeed = 1.2;
24 | this.panSpeed = 0.3;
25 |
26 | this.noRotate = false;
27 | this.noZoom = false;
28 | this.noPan = false;
29 |
30 | this.staticMoving = false;
31 | this.dynamicDampingFactor = 0.2;
32 |
33 | this.minDistance = 0;
34 | this.maxDistance = Infinity;
35 |
36 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
37 |
38 | // internals
39 |
40 | this.target = new THREE.Vector3();
41 |
42 | var lastPosition = new THREE.Vector3();
43 |
44 | var _state = STATE.NONE,
45 | _prevState = STATE.NONE,
46 |
47 | _eye = new THREE.Vector3(),
48 |
49 | _rotateStart = new THREE.Vector3(),
50 | _rotateEnd = new THREE.Vector3(),
51 |
52 | _zoomStart = new THREE.Vector2(),
53 | _zoomEnd = new THREE.Vector2(),
54 |
55 | _touchZoomDistanceStart = 0,
56 | _touchZoomDistanceEnd = 0,
57 |
58 | _panStart = new THREE.Vector2(),
59 | _panEnd = new THREE.Vector2();
60 |
61 | // events
62 |
63 | var changeEvent = { type: 'change' };
64 |
65 |
66 | // methods
67 |
68 | this.handleResize = function () {
69 |
70 | this.screen.width = window.innerWidth;
71 | this.screen.height = window.innerHeight;
72 |
73 | this.screen.offsetLeft = 0;
74 | this.screen.offsetTop = 0;
75 |
76 | this.radius = ( this.screen.width + this.screen.height ) / 4;
77 |
78 | };
79 |
80 | this.handleEvent = function ( event ) {
81 |
82 | if ( typeof this[ event.type ] == 'function' ) {
83 |
84 | this[ event.type ]( event );
85 |
86 | }
87 |
88 | };
89 |
90 | this.getMouseOnScreen = function ( clientX, clientY ) {
91 |
92 | return new THREE.Vector2(
93 | ( clientX - _this.screen.offsetLeft ) / _this.radius * 0.5,
94 | ( clientY - _this.screen.offsetTop ) / _this.radius * 0.5
95 | );
96 |
97 | };
98 |
99 | this.getMouseProjectionOnBall = function ( clientX, clientY ) {
100 |
101 | var mouseOnBall = new THREE.Vector3(
102 | ( clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft ) / _this.radius,
103 | ( _this.screen.height * 0.5 + _this.screen.offsetTop - clientY ) / _this.radius,
104 | 0.0
105 | );
106 |
107 | var length = mouseOnBall.length();
108 |
109 | if ( length > 1.0 ) {
110 |
111 | mouseOnBall.normalize();
112 |
113 | } else {
114 |
115 | mouseOnBall.z = Math.sqrt( 1.0 - length * length );
116 |
117 | }
118 |
119 | _eye.copy( _this.object.position ).sub( _this.target );
120 |
121 | var projection = _this.object.up.clone().setLength( mouseOnBall.y );
122 | projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) );
123 | projection.add( _eye.setLength( mouseOnBall.z ) );
124 |
125 | return projection;
126 |
127 | };
128 |
129 | this.rotateCamera = function () {
130 |
131 | var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
132 |
133 | if ( angle ) {
134 |
135 | var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(),
136 | quaternion = new THREE.Quaternion();
137 |
138 | angle *= _this.rotateSpeed;
139 |
140 | quaternion.setFromAxisAngle( axis, -angle );
141 |
142 | _eye.applyQuaternion( quaternion );
143 | _this.object.up.applyQuaternion( quaternion );
144 |
145 | _rotateEnd.applyQuaternion( quaternion );
146 |
147 | if ( _this.staticMoving ) {
148 |
149 | _rotateStart.copy( _rotateEnd );
150 |
151 | } else {
152 |
153 | quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
154 | _rotateStart.applyQuaternion( quaternion );
155 |
156 | }
157 |
158 | }
159 |
160 | };
161 |
162 | this.zoomCamera = function () {
163 |
164 | if ( _state === STATE.TOUCH_ZOOM ) {
165 |
166 | var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
167 | _touchZoomDistanceStart = _touchZoomDistanceEnd;
168 | _eye.multiplyScalar( factor );
169 |
170 | } else {
171 |
172 | var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
173 |
174 | if ( factor !== 1.0 && factor > 0.0 ) {
175 |
176 | _eye.multiplyScalar( factor );
177 |
178 | if ( _this.staticMoving ) {
179 |
180 | _zoomStart.copy( _zoomEnd );
181 |
182 | } else {
183 |
184 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
185 |
186 | }
187 |
188 | }
189 |
190 | }
191 |
192 | };
193 |
194 | this.panCamera = function () {
195 |
196 | var mouseChange = _panEnd.clone().sub( _panStart );
197 |
198 | if ( mouseChange.lengthSq() ) {
199 |
200 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
201 |
202 | var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x );
203 | pan.add( _this.object.up.clone().setLength( mouseChange.y ) );
204 |
205 | _this.object.position.add( pan );
206 | _this.target.add( pan );
207 |
208 | if ( _this.staticMoving ) {
209 |
210 | _panStart = _panEnd;
211 |
212 | } else {
213 |
214 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
215 |
216 | }
217 |
218 | }
219 |
220 | };
221 |
222 | this.checkDistances = function () {
223 |
224 | if ( !_this.noZoom || !_this.noPan ) {
225 |
226 | if ( _this.object.position.lengthSq() > _this.maxDistance * _this.maxDistance ) {
227 |
228 | _this.object.position.setLength( _this.maxDistance );
229 |
230 | }
231 |
232 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
233 |
234 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
235 |
236 | }
237 |
238 | }
239 |
240 | };
241 |
242 | this.update = function () {
243 |
244 | _eye.subVectors( _this.object.position, _this.target );
245 |
246 | if ( !_this.noRotate ) {
247 |
248 | _this.rotateCamera();
249 |
250 | }
251 |
252 | if ( !_this.noZoom ) {
253 |
254 | _this.zoomCamera();
255 |
256 | }
257 |
258 | if ( !_this.noPan ) {
259 |
260 | _this.panCamera();
261 |
262 | }
263 |
264 | _this.object.position.addVectors( _this.target, _eye );
265 |
266 | _this.checkDistances();
267 |
268 | _this.object.lookAt( _this.target );
269 |
270 | if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {
271 |
272 | _this.dispatchEvent( changeEvent );
273 |
274 | lastPosition.copy( _this.object.position );
275 |
276 | }
277 |
278 | };
279 |
280 | // listeners
281 |
282 | function keydown( event ) {
283 |
284 | if ( _this.enabled === false ) return;
285 |
286 | window.removeEventListener( 'keydown', keydown );
287 |
288 | _prevState = _state;
289 |
290 | if ( _state !== STATE.NONE ) {
291 |
292 | return;
293 |
294 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {
295 |
296 | _state = STATE.ROTATE;
297 |
298 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {
299 |
300 | _state = STATE.ZOOM;
301 |
302 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {
303 |
304 | _state = STATE.PAN;
305 |
306 | }
307 |
308 | }
309 |
310 | function keyup( event ) {
311 |
312 | if ( _this.enabled === false ) return;
313 |
314 | _state = _prevState;
315 |
316 | window.addEventListener( 'keydown', keydown, false );
317 |
318 | }
319 |
320 | function mousedown( event ) {
321 |
322 | if ( _this.enabled === false ) return;
323 |
324 | event.preventDefault();
325 | event.stopPropagation();
326 |
327 | if ( _state === STATE.NONE ) {
328 |
329 | _state = event.button;
330 |
331 | }
332 |
333 | if ( _state === STATE.ROTATE && !_this.noRotate ) {
334 |
335 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
336 |
337 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) {
338 |
339 | _zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
340 |
341 | } else if ( _state === STATE.PAN && !_this.noPan ) {
342 |
343 | _panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
344 |
345 | }
346 |
347 | document.addEventListener( 'mousemove', mousemove, false );
348 | document.addEventListener( 'mouseup', mouseup, false );
349 |
350 | }
351 |
352 | function mousemove( event ) {
353 |
354 | if ( _this.enabled === false ) return;
355 |
356 | event.preventDefault();
357 | event.stopPropagation();
358 |
359 | if ( _state === STATE.ROTATE && !_this.noRotate ) {
360 |
361 | _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
362 |
363 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) {
364 |
365 | _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
366 |
367 | } else if ( _state === STATE.PAN && !_this.noPan ) {
368 |
369 | _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
370 |
371 | }
372 |
373 | }
374 |
375 | function mouseup( event ) {
376 |
377 | if ( _this.enabled === false ) return;
378 |
379 | event.preventDefault();
380 | event.stopPropagation();
381 |
382 | _state = STATE.NONE;
383 |
384 | document.removeEventListener( 'mousemove', mousemove );
385 | document.removeEventListener( 'mouseup', mouseup );
386 |
387 | }
388 |
389 | function mousewheel( event ) {
390 |
391 | if ( _this.enabled === false ) return;
392 |
393 | event.preventDefault();
394 | event.stopPropagation();
395 |
396 | var delta = 0;
397 |
398 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
399 |
400 | delta = event.wheelDelta / 40;
401 |
402 | } else if ( event.detail ) { // Firefox
403 |
404 | delta = - event.detail / 3;
405 |
406 | }
407 |
408 | _zoomStart.y += ( 1 / delta ) * 0.05;
409 |
410 | }
411 |
412 | function touchstart( event ) {
413 |
414 | if ( _this.enabled === false ) return;
415 |
416 | switch ( event.touches.length ) {
417 |
418 | case 1:
419 | _state = STATE.TOUCH_ROTATE;
420 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
421 | break;
422 |
423 | case 2:
424 | _state = STATE.TOUCH_ZOOM;
425 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
426 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
427 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
428 | break;
429 |
430 | case 3:
431 | _state = STATE.TOUCH_PAN;
432 | _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
433 | break;
434 |
435 | default:
436 | _state = STATE.NONE;
437 |
438 | }
439 |
440 | }
441 |
442 | function touchmove( event ) {
443 |
444 | if ( _this.enabled === false ) return;
445 |
446 | event.preventDefault();
447 | event.stopPropagation();
448 |
449 | switch ( event.touches.length ) {
450 |
451 | case 1:
452 | _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
453 | break;
454 |
455 | case 2:
456 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
457 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
458 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
459 | break;
460 |
461 | case 3:
462 | _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
463 | break;
464 |
465 | default:
466 | _state = STATE.NONE;
467 |
468 | }
469 |
470 | }
471 |
472 | function touchend( event ) {
473 |
474 | if ( _this.enabled === false ) return;
475 |
476 | switch ( event.touches.length ) {
477 |
478 | case 1:
479 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
480 | break;
481 |
482 | case 2:
483 | _touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
484 | break;
485 |
486 | case 3:
487 | _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
488 | break;
489 |
490 | }
491 |
492 | _state = STATE.NONE;
493 |
494 | }
495 |
496 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
497 |
498 | this.domElement.addEventListener( 'mousedown', mousedown, false );
499 |
500 | this.domElement.addEventListener( 'mousewheel', mousewheel, false );
501 | this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
502 |
503 | this.domElement.addEventListener( 'touchstart', touchstart, false );
504 | this.domElement.addEventListener( 'touchend', touchend, false );
505 | this.domElement.addEventListener( 'touchmove', touchmove, false );
506 |
507 | window.addEventListener( 'keydown', keydown, false );
508 | window.addEventListener( 'keyup', keyup, false );
509 |
510 | this.handleResize();
511 |
512 | };
513 |
--------------------------------------------------------------------------------
/js/thingiview/thingiview.js:
--------------------------------------------------------------------------------
1 | Thingiview = function(containerId) {
2 | scope = this;
3 |
4 | this.containerId = containerId;
5 | var container = document.getElementById(containerId);
6 |
7 | var camera = null;
8 | var scene = null;
9 | var renderer = null;
10 | var object = null;
11 | var plane = null;
12 |
13 | var ambientLight = null;
14 | var directionalLight = null;
15 | var pointLight = null;
16 |
17 | var targetXRotation = 0;
18 | var targetXRotationOnMouseDown = 0;
19 | var mouseX = 0;
20 | var mouseXOnMouseDown = 0;
21 |
22 | var targetYRotation = 0;
23 | var targetYRotationOnMouseDown = 0;
24 | var mouseY = 0;
25 | var mouseYOnMouseDown = 0;
26 |
27 | var mouseDown = false;
28 | var mouseOver = false;
29 |
30 | var windowHalfX = window.innerWidth / 2;
31 | var windowHalfY = window.innerHeight / 2
32 |
33 | var view = null;
34 | var infoMessage = null;
35 | var progressBar = null;
36 | var alertBox = null;
37 |
38 | var timer = null;
39 |
40 | var rotateTimer = null;
41 | var rotateListener = null;
42 | var wasRotating = null;
43 |
44 | var cameraView = 'iso';
45 | var cameraZoom = 0;
46 | var rotate = false;
47 | var backgroundColor = '#606060';
48 | var objectMaterial = 'solid';
49 | var objectColor = 0xffffff;
50 | var showPlane = true;
51 | var isWebGl = false;
52 |
53 | if (document.defaultView && document.defaultView.getComputedStyle) {
54 | var width = parseFloat(document.defaultView.getComputedStyle(container,null).getPropertyValue('width'));
55 | var height = parseFloat(document.defaultView.getComputedStyle(container,null).getPropertyValue('height'));
56 | } else {
57 | var width = parseFloat(container.currentStyle.width);
58 | var height = parseFloat(container.currentStyle.height);
59 | }
60 |
61 | var geometry;
62 |
63 | this.initScene = function() {
64 | container.style.position = 'relative';
65 | container.innerHTML = '';
66 |
67 | camera = new THREE_32.Camera(45, width/ height, 1, 100000);
68 | camera.updateMatrix();
69 |
70 | scene = new THREE_32.Scene();
71 |
72 | ambientLight = new THREE_32.AmbientLight(0x202020);
73 | scene.addLight(ambientLight);
74 |
75 | directionalLight = new THREE_32.DirectionalLight(0xffffff, 0.75);
76 | directionalLight.position.x = 1;
77 | directionalLight.position.y = 1;
78 | directionalLight.position.z = 2;
79 | directionalLight.position.normalize();
80 | scene.addLight(directionalLight);
81 |
82 | pointLight = new THREE_32.PointLight(0xffffff, 0.3);
83 | pointLight.position.x = 0;
84 | pointLight.position.y = -25;
85 | pointLight.position.z = 10;
86 | scene.addLight(pointLight);
87 |
88 | progressBar = document.createElement('div');
89 | progressBar.style.position = 'absolute';
90 | progressBar.style.top = '0px';
91 | progressBar.style.left = '0px';
92 | progressBar.style.backgroundColor = 'red';
93 | progressBar.style.padding = '5px';
94 | progressBar.style.display = 'none';
95 | progressBar.style.overflow = 'visible';
96 | progressBar.style.whiteSpace = 'nowrap';
97 | progressBar.style.zIndex = 100;
98 | container.appendChild(progressBar);
99 |
100 | alertBox = document.createElement('div');
101 | alertBox.id = 'alertBox';
102 | alertBox.style.position = 'absolute';
103 | alertBox.style.top = '25%';
104 | alertBox.style.left = '25%';
105 | alertBox.style.width = '50%';
106 | alertBox.style.height = '50%';
107 | alertBox.style.backgroundColor = '#dddddd';
108 | alertBox.style.padding = '10px';
109 | alertBox.style.display = 'none';
110 | alertBox.style.zIndex = 100;
111 | container.appendChild(alertBox);
112 |
113 | if (showPlane) {
114 | loadPlaneGeometry();
115 | }
116 |
117 | this.setCameraView(cameraView);
118 | this.setObjectMaterial(objectMaterial);
119 |
120 | testCanvas = document.createElement('canvas');
121 | try {
122 | if (testCanvas.getContext('experimental-webgl')) {
123 | isWebGl = true;
124 | renderer = new THREE_32.WebGLRenderer();
125 | } else {
126 | renderer = new THREE_32.CanvasRenderer();
127 | }
128 | } catch(e) {
129 | renderer = new THREE_32.CanvasRenderer();
130 | }
131 |
132 | renderer.setSize(width, height);
133 | renderer.domElement.style.backgroundColor = backgroundColor;
134 | container.appendChild(renderer.domElement);
135 |
136 | window.addEventListener('mousemove', onRendererMouseMove, false);
137 | renderer.domElement.addEventListener('mouseover', onRendererMouseOver, false);
138 | renderer.domElement.addEventListener('mouseout', onRendererMouseOut, false);
139 | renderer.domElement.addEventListener('mousedown', onRendererMouseDown, false);
140 | window.addEventListener('mouseup', onRendererMouseUp, false);
141 |
142 | renderer.domElement.addEventListener('touchstart', onRendererTouchStart, false);
143 | renderer.domElement.addEventListener('touchend', onRendererTouchEnd, false);
144 | renderer.domElement.addEventListener('touchmove', onRendererTouchMove, false);
145 |
146 | renderer.domElement.addEventListener('DOMMouseScroll', onRendererScroll, false);
147 | renderer.domElement.addEventListener('mousewheel', onRendererScroll, false);
148 | renderer.domElement.addEventListener('gesturechange', onRendererGestureChange, false);
149 | }
150 |
151 | this.onContainerResize = function(event) {
152 | width = parseFloat(document.defaultView.getComputedStyle(container,null).getPropertyValue('width'));
153 | height = parseFloat(document.defaultView.getComputedStyle(container,null).getPropertyValue('height'));
154 |
155 | if (renderer) {
156 | renderer.setSize(width, height);
157 | camera.projectionMatrix = THREE_32.Matrix4.makePerspective(70, width / height, 1, 10000);
158 | sceneLoop();
159 | }
160 | };
161 |
162 | onRendererScroll = function(event) {
163 | event.preventDefault();
164 |
165 | var rolled = 0;
166 |
167 | if (event.wheelDelta === undefined) {
168 | // Firefox
169 | // The measurement units of the detail and wheelDelta properties are different.
170 | rolled = -40 * event.detail;
171 | } else {
172 | rolled = event.wheelDelta;
173 | }
174 |
175 | if (rolled > 0) {
176 | // up
177 | scope.setCameraZoom(+10);
178 | } else {
179 | // down
180 | scope.setCameraZoom(-10);
181 | }
182 | }
183 |
184 | onRendererGestureChange = function(event) {
185 | event.preventDefault();
186 |
187 | if (event.scale > 1) {
188 | scope.setCameraZoom(+5);
189 | } else {
190 | scope.setCameraZoom(-5);
191 | }
192 | }
193 |
194 | onRendererMouseOver = function(event) {
195 | mouseOver = true;
196 | if (timer == null) {
197 | timer = setInterval(sceneLoop, 1000/60);
198 | }
199 | }
200 |
201 | onRendererMouseDown = function(event) {
202 | event.preventDefault();
203 | mouseDown = true;
204 |
205 | if(scope.getRotation()){
206 | wasRotating = true;
207 | scope.setRotation(false);
208 | } else {
209 | wasRotating = false;
210 | }
211 |
212 | mouseXOnMouseDown = event.clientX - windowHalfX;
213 | mouseYOnMouseDown = event.clientY - windowHalfY;
214 |
215 | targetXRotationOnMouseDown = targetXRotation;
216 | targetYRotationOnMouseDown = targetYRotation;
217 | }
218 |
219 | onRendererMouseMove = function(event) {
220 | if (mouseDown) {
221 | mouseX = event.clientX - windowHalfX;
222 | xrot = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
223 |
224 | mouseY = event.clientY - windowHalfY;
225 | yrot = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.02;
226 |
227 | targetXRotation = xrot;
228 | targetYRotation = yrot;
229 | }
230 | }
231 |
232 | onRendererMouseUp = function(event) {
233 | if (mouseDown) {
234 | mouseDown = false;
235 | if (!mouseOver) {
236 | clearInterval(timer);
237 | timer = null;
238 | }
239 | if (wasRotating) {
240 | scope.setRotation(true);
241 | }
242 | }
243 | }
244 |
245 | onRendererMouseOut = function(event) {
246 | if (!mouseDown) {
247 | clearInterval(timer);
248 | timer = null;
249 | }
250 | mouseOver = false;
251 | }
252 |
253 | onRendererTouchStart = function(event) {
254 | targetXRotation = object.rotation.z;
255 | targetYRotation = object.rotation.x;
256 |
257 | timer = setInterval(sceneLoop, 1000/60);
258 |
259 | if (event.touches.length == 1) {
260 | event.preventDefault();
261 |
262 | mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
263 | targetXRotationOnMouseDown = targetXRotation;
264 |
265 | mouseYOnMouseDown = event.touches[0].pageY - windowHalfY;
266 | targetYRotationOnMouseDown = targetYRotation;
267 | }
268 | }
269 |
270 | onRendererTouchEnd = function(event) {
271 | clearInterval(timer);
272 | timer = null;
273 | }
274 |
275 | onRendererTouchMove = function(event) {
276 | if (event.touches.length == 1) {
277 | event.preventDefault();
278 |
279 | mouseX = event.touches[0].pageX - windowHalfX;
280 | targetXRotation = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
281 |
282 | mouseY = event.touches[0].pageY - windowHalfY;
283 | targetYRotation = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.05;
284 | }
285 | }
286 |
287 | sceneLoop = function() {
288 | if (object) {
289 | if (showPlane) {
290 | plane.rotation.z = object.rotation.z = (targetXRotation - object.rotation.z) * 0.2;
291 | plane.rotation.x = object.rotation.x = (targetYRotation - object.rotation.x) * 0.2;
292 | } else {
293 | object.rotation.z = (targetXRotation - object.rotation.z) * 0.2;
294 | object.rotation.x = (targetYRotation - object.rotation.x) * 0.2;
295 | }
296 |
297 | camera.updateMatrix();
298 | object.updateMatrix();
299 |
300 | if (showPlane) {
301 | plane.updateMatrix();
302 | }
303 |
304 | renderer.render(scene, camera);
305 | }
306 | }
307 |
308 | rotateLoop = function() {
309 | targetXRotation += 0.05;
310 | sceneLoop();
311 | }
312 |
313 | this.getShowPlane = function(){
314 | return showPlane;
315 | }
316 |
317 | this.setShowPlane = function(show) {
318 | showPlane = show;
319 |
320 | if (show) {
321 | if (scene && !plane) {
322 | loadPlaneGeometry();
323 | }
324 | plane.material[0].opacity = 1;
325 | // plane.updateMatrix();
326 | } else {
327 | if (scene && plane) {
328 | // alert(plane.material[0].opacity);
329 | plane.material[0].opacity = 0;
330 | // plane.updateMatrix();
331 | }
332 | }
333 |
334 | sceneLoop();
335 | }
336 |
337 | this.getRotation = function() {
338 | return rotateTimer !== null;
339 | }
340 |
341 | this.setRotation = function(rotate) {
342 | rotation = rotate;
343 |
344 | if (rotate) {
345 | rotateTimer = setInterval(rotateLoop, 1000/60);
346 | } else {
347 | clearInterval(rotateTimer);
348 | rotateTimer = null;
349 | }
350 |
351 | scope.onSetRotation();
352 | }
353 |
354 | this.onSetRotation = function(callback) {
355 | if(callback === undefined){
356 | if(rotateListener !== null){
357 | try{
358 | rotateListener(scope.getRotation());
359 | } catch(ignored) {}
360 | }
361 | } else {
362 | rotateListener = callback;
363 | }
364 | }
365 |
366 | this.setCameraView = function(dir) {
367 | cameraView = dir;
368 |
369 | targetXRotation = 0;
370 | targetYRotation = 0;
371 |
372 | if (object) {
373 | object.rotation.x = 0;
374 | object.rotation.y = 0;
375 | object.rotation.z = 0;
376 | }
377 |
378 | if (showPlane && object) {
379 | plane.rotation.x = object.rotation.x;
380 | plane.rotation.y = object.rotation.y;
381 | plane.rotation.z = object.rotation.z;
382 | }
383 |
384 | if (dir == 'top') {
385 | // camera.position.y = 0;
386 | // camera.position.z = 100;
387 | // camera.target.position.z = 0;
388 | if (showPlane) {
389 | plane.flipSided = false;
390 | }
391 | } else if (dir == 'side') {
392 | // camera.position.y = -70;
393 | // camera.position.z = 70;
394 | // camera.target.position.z = 0;
395 | targetYRotation = -4.5;
396 | if (showPlane) {
397 | plane.flipSided = false;
398 | }
399 | } else if (dir == 'bottom') {
400 | // camera.position.y = 0;
401 | // camera.position.z = -100;
402 | // camera.target.position.z = 0;
403 | if (showPlane) {
404 | plane.flipSided = true;
405 | }
406 | } else if (dir == 'iso') {
407 | targetXRotation = 45;
408 | targetYRotation = 0;
409 | if (showPlane) {
410 | plane.flipSided = true;
411 | }
412 | } else {
413 | // camera.position.y = -70;
414 | // camera.position.z = 70;
415 | // camera.target.position.z = 0;
416 | if (showPlane) {
417 | plane.flipSided = false;
418 | }
419 | }
420 |
421 | mouseX = targetXRotation;
422 | mouseXOnMouseDown = targetXRotation;
423 |
424 | mouseY = targetYRotation;
425 | mouseYOnMouseDown = targetYRotation;
426 |
427 | scope.centerCamera();
428 |
429 | sceneLoop();
430 | }
431 |
432 | this.setCameraZoom = function(factor) {
433 | cameraZoom = factor;
434 |
435 | if (cameraView == 'bottom') {
436 | if (camera.position.z + factor > 0) {
437 | factor = 0;
438 | }
439 | } else {
440 | if (camera.position.z - factor < 0) {
441 | factor = 0;
442 | }
443 | }
444 |
445 | if (cameraView == 'top') {
446 | camera.position.z -= factor;
447 | } else if (cameraView == 'bottom') {
448 | camera.position.z += factor;
449 | } else if (cameraView == 'side') {
450 | camera.position.y += factor;
451 | camera.position.z -= factor;
452 | } else {
453 | camera.position.y += factor;
454 | camera.position.z -= factor;
455 | }
456 |
457 | sceneLoop();
458 | }
459 |
460 | this.getObjectMaterial = function() {
461 | return objectMaterial;
462 | }
463 |
464 | this.setObjectMaterial = function(type) {
465 | objectMaterial = type;
466 |
467 | loadObjectGeometry();
468 | }
469 |
470 | this.setBackgroundColor = function(color) {
471 | backgroundColor = color
472 |
473 | if (renderer) {
474 | renderer.domElement.style.backgroundColor = color;
475 | }
476 | }
477 |
478 | this.setObjectColor = function(color) {
479 | objectColor = parseInt(color.replace(/\#/g, ''), 16);
480 |
481 | loadObjectGeometry();
482 | }
483 |
484 | this.loadSTL = function(url) {
485 | scope.newWorker('loadSTL', url);
486 | }
487 |
488 | this.loadOBJ = function(url) {
489 | scope.newWorker('loadOBJ', url);
490 | }
491 |
492 | this.loadSTLString = function(STLString) {
493 | scope.newWorker('loadSTLString', STLString);
494 | }
495 |
496 | this.loadSTLBinary = function(STLBinary) {
497 | scope.newWorker('loadSTLBinary', STLBinary);
498 | }
499 |
500 | this.loadOBJString = function(OBJString) {
501 | scope.newWorker('loadOBJString', OBJString);
502 | }
503 |
504 | this.loadJSON = function(url) {
505 | scope.newWorker('loadJSON', url);
506 | }
507 |
508 | this.loadPLY = function(url) {
509 | scope.newWorker('loadPLY', url);
510 | }
511 |
512 | this.loadPLYString = function(PLYString) {
513 | scope.newWorker('loadPLYString', PLYString);
514 | }
515 |
516 | this.loadPLYBinary = function(PLYBinary) {
517 | scope.newWorker('loadPLYBinary', PLYBinary);
518 | }
519 |
520 | this.centerCamera = function() {
521 | if (geometry) {
522 | // Using method from http://msdn.microsoft.com/en-us/library/bb197900(v=xnagamestudio.10).aspx
523 | // log("bounding sphere radius = " + geometry.boundingSphere.radius);
524 |
525 | // look at the center of the object
526 | camera.target.position.x = geometry.center_x;
527 | camera.target.position.y = geometry.center_y;
528 | camera.target.position.z = geometry.center_z;
529 |
530 | // set camera position to center of sphere
531 | camera.position.x = geometry.center_x;
532 | camera.position.y = geometry.center_y;
533 | camera.position.z = geometry.center_z;
534 |
535 | // find distance to center
536 | distance = geometry.boundingSphere.radius / Math.sin((camera.fov/2) * (Math.PI / 180));
537 |
538 | // zoom backwards about half that distance, I don't think I'm doing the math or backwards vector calculation correctly?
539 | // scope.setCameraZoom(-distance/1.8);
540 | // scope.setCameraZoom(-distance/1.5);
541 | scope.setCameraZoom(-distance/0.9);
542 |
543 | directionalLight.position.x = geometry.min_y * 2;
544 | directionalLight.position.y = geometry.min_y * 2;
545 | directionalLight.position.z = geometry.max_z * 2;
546 |
547 | pointLight.position.x = geometry.center_y;
548 | pointLight.position.y = geometry.center_y;
549 | pointLight.position.z = geometry.max_z * 2;
550 | } else {
551 | // set to any valid position so it doesn't fail before geometry is available
552 | camera.position.y = -70;
553 | camera.position.z = 70;
554 | camera.target.position.z = 0;
555 | }
556 | }
557 |
558 | this.loadArray = function(array) {
559 | log("loading array...");
560 | geometry = new STLGeometry(array);
561 | loadObjectGeometry();
562 | scope.setRotation(false);
563 | scope.setRotation(true);
564 | scope.centerCamera();
565 | log("finished loading " + geometry.faces.length + " faces.");
566 | }
567 |
568 | this.progressBarMessage = function(msg){
569 | progressBar.style.display = 'block';
570 | progressBar.innerHTML = msg;
571 | }
572 |
573 | this.newWorker = function(cmd, param) {
574 | scope.setRotation(false);
575 |
576 | var worker = new WorkerFacade(thingiurlbase + '/thingiloader.js');
577 |
578 | worker.onmessage = function(event) {
579 | if (event.data.status == "complete") {
580 | progressBar.innerHTML = 'Initializing geometry...';
581 | // scene.removeObject(object);
582 | geometry = new STLGeometry(event.data.content);
583 | loadObjectGeometry();
584 | progressBar.innerHTML = '';
585 | progressBar.style.display = 'none';
586 |
587 | scope.setRotation(false);
588 | //scope.setRotation(true);
589 | log("finished loading " + geometry.faces.length + " faces.");
590 | //thingiview.setCameraView(cameraView);
591 | scope.setCameraView(cameraView);
592 | scope.centerCamera();
593 | } else if (event.data.status == "complete_points") {
594 | progressBar.innerHTML = 'Initializing points...';
595 |
596 | geometry = new THREE_32.Geometry();
597 |
598 | var material = new THREE_32.ParticleBasicMaterial( { color: 0xff0000, opacity: 1 } );
599 |
600 | // material = new THREE_32.ParticleBasicMaterial( { size: 35, sizeAttenuation: false} );
601 | // material.color.setHSV( 1.0, 0.2, 0.8 );
602 |
603 | for (i in event.data.content[0]) {
604 | // for (var i=0; i<10; i++) {
605 | vector = new THREE_32.Vector3( event.data.content[0][i][0], event.data.content[0][i][1], event.data.content[0][i][2] );
606 | geometry.vertices.push( new THREE_32.Vertex( vector ) );
607 | }
608 |
609 | particles = new THREE_32.ParticleSystem( geometry, material );
610 | particles.sortParticles = true;
611 | particles.updateMatrix();
612 | scene.addObject( particles );
613 |
614 | camera.updateMatrix();
615 | renderer.render(scene, camera);
616 |
617 | progressBar.innerHTML = '';
618 | progressBar.style.display = 'none';
619 |
620 | scope.setRotation(false);
621 | scope.setRotation(true);
622 | log("finished loading " + event.data.content[0].length + " points.");
623 | // scope.centerCamera();
624 | } else if (event.data.status == "progress") {
625 | progressBar.style.display = 'block';
626 | progressBar.style.width = event.data.content;
627 | // log(event.data.content);
628 | } else if (event.data.status == "message") {
629 | progressBar.style.display = 'block';
630 | progressBar.innerHTML = event.data.content;
631 | log(event.data.content);
632 | } else if (event.data.status == "alert") {
633 | scope.displayAlert(event.data.content);
634 | } else {
635 | alert('Error: ' + event.data);
636 | log('Unknown Worker Message: ' + event.data);
637 | }
638 | }
639 |
640 | worker.onerror = function(error) {
641 | log(error);
642 | error.preventDefault();
643 | }
644 |
645 | worker.postMessage({'cmd':cmd, 'param':param});
646 | }
647 |
648 | this.displayAlert = function(msg) {
649 | msg = msg + "
"
650 |
651 | alertBox.innerHTML = msg;
652 | alertBox.style.display = 'block';
653 |
654 | // log(msg);
655 | }
656 |
657 | function loadPlaneGeometry() {
658 | // TODO: switch to lines instead of the Plane object so we can get rid of the horizontal lines in canvas renderer...
659 | plane = new THREE_32.Mesh(new Plane(100, 100, 10, 10), new THREE_32.MeshBasicMaterial({color:0xafafaf,wireframe:true}));
660 | scene.addObject(plane);
661 | }
662 |
663 | function loadObjectGeometry() {
664 | if (scene && geometry) {
665 | if (objectMaterial == 'wireframe') {
666 | material = new THREE_32.MeshBasicMaterial({color:objectColor,wireframe:true});
667 | } else {
668 | if (isWebGl) {
669 | material = new THREE_32.MeshLambertMaterial({color:objectColor, shading: THREE_32.FlatShading});
670 | } else {
671 | material = new THREE_32.MeshLambertMaterial({color:objectColor, shading: THREE_32.FlatShading});
672 | }
673 | }
674 |
675 | if (object) {
676 | // shouldn't be needed, but this fixes a bug with webgl not removing previous object when loading a new one dynamically
677 | object.materials = [new THREE_32.MeshBasicMaterial({color:0xffffff, opacity:0})];
678 | scene.removeObject(object);
679 | }
680 |
681 | object = new THREE_32.Mesh(geometry, material);
682 | scene.addObject(object);
683 |
684 | if (objectMaterial != 'wireframe') {
685 | object.overdraw = true;
686 | object.doubleSided = true;
687 | }
688 |
689 | object.updateMatrix();
690 |
691 | targetXRotation = 0;
692 | targetYRotation = 0;
693 |
694 | sceneLoop();
695 | }
696 | }
697 |
698 | };
699 |
700 | var STLGeometry = function(stlArray) {
701 | // log("building geometry...");
702 | THREE_32.Geometry.call(this);
703 |
704 | var scope = this;
705 |
706 | for (var i=0; i 0){
798 | theworker.postToWorkerFunction(callings[0]);
799 | callings.shift();
800 | }
801 | };
802 | document.body.appendChild(scr);
803 |
804 | var binaryscr = document.createElement("SCRIPT");
805 | binaryscr.src = thingiurlbase + '/binaryReader.js';
806 | binaryscr.type = "text/javascript";
807 | document.body.appendChild(binaryscr);
808 |
809 | return theworker;
810 | };
811 | that.fake = true;
812 | that.add = function(pth, worker){
813 | workers[pth] = worker;
814 | return function(param){
815 | masters[pth].onmessage({"data": param});
816 | };
817 | };
818 | that.toString = function(){
819 | return "FakeWorker('"+path+"')";
820 | };
821 | return that;
822 | }());
823 | }
824 |
--------------------------------------------------------------------------------
/css/bootstrap/bootstrap-responsive.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.2.2
3 | *
4 | * Copyright 2012 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | */
10 |
11 | @-ms-viewport {
12 | width: device-width;
13 | }
14 |
15 | .clearfix {
16 | *zoom: 1;
17 | }
18 |
19 | .clearfix:before,
20 | .clearfix:after {
21 | display: table;
22 | line-height: 0;
23 | content: "";
24 | }
25 |
26 | .clearfix:after {
27 | clear: both;
28 | }
29 |
30 | .hide-text {
31 | font: 0/0 a;
32 | color: transparent;
33 | text-shadow: none;
34 | background-color: transparent;
35 | border: 0;
36 | }
37 |
38 | .input-block-level {
39 | display: block;
40 | width: 100%;
41 | min-height: 30px;
42 | -webkit-box-sizing: border-box;
43 | -moz-box-sizing: border-box;
44 | box-sizing: border-box;
45 | }
46 |
47 | .hidden {
48 | display: none;
49 | visibility: hidden;
50 | }
51 |
52 | .visible-phone {
53 | display: none !important;
54 | }
55 |
56 | .visible-tablet {
57 | display: none !important;
58 | }
59 |
60 | .hidden-desktop {
61 | display: none !important;
62 | }
63 |
64 | .visible-desktop {
65 | display: inherit !important;
66 | }
67 |
68 | @media (min-width: 768px) and (max-width: 979px) {
69 | .hidden-desktop {
70 | display: inherit !important;
71 | }
72 | .visible-desktop {
73 | display: none !important ;
74 | }
75 | .visible-tablet {
76 | display: inherit !important;
77 | }
78 | .hidden-tablet {
79 | display: none !important;
80 | }
81 | }
82 |
83 | @media (max-width: 767px) {
84 | .hidden-desktop {
85 | display: inherit !important;
86 | }
87 | .visible-desktop {
88 | display: none !important;
89 | }
90 | .visible-phone {
91 | display: inherit !important;
92 | }
93 | .hidden-phone {
94 | display: none !important;
95 | }
96 | }
97 |
98 | @media (min-width: 1200px) {
99 | .row {
100 | margin-left: -30px;
101 | *zoom: 1;
102 | }
103 | .row:before,
104 | .row:after {
105 | display: table;
106 | line-height: 0;
107 | content: "";
108 | }
109 | .row:after {
110 | clear: both;
111 | }
112 | [class*="span"] {
113 | float: left;
114 | min-height: 1px;
115 | margin-left: 30px;
116 | }
117 | .container,
118 | .navbar-static-top .container,
119 | .navbar-fixed-top .container,
120 | .navbar-fixed-bottom .container {
121 | width: 1170px;
122 | }
123 | .span12 {
124 | width: 1170px;
125 | }
126 | .span11 {
127 | width: 1070px;
128 | }
129 | .span10 {
130 | width: 970px;
131 | }
132 | .span9 {
133 | width: 870px;
134 | }
135 | .span8 {
136 | width: 770px;
137 | }
138 | .span7 {
139 | width: 670px;
140 | }
141 | .span6 {
142 | width: 570px;
143 | }
144 | .span5 {
145 | width: 470px;
146 | }
147 | .span4 {
148 | width: 370px;
149 | }
150 | .span3 {
151 | width: 270px;
152 | }
153 | .span2 {
154 | width: 170px;
155 | }
156 | .span1 {
157 | width: 70px;
158 | }
159 | .offset12 {
160 | margin-left: 1230px;
161 | }
162 | .offset11 {
163 | margin-left: 1130px;
164 | }
165 | .offset10 {
166 | margin-left: 1030px;
167 | }
168 | .offset9 {
169 | margin-left: 930px;
170 | }
171 | .offset8 {
172 | margin-left: 830px;
173 | }
174 | .offset7 {
175 | margin-left: 730px;
176 | }
177 | .offset6 {
178 | margin-left: 630px;
179 | }
180 | .offset5 {
181 | margin-left: 530px;
182 | }
183 | .offset4 {
184 | margin-left: 430px;
185 | }
186 | .offset3 {
187 | margin-left: 330px;
188 | }
189 | .offset2 {
190 | margin-left: 230px;
191 | }
192 | .offset1 {
193 | margin-left: 130px;
194 | }
195 | .row-fluid {
196 | width: 100%;
197 | *zoom: 1;
198 | }
199 | .row-fluid:before,
200 | .row-fluid:after {
201 | display: table;
202 | line-height: 0;
203 | content: "";
204 | }
205 | .row-fluid:after {
206 | clear: both;
207 | }
208 | .row-fluid [class*="span"] {
209 | display: block;
210 | float: left;
211 | width: 100%;
212 | min-height: 30px;
213 | margin-left: 2.564102564102564%;
214 | *margin-left: 2.5109110747408616%;
215 | -webkit-box-sizing: border-box;
216 | -moz-box-sizing: border-box;
217 | box-sizing: border-box;
218 | }
219 | .row-fluid [class*="span"]:first-child {
220 | margin-left: 0;
221 | }
222 | .row-fluid .controls-row [class*="span"] + [class*="span"] {
223 | margin-left: 2.564102564102564%;
224 | }
225 | .row-fluid .span12 {
226 | width: 100%;
227 | *width: 99.94680851063829%;
228 | }
229 | .row-fluid .span11 {
230 | width: 91.45299145299145%;
231 | *width: 91.39979996362975%;
232 | }
233 | .row-fluid .span10 {
234 | width: 82.90598290598291%;
235 | *width: 82.8527914166212%;
236 | }
237 | .row-fluid .span9 {
238 | width: 74.35897435897436%;
239 | *width: 74.30578286961266%;
240 | }
241 | .row-fluid .span8 {
242 | width: 65.81196581196582%;
243 | *width: 65.75877432260411%;
244 | }
245 | .row-fluid .span7 {
246 | width: 57.26495726495726%;
247 | *width: 57.21176577559556%;
248 | }
249 | .row-fluid .span6 {
250 | width: 48.717948717948715%;
251 | *width: 48.664757228587014%;
252 | }
253 | .row-fluid .span5 {
254 | width: 40.17094017094017%;
255 | *width: 40.11774868157847%;
256 | }
257 | .row-fluid .span4 {
258 | width: 31.623931623931625%;
259 | *width: 31.570740134569924%;
260 | }
261 | .row-fluid .span3 {
262 | width: 23.076923076923077%;
263 | *width: 23.023731587561375%;
264 | }
265 | .row-fluid .span2 {
266 | width: 14.52991452991453%;
267 | *width: 14.476723040552828%;
268 | }
269 | .row-fluid .span1 {
270 | width: 5.982905982905983%;
271 | *width: 5.929714493544281%;
272 | }
273 | .row-fluid .offset12 {
274 | margin-left: 105.12820512820512%;
275 | *margin-left: 105.02182214948171%;
276 | }
277 | .row-fluid .offset12:first-child {
278 | margin-left: 102.56410256410257%;
279 | *margin-left: 102.45771958537915%;
280 | }
281 | .row-fluid .offset11 {
282 | margin-left: 96.58119658119658%;
283 | *margin-left: 96.47481360247316%;
284 | }
285 | .row-fluid .offset11:first-child {
286 | margin-left: 94.01709401709402%;
287 | *margin-left: 93.91071103837061%;
288 | }
289 | .row-fluid .offset10 {
290 | margin-left: 88.03418803418803%;
291 | *margin-left: 87.92780505546462%;
292 | }
293 | .row-fluid .offset10:first-child {
294 | margin-left: 85.47008547008548%;
295 | *margin-left: 85.36370249136206%;
296 | }
297 | .row-fluid .offset9 {
298 | margin-left: 79.48717948717949%;
299 | *margin-left: 79.38079650845607%;
300 | }
301 | .row-fluid .offset9:first-child {
302 | margin-left: 76.92307692307693%;
303 | *margin-left: 76.81669394435352%;
304 | }
305 | .row-fluid .offset8 {
306 | margin-left: 70.94017094017094%;
307 | *margin-left: 70.83378796144753%;
308 | }
309 | .row-fluid .offset8:first-child {
310 | margin-left: 68.37606837606839%;
311 | *margin-left: 68.26968539734497%;
312 | }
313 | .row-fluid .offset7 {
314 | margin-left: 62.393162393162385%;
315 | *margin-left: 62.28677941443899%;
316 | }
317 | .row-fluid .offset7:first-child {
318 | margin-left: 59.82905982905982%;
319 | *margin-left: 59.72267685033642%;
320 | }
321 | .row-fluid .offset6 {
322 | margin-left: 53.84615384615384%;
323 | *margin-left: 53.739770867430444%;
324 | }
325 | .row-fluid .offset6:first-child {
326 | margin-left: 51.28205128205128%;
327 | *margin-left: 51.175668303327875%;
328 | }
329 | .row-fluid .offset5 {
330 | margin-left: 45.299145299145295%;
331 | *margin-left: 45.1927623204219%;
332 | }
333 | .row-fluid .offset5:first-child {
334 | margin-left: 42.73504273504273%;
335 | *margin-left: 42.62865975631933%;
336 | }
337 | .row-fluid .offset4 {
338 | margin-left: 36.75213675213675%;
339 | *margin-left: 36.645753773413354%;
340 | }
341 | .row-fluid .offset4:first-child {
342 | margin-left: 34.18803418803419%;
343 | *margin-left: 34.081651209310785%;
344 | }
345 | .row-fluid .offset3 {
346 | margin-left: 28.205128205128204%;
347 | *margin-left: 28.0987452264048%;
348 | }
349 | .row-fluid .offset3:first-child {
350 | margin-left: 25.641025641025642%;
351 | *margin-left: 25.53464266230224%;
352 | }
353 | .row-fluid .offset2 {
354 | margin-left: 19.65811965811966%;
355 | *margin-left: 19.551736679396257%;
356 | }
357 | .row-fluid .offset2:first-child {
358 | margin-left: 17.094017094017094%;
359 | *margin-left: 16.98763411529369%;
360 | }
361 | .row-fluid .offset1 {
362 | margin-left: 11.11111111111111%;
363 | *margin-left: 11.004728132387708%;
364 | }
365 | .row-fluid .offset1:first-child {
366 | margin-left: 8.547008547008547%;
367 | *margin-left: 8.440625568285142%;
368 | }
369 | input,
370 | textarea,
371 | .uneditable-input {
372 | margin-left: 0;
373 | }
374 | .controls-row [class*="span"] + [class*="span"] {
375 | margin-left: 30px;
376 | }
377 | input.span12,
378 | textarea.span12,
379 | .uneditable-input.span12 {
380 | width: 1156px;
381 | }
382 | input.span11,
383 | textarea.span11,
384 | .uneditable-input.span11 {
385 | width: 1056px;
386 | }
387 | input.span10,
388 | textarea.span10,
389 | .uneditable-input.span10 {
390 | width: 956px;
391 | }
392 | input.span9,
393 | textarea.span9,
394 | .uneditable-input.span9 {
395 | width: 856px;
396 | }
397 | input.span8,
398 | textarea.span8,
399 | .uneditable-input.span8 {
400 | width: 756px;
401 | }
402 | input.span7,
403 | textarea.span7,
404 | .uneditable-input.span7 {
405 | width: 656px;
406 | }
407 | input.span6,
408 | textarea.span6,
409 | .uneditable-input.span6 {
410 | width: 556px;
411 | }
412 | input.span5,
413 | textarea.span5,
414 | .uneditable-input.span5 {
415 | width: 456px;
416 | }
417 | input.span4,
418 | textarea.span4,
419 | .uneditable-input.span4 {
420 | width: 356px;
421 | }
422 | input.span3,
423 | textarea.span3,
424 | .uneditable-input.span3 {
425 | width: 256px;
426 | }
427 | input.span2,
428 | textarea.span2,
429 | .uneditable-input.span2 {
430 | width: 156px;
431 | }
432 | input.span1,
433 | textarea.span1,
434 | .uneditable-input.span1 {
435 | width: 56px;
436 | }
437 | .thumbnails {
438 | margin-left: -30px;
439 | }
440 | .thumbnails > li {
441 | margin-left: 30px;
442 | }
443 | .row-fluid .thumbnails {
444 | margin-left: 0;
445 | }
446 | }
447 |
448 | @media (min-width: 768px) and (max-width: 979px) {
449 | .row {
450 | margin-left: -20px;
451 | *zoom: 1;
452 | }
453 | .row:before,
454 | .row:after {
455 | display: table;
456 | line-height: 0;
457 | content: "";
458 | }
459 | .row:after {
460 | clear: both;
461 | }
462 | [class*="span"] {
463 | float: left;
464 | min-height: 1px;
465 | margin-left: 20px;
466 | }
467 | .container,
468 | .navbar-static-top .container,
469 | .navbar-fixed-top .container,
470 | .navbar-fixed-bottom .container {
471 | width: 724px;
472 | }
473 | .span12 {
474 | width: 724px;
475 | }
476 | .span11 {
477 | width: 662px;
478 | }
479 | .span10 {
480 | width: 600px;
481 | }
482 | .span9 {
483 | width: 538px;
484 | }
485 | .span8 {
486 | width: 476px;
487 | }
488 | .span7 {
489 | width: 414px;
490 | }
491 | .span6 {
492 | width: 352px;
493 | }
494 | .span5 {
495 | width: 290px;
496 | }
497 | .span4 {
498 | width: 228px;
499 | }
500 | .span3 {
501 | width: 166px;
502 | }
503 | .span2 {
504 | width: 104px;
505 | }
506 | .span1 {
507 | width: 42px;
508 | }
509 | .offset12 {
510 | margin-left: 764px;
511 | }
512 | .offset11 {
513 | margin-left: 702px;
514 | }
515 | .offset10 {
516 | margin-left: 640px;
517 | }
518 | .offset9 {
519 | margin-left: 578px;
520 | }
521 | .offset8 {
522 | margin-left: 516px;
523 | }
524 | .offset7 {
525 | margin-left: 454px;
526 | }
527 | .offset6 {
528 | margin-left: 392px;
529 | }
530 | .offset5 {
531 | margin-left: 330px;
532 | }
533 | .offset4 {
534 | margin-left: 268px;
535 | }
536 | .offset3 {
537 | margin-left: 206px;
538 | }
539 | .offset2 {
540 | margin-left: 144px;
541 | }
542 | .offset1 {
543 | margin-left: 82px;
544 | }
545 | .row-fluid {
546 | width: 100%;
547 | *zoom: 1;
548 | }
549 | .row-fluid:before,
550 | .row-fluid:after {
551 | display: table;
552 | line-height: 0;
553 | content: "";
554 | }
555 | .row-fluid:after {
556 | clear: both;
557 | }
558 | .row-fluid [class*="span"] {
559 | display: block;
560 | float: left;
561 | width: 100%;
562 | min-height: 30px;
563 | margin-left: 2.7624309392265194%;
564 | *margin-left: 2.709239449864817%;
565 | -webkit-box-sizing: border-box;
566 | -moz-box-sizing: border-box;
567 | box-sizing: border-box;
568 | }
569 | .row-fluid [class*="span"]:first-child {
570 | margin-left: 0;
571 | }
572 | .row-fluid .controls-row [class*="span"] + [class*="span"] {
573 | margin-left: 2.7624309392265194%;
574 | }
575 | .row-fluid .span12 {
576 | width: 100%;
577 | *width: 99.94680851063829%;
578 | }
579 | .row-fluid .span11 {
580 | width: 91.43646408839778%;
581 | *width: 91.38327259903608%;
582 | }
583 | .row-fluid .span10 {
584 | width: 82.87292817679558%;
585 | *width: 82.81973668743387%;
586 | }
587 | .row-fluid .span9 {
588 | width: 74.30939226519337%;
589 | *width: 74.25620077583166%;
590 | }
591 | .row-fluid .span8 {
592 | width: 65.74585635359117%;
593 | *width: 65.69266486422946%;
594 | }
595 | .row-fluid .span7 {
596 | width: 57.18232044198895%;
597 | *width: 57.12912895262725%;
598 | }
599 | .row-fluid .span6 {
600 | width: 48.61878453038674%;
601 | *width: 48.56559304102504%;
602 | }
603 | .row-fluid .span5 {
604 | width: 40.05524861878453%;
605 | *width: 40.00205712942283%;
606 | }
607 | .row-fluid .span4 {
608 | width: 31.491712707182323%;
609 | *width: 31.43852121782062%;
610 | }
611 | .row-fluid .span3 {
612 | width: 22.92817679558011%;
613 | *width: 22.87498530621841%;
614 | }
615 | .row-fluid .span2 {
616 | width: 14.3646408839779%;
617 | *width: 14.311449394616199%;
618 | }
619 | .row-fluid .span1 {
620 | width: 5.801104972375691%;
621 | *width: 5.747913483013988%;
622 | }
623 | .row-fluid .offset12 {
624 | margin-left: 105.52486187845304%;
625 | *margin-left: 105.41847889972962%;
626 | }
627 | .row-fluid .offset12:first-child {
628 | margin-left: 102.76243093922652%;
629 | *margin-left: 102.6560479605031%;
630 | }
631 | .row-fluid .offset11 {
632 | margin-left: 96.96132596685082%;
633 | *margin-left: 96.8549429881274%;
634 | }
635 | .row-fluid .offset11:first-child {
636 | margin-left: 94.1988950276243%;
637 | *margin-left: 94.09251204890089%;
638 | }
639 | .row-fluid .offset10 {
640 | margin-left: 88.39779005524862%;
641 | *margin-left: 88.2914070765252%;
642 | }
643 | .row-fluid .offset10:first-child {
644 | margin-left: 85.6353591160221%;
645 | *margin-left: 85.52897613729868%;
646 | }
647 | .row-fluid .offset9 {
648 | margin-left: 79.8342541436464%;
649 | *margin-left: 79.72787116492299%;
650 | }
651 | .row-fluid .offset9:first-child {
652 | margin-left: 77.07182320441989%;
653 | *margin-left: 76.96544022569647%;
654 | }
655 | .row-fluid .offset8 {
656 | margin-left: 71.2707182320442%;
657 | *margin-left: 71.16433525332079%;
658 | }
659 | .row-fluid .offset8:first-child {
660 | margin-left: 68.50828729281768%;
661 | *margin-left: 68.40190431409427%;
662 | }
663 | .row-fluid .offset7 {
664 | margin-left: 62.70718232044199%;
665 | *margin-left: 62.600799341718584%;
666 | }
667 | .row-fluid .offset7:first-child {
668 | margin-left: 59.94475138121547%;
669 | *margin-left: 59.838368402492065%;
670 | }
671 | .row-fluid .offset6 {
672 | margin-left: 54.14364640883978%;
673 | *margin-left: 54.037263430116376%;
674 | }
675 | .row-fluid .offset6:first-child {
676 | margin-left: 51.38121546961326%;
677 | *margin-left: 51.27483249088986%;
678 | }
679 | .row-fluid .offset5 {
680 | margin-left: 45.58011049723757%;
681 | *margin-left: 45.47372751851417%;
682 | }
683 | .row-fluid .offset5:first-child {
684 | margin-left: 42.81767955801105%;
685 | *margin-left: 42.71129657928765%;
686 | }
687 | .row-fluid .offset4 {
688 | margin-left: 37.01657458563536%;
689 | *margin-left: 36.91019160691196%;
690 | }
691 | .row-fluid .offset4:first-child {
692 | margin-left: 34.25414364640884%;
693 | *margin-left: 34.14776066768544%;
694 | }
695 | .row-fluid .offset3 {
696 | margin-left: 28.45303867403315%;
697 | *margin-left: 28.346655695309746%;
698 | }
699 | .row-fluid .offset3:first-child {
700 | margin-left: 25.69060773480663%;
701 | *margin-left: 25.584224756083227%;
702 | }
703 | .row-fluid .offset2 {
704 | margin-left: 19.88950276243094%;
705 | *margin-left: 19.783119783707537%;
706 | }
707 | .row-fluid .offset2:first-child {
708 | margin-left: 17.12707182320442%;
709 | *margin-left: 17.02068884448102%;
710 | }
711 | .row-fluid .offset1 {
712 | margin-left: 11.32596685082873%;
713 | *margin-left: 11.219583872105325%;
714 | }
715 | .row-fluid .offset1:first-child {
716 | margin-left: 8.56353591160221%;
717 | *margin-left: 8.457152932878806%;
718 | }
719 | input,
720 | textarea,
721 | .uneditable-input {
722 | margin-left: 0;
723 | }
724 | .controls-row [class*="span"] + [class*="span"] {
725 | margin-left: 20px;
726 | }
727 | input.span12,
728 | textarea.span12,
729 | .uneditable-input.span12 {
730 | width: 710px;
731 | }
732 | input.span11,
733 | textarea.span11,
734 | .uneditable-input.span11 {
735 | width: 648px;
736 | }
737 | input.span10,
738 | textarea.span10,
739 | .uneditable-input.span10 {
740 | width: 586px;
741 | }
742 | input.span9,
743 | textarea.span9,
744 | .uneditable-input.span9 {
745 | width: 524px;
746 | }
747 | input.span8,
748 | textarea.span8,
749 | .uneditable-input.span8 {
750 | width: 462px;
751 | }
752 | input.span7,
753 | textarea.span7,
754 | .uneditable-input.span7 {
755 | width: 400px;
756 | }
757 | input.span6,
758 | textarea.span6,
759 | .uneditable-input.span6 {
760 | width: 338px;
761 | }
762 | input.span5,
763 | textarea.span5,
764 | .uneditable-input.span5 {
765 | width: 276px;
766 | }
767 | input.span4,
768 | textarea.span4,
769 | .uneditable-input.span4 {
770 | width: 214px;
771 | }
772 | input.span3,
773 | textarea.span3,
774 | .uneditable-input.span3 {
775 | width: 152px;
776 | }
777 | input.span2,
778 | textarea.span2,
779 | .uneditable-input.span2 {
780 | width: 90px;
781 | }
782 | input.span1,
783 | textarea.span1,
784 | .uneditable-input.span1 {
785 | width: 28px;
786 | }
787 | }
788 |
789 | @media (max-width: 767px) {
790 | body {
791 | padding-right: 20px;
792 | padding-left: 20px;
793 | }
794 | .navbar-fixed-top,
795 | .navbar-fixed-bottom,
796 | .navbar-static-top {
797 | margin-right: -20px;
798 | margin-left: -20px;
799 | }
800 | .container-fluid {
801 | padding: 0;
802 | }
803 | .dl-horizontal dt {
804 | float: none;
805 | width: auto;
806 | clear: none;
807 | text-align: left;
808 | }
809 | .dl-horizontal dd {
810 | margin-left: 0;
811 | }
812 | .container {
813 | width: auto;
814 | }
815 | .row-fluid {
816 | width: 100%;
817 | }
818 | .row,
819 | .thumbnails {
820 | margin-left: 0;
821 | }
822 | .thumbnails > li {
823 | float: none;
824 | margin-left: 0;
825 | }
826 | [class*="span"],
827 | .uneditable-input[class*="span"],
828 | .row-fluid [class*="span"] {
829 | display: block;
830 | float: none;
831 | width: 100%;
832 | margin-left: 0;
833 | -webkit-box-sizing: border-box;
834 | -moz-box-sizing: border-box;
835 | box-sizing: border-box;
836 | }
837 | .span12,
838 | .row-fluid .span12 {
839 | width: 100%;
840 | -webkit-box-sizing: border-box;
841 | -moz-box-sizing: border-box;
842 | box-sizing: border-box;
843 | }
844 | .row-fluid [class*="offset"]:first-child {
845 | margin-left: 0;
846 | }
847 | .input-large,
848 | .input-xlarge,
849 | .input-xxlarge,
850 | input[class*="span"],
851 | select[class*="span"],
852 | textarea[class*="span"],
853 | .uneditable-input {
854 | display: block;
855 | width: 100%;
856 | min-height: 30px;
857 | -webkit-box-sizing: border-box;
858 | -moz-box-sizing: border-box;
859 | box-sizing: border-box;
860 | }
861 | .input-prepend input,
862 | .input-append input,
863 | .input-prepend input[class*="span"],
864 | .input-append input[class*="span"] {
865 | display: inline-block;
866 | width: auto;
867 | }
868 | .controls-row [class*="span"] + [class*="span"] {
869 | margin-left: 0;
870 | }
871 | .modal {
872 | position: fixed;
873 | top: 20px;
874 | right: 20px;
875 | left: 20px;
876 | width: auto;
877 | margin: 0;
878 | }
879 | .modal.fade {
880 | top: -100px;
881 | }
882 | .modal.fade.in {
883 | top: 20px;
884 | }
885 | }
886 |
887 | @media (max-width: 480px) {
888 | .nav-collapse {
889 | -webkit-transform: translate3d(0, 0, 0);
890 | }
891 | .page-header h1 small {
892 | display: block;
893 | line-height: 20px;
894 | }
895 | input[type="checkbox"],
896 | input[type="radio"] {
897 | border: 1px solid #ccc;
898 | }
899 | .form-horizontal .control-label {
900 | float: none;
901 | width: auto;
902 | padding-top: 0;
903 | text-align: left;
904 | }
905 | .form-horizontal .controls {
906 | margin-left: 0;
907 | }
908 | .form-horizontal .control-list {
909 | padding-top: 0;
910 | }
911 | .form-horizontal .form-actions {
912 | padding-right: 10px;
913 | padding-left: 10px;
914 | }
915 | .media .pull-left,
916 | .media .pull-right {
917 | display: block;
918 | float: none;
919 | margin-bottom: 10px;
920 | }
921 | .media-object {
922 | margin-right: 0;
923 | margin-left: 0;
924 | }
925 | .modal {
926 | top: 10px;
927 | right: 10px;
928 | left: 10px;
929 | }
930 | .modal-header .close {
931 | padding: 10px;
932 | margin: -10px;
933 | }
934 | .carousel-caption {
935 | position: static;
936 | }
937 | }
938 |
939 | @media (max-width: 979px) {
940 | body {
941 | padding-top: 0;
942 | }
943 | .navbar-fixed-top,
944 | .navbar-fixed-bottom {
945 | position: static;
946 | }
947 | .navbar-fixed-top {
948 | margin-bottom: 20px;
949 | }
950 | .navbar-fixed-bottom {
951 | margin-top: 20px;
952 | }
953 | .navbar-fixed-top .navbar-inner,
954 | .navbar-fixed-bottom .navbar-inner {
955 | padding: 5px;
956 | }
957 | .navbar .container {
958 | width: auto;
959 | padding: 0;
960 | }
961 | .navbar .brand {
962 | padding-right: 10px;
963 | padding-left: 10px;
964 | margin: 0 0 0 -5px;
965 | }
966 | .nav-collapse {
967 | clear: both;
968 | }
969 | .nav-collapse .nav {
970 | float: none;
971 | margin: 0 0 10px;
972 | }
973 | .nav-collapse .nav > li {
974 | float: none;
975 | }
976 | .nav-collapse .nav > li > a {
977 | margin-bottom: 2px;
978 | }
979 | .nav-collapse .nav > .divider-vertical {
980 | display: none;
981 | }
982 | .nav-collapse .nav .nav-header {
983 | color: #777777;
984 | text-shadow: none;
985 | }
986 | .nav-collapse .nav > li > a,
987 | .nav-collapse .dropdown-menu a {
988 | padding: 9px 15px;
989 | font-weight: bold;
990 | color: #777777;
991 | -webkit-border-radius: 3px;
992 | -moz-border-radius: 3px;
993 | border-radius: 3px;
994 | }
995 | .nav-collapse .btn {
996 | padding: 4px 10px 4px;
997 | font-weight: normal;
998 | -webkit-border-radius: 4px;
999 | -moz-border-radius: 4px;
1000 | border-radius: 4px;
1001 | }
1002 | .nav-collapse .dropdown-menu li + li a {
1003 | margin-bottom: 2px;
1004 | }
1005 | .nav-collapse .nav > li > a:hover,
1006 | .nav-collapse .dropdown-menu a:hover {
1007 | background-color: #f2f2f2;
1008 | }
1009 | .navbar-inverse .nav-collapse .nav > li > a,
1010 | .navbar-inverse .nav-collapse .dropdown-menu a {
1011 | color: #999999;
1012 | }
1013 | .navbar-inverse .nav-collapse .nav > li > a:hover,
1014 | .navbar-inverse .nav-collapse .dropdown-menu a:hover {
1015 | background-color: #111111;
1016 | }
1017 | .nav-collapse.in .btn-group {
1018 | padding: 0;
1019 | margin-top: 5px;
1020 | }
1021 | .nav-collapse .dropdown-menu {
1022 | position: static;
1023 | top: auto;
1024 | left: auto;
1025 | display: none;
1026 | float: none;
1027 | max-width: none;
1028 | padding: 0;
1029 | margin: 0 15px;
1030 | background-color: transparent;
1031 | border: none;
1032 | -webkit-border-radius: 0;
1033 | -moz-border-radius: 0;
1034 | border-radius: 0;
1035 | -webkit-box-shadow: none;
1036 | -moz-box-shadow: none;
1037 | box-shadow: none;
1038 | }
1039 | .nav-collapse .open > .dropdown-menu {
1040 | display: block;
1041 | }
1042 | .nav-collapse .dropdown-menu:before,
1043 | .nav-collapse .dropdown-menu:after {
1044 | display: none;
1045 | }
1046 | .nav-collapse .dropdown-menu .divider {
1047 | display: none;
1048 | }
1049 | .nav-collapse .nav > li > .dropdown-menu:before,
1050 | .nav-collapse .nav > li > .dropdown-menu:after {
1051 | display: none;
1052 | }
1053 | .nav-collapse .navbar-form,
1054 | .nav-collapse .navbar-search {
1055 | float: none;
1056 | padding: 10px 15px;
1057 | margin: 10px 0;
1058 | border-top: 1px solid #f2f2f2;
1059 | border-bottom: 1px solid #f2f2f2;
1060 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
1061 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
1062 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
1063 | }
1064 | .navbar-inverse .nav-collapse .navbar-form,
1065 | .navbar-inverse .nav-collapse .navbar-search {
1066 | border-top-color: #111111;
1067 | border-bottom-color: #111111;
1068 | }
1069 | .navbar .nav-collapse .nav.pull-right {
1070 | float: none;
1071 | margin-left: 0;
1072 | }
1073 | .nav-collapse,
1074 | .nav-collapse.collapse {
1075 | height: 0;
1076 | overflow: hidden;
1077 | }
1078 | .navbar .btn-navbar {
1079 | display: block;
1080 | }
1081 | .navbar-static .navbar-inner {
1082 | padding-right: 10px;
1083 | padding-left: 10px;
1084 | }
1085 | }
1086 |
1087 | @media (min-width: 980px) {
1088 | .nav-collapse.collapse {
1089 | height: auto !important;
1090 | overflow: visible !important;
1091 | }
1092 | }
1093 |
--------------------------------------------------------------------------------
/js/bootstrap.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap.js by @fat & @mdo
3 | * Copyright 2012 Twitter, Inc.
4 | * http://www.apache.org/licenses/LICENSE-2.0.txt
5 | */
6 | !function($){"use strict";$(function(){$.support.transition=function(){var transitionEnd=function(){var name,el=document.createElement("bootstrap"),transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(name in transEndEventNames)if(void 0!==el.style[name])return transEndEventNames[name]}();return transitionEnd&&{end:transitionEnd}}()})}(window.jQuery),!function($){"use strict";var dismiss='[data-dismiss="alert"]',Alert=function(el){$(el).on("click",dismiss,this.close)};Alert.prototype.close=function(e){function removeElement(){$parent.trigger("closed").remove()}var $parent,$this=$(this),selector=$this.attr("data-target");selector||(selector=$this.attr("href"),selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),e&&e.preventDefault(),$parent.length||($parent=$this.hasClass("alert")?$this:$this.parent()),$parent.trigger(e=$.Event("close")),e.isDefaultPrevented()||($parent.removeClass("in"),$.support.transition&&$parent.hasClass("fade")?$parent.on($.support.transition.end,removeElement):removeElement())};var old=$.fn.alert;$.fn.alert=function(option){return this.each(function(){var $this=$(this),data=$this.data("alert");data||$this.data("alert",data=new Alert(this)),"string"==typeof option&&data[option].call($this)})},$.fn.alert.Constructor=Alert,$.fn.alert.noConflict=function(){return $.fn.alert=old,this},$(document).on("click.alert.data-api",dismiss,Alert.prototype.close)}(window.jQuery),!function($){"use strict";var Button=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.button.defaults,options)};Button.prototype.setState=function(state){var d="disabled",$el=this.$element,data=$el.data(),val=$el.is("input")?"val":"html";state+="Text",data.resetText||$el.data("resetText",$el[val]()),$el[val](data[state]||this.options[state]),setTimeout(function(){"loadingText"==state?$el.addClass(d).attr(d,d):$el.removeClass(d).removeAttr(d)},0)},Button.prototype.toggle=function(){var $parent=this.$element.closest('[data-toggle="buttons-radio"]');$parent&&$parent.find(".active").removeClass("active"),this.$element.toggleClass("active")};var old=$.fn.button;$.fn.button=function(option){return this.each(function(){var $this=$(this),data=$this.data("button"),options="object"==typeof option&&option;data||$this.data("button",data=new Button(this,options)),"toggle"==option?data.toggle():option&&data.setState(option)})},$.fn.button.defaults={loadingText:"loading..."},$.fn.button.Constructor=Button,$.fn.button.noConflict=function(){return $.fn.button=old,this},$(document).on("click.button.data-api","[data-toggle^=button]",function(e){var $btn=$(e.target);$btn.hasClass("btn")||($btn=$btn.closest(".btn")),$btn.button("toggle")})}(window.jQuery),!function($){"use strict";var Carousel=function(element,options){this.$element=$(element),this.options=options,"hover"==this.options.pause&&this.$element.on("mouseenter",$.proxy(this.pause,this)).on("mouseleave",$.proxy(this.cycle,this))};Carousel.prototype={cycle:function(e){return e||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval)),this},to:function(pos){var $active=this.$element.find(".item.active"),children=$active.parent().children(),activePos=children.index($active),that=this;if(!(pos>children.length-1||0>pos))return this.sliding?this.$element.one("slid",function(){that.to(pos)}):activePos==pos?this.pause().cycle():this.slide(pos>activePos?"next":"prev",$(children[pos]))},pause:function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&$.support.transition.end&&(this.$element.trigger($.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){return this.sliding?void 0:this.slide("next")},prev:function(){return this.sliding?void 0:this.slide("prev")},slide:function(type,next){var e,$active=this.$element.find(".item.active"),$next=next||$active[type](),isCycling=this.interval,direction="next"==type?"left":"right",fallback="next"==type?"first":"last",that=this;if(this.sliding=!0,isCycling&&this.pause(),$next=$next.length?$next:this.$element.find(".item")[fallback](),e=$.Event("slide",{relatedTarget:$next[0]}),!$next.hasClass("active")){if($.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(e),e.isDefaultPrevented())return;$next.addClass(type),$next[0].offsetWidth,$active.addClass(direction),$next.addClass(direction),this.$element.one($.support.transition.end,function(){$next.removeClass([type,direction].join(" ")).addClass("active"),$active.removeClass(["active",direction].join(" ")),that.sliding=!1,setTimeout(function(){that.$element.trigger("slid")},0)})}else{if(this.$element.trigger(e),e.isDefaultPrevented())return;$active.removeClass("active"),$next.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return isCycling&&this.cycle(),this}}};var old=$.fn.carousel;$.fn.carousel=function(option){return this.each(function(){var $this=$(this),data=$this.data("carousel"),options=$.extend({},$.fn.carousel.defaults,"object"==typeof option&&option),action="string"==typeof option?option:options.slide;data||$this.data("carousel",data=new Carousel(this,options)),"number"==typeof option?data.to(option):action?data[action]():options.interval&&data.cycle()})},$.fn.carousel.defaults={interval:5e3,pause:"hover"},$.fn.carousel.Constructor=Carousel,$.fn.carousel.noConflict=function(){return $.fn.carousel=old,this},$(document).on("click.carousel.data-api","[data-slide]",function(e){var href,$this=$(this),$target=$($this.attr("data-target")||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")),options=$.extend({},$target.data(),$this.data());$target.carousel(options),e.preventDefault()})}(window.jQuery),!function($){"use strict";var Collapse=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.collapse.defaults,options),this.options.parent&&(this.$parent=$(this.options.parent)),this.options.toggle&&this.toggle()};Collapse.prototype={constructor:Collapse,dimension:function(){var hasWidth=this.$element.hasClass("width");return hasWidth?"width":"height"},show:function(){var dimension,scroll,actives,hasData;if(!this.transitioning){if(dimension=this.dimension(),scroll=$.camelCase(["scroll",dimension].join("-")),actives=this.$parent&&this.$parent.find("> .accordion-group > .in"),actives&&actives.length){if(hasData=actives.data("collapse"),hasData&&hasData.transitioning)return;actives.collapse("hide"),hasData||actives.data("collapse",null)}this.$element[dimension](0),this.transition("addClass",$.Event("show"),"shown"),$.support.transition&&this.$element[dimension](this.$element[0][scroll])}},hide:function(){var dimension;this.transitioning||(dimension=this.dimension(),this.reset(this.$element[dimension]()),this.transition("removeClass",$.Event("hide"),"hidden"),this.$element[dimension](0))},reset:function(size){var dimension=this.dimension();return this.$element.removeClass("collapse")[dimension](size||"auto")[0].offsetWidth,this.$element[null!==size?"addClass":"removeClass"]("collapse"),this},transition:function(method,startEvent,completeEvent){var that=this,complete=function(){"show"==startEvent.type&&that.reset(),that.transitioning=0,that.$element.trigger(completeEvent)};this.$element.trigger(startEvent),startEvent.isDefaultPrevented()||(this.transitioning=1,this.$element[method]("in"),$.support.transition&&this.$element.hasClass("collapse")?this.$element.one($.support.transition.end,complete):complete())},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var old=$.fn.collapse;$.fn.collapse=function(option){return this.each(function(){var $this=$(this),data=$this.data("collapse"),options="object"==typeof option&&option;data||$this.data("collapse",data=new Collapse(this,options)),"string"==typeof option&&data[option]()})},$.fn.collapse.defaults={toggle:!0},$.fn.collapse.Constructor=Collapse,$.fn.collapse.noConflict=function(){return $.fn.collapse=old,this},$(document).on("click.collapse.data-api","[data-toggle=collapse]",function(e){var href,$this=$(this),target=$this.attr("data-target")||e.preventDefault()||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),option=$(target).data("collapse")?"toggle":$this.data();$this[$(target).hasClass("in")?"addClass":"removeClass"]("collapsed"),$(target).collapse(option)})}(window.jQuery),!function($){"use strict";function clearMenus(){$(toggle).each(function(){getParent($(this)).removeClass("open")})}function getParent($this){var $parent,selector=$this.attr("data-target");return selector||(selector=$this.attr("href"),selector=selector&&/#/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),$parent.length||($parent=$this.parent()),$parent}var toggle="[data-toggle=dropdown]",Dropdown=function(element){var $el=$(element).on("click.dropdown.data-api",this.toggle);$("html").on("click.dropdown.data-api",function(){$el.parent().removeClass("open")})};Dropdown.prototype={constructor:Dropdown,toggle:function(){var $parent,isActive,$this=$(this);if(!$this.is(".disabled, :disabled"))return $parent=getParent($this),isActive=$parent.hasClass("open"),clearMenus(),isActive||$parent.toggleClass("open"),$this.focus(),!1},keydown:function(e){var $this,$items,$parent,isActive,index;if(/(38|40|27)/.test(e.keyCode)&&($this=$(this),e.preventDefault(),e.stopPropagation(),!$this.is(".disabled, :disabled"))){if($parent=getParent($this),isActive=$parent.hasClass("open"),!isActive||isActive&&27==e.keyCode)return $this.click();$items=$("[role=menu] li:not(.divider):visible a",$parent),$items.length&&(index=$items.index($items.filter(":focus")),38==e.keyCode&&index>0&&index--,40==e.keyCode&&$items.length-1>index&&index++,~index||(index=0),$items.eq(index).focus())}}};var old=$.fn.dropdown;$.fn.dropdown=function(option){return this.each(function(){var $this=$(this),data=$this.data("dropdown");data||$this.data("dropdown",data=new Dropdown(this)),"string"==typeof option&&data[option].call($this)})},$.fn.dropdown.Constructor=Dropdown,$.fn.dropdown.noConflict=function(){return $.fn.dropdown=old,this},$(document).on("click.dropdown.data-api touchstart.dropdown.data-api",clearMenus).on("click.dropdown touchstart.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("touchstart.dropdown.data-api",".dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api touchstart.dropdown.data-api",toggle,Dropdown.prototype.toggle).on("keydown.dropdown.data-api touchstart.dropdown.data-api",toggle+", [role=menu]",Dropdown.prototype.keydown)}(window.jQuery),!function($){"use strict";var Modal=function(element,options){this.options=options,this.$element=$(element).delegate('[data-dismiss="modal"]',"click.dismiss.modal",$.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};Modal.prototype={constructor:Modal,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var that=this,e=$.Event("show");this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass("fade");that.$element.parent().length||that.$element.appendTo(document.body),that.$element.show(),transition&&that.$element[0].offsetWidth,that.$element.addClass("in").attr("aria-hidden",!1),that.enforceFocus(),transition?that.$element.one($.support.transition.end,function(){that.$element.focus().trigger("shown")}):that.$element.focus().trigger("shown")}))},hide:function(e){e&&e.preventDefault(),e=$.Event("hide"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,this.escape(),$(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),$.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal())},enforceFocus:function(){var that=this;$(document).on("focusin.modal",function(e){that.$element[0]===e.target||that.$element.has(e.target).length||that.$element.focus()})},escape:function(){var that=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(e){27==e.which&&that.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var that=this,timeout=setTimeout(function(){that.$element.off($.support.transition.end),that.hideModal()},500);this.$element.one($.support.transition.end,function(){clearTimeout(timeout),that.hideModal()})},hideModal:function(){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(callback){var animate=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate;this.$backdrop=$('').appendTo(document.body),this.$backdrop.click("static"==this.options.backdrop?$.proxy(this.$element[0].focus,this.$element[0]):$.proxy(this.hide,this)),doAnimate&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),doAnimate?this.$backdrop.one($.support.transition.end,callback):callback()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),$.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one($.support.transition.end,$.proxy(this.removeBackdrop,this)):this.removeBackdrop()):callback&&callback()}};var old=$.fn.modal;$.fn.modal=function(option){return this.each(function(){var $this=$(this),data=$this.data("modal"),options=$.extend({},$.fn.modal.defaults,$this.data(),"object"==typeof option&&option);data||$this.data("modal",data=new Modal(this,options)),"string"==typeof option?data[option]():options.show&&data.show()})},$.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},$.fn.modal.Constructor=Modal,$.fn.modal.noConflict=function(){return $.fn.modal=old,this},$(document).on("click.modal.data-api",'[data-toggle="modal"]',function(e){var $this=$(this),href=$this.attr("href"),$target=$($this.attr("data-target")||href&&href.replace(/.*(?=#[^\s]+$)/,"")),option=$target.data("modal")?"toggle":$.extend({remote:!/#/.test(href)&&href},$target.data(),$this.data());e.preventDefault(),$target.modal(option).one("hide",function(){$this.focus()})})}(window.jQuery),!function($){"use strict";var Tooltip=function(element,options){this.init("tooltip",element,options)};Tooltip.prototype={constructor:Tooltip,init:function(type,element,options){var eventIn,eventOut;this.type=type,this.$element=$(element),this.options=this.getOptions(options),this.enabled=!0,"click"==this.options.trigger?this.$element.on("click."+this.type,this.options.selector,$.proxy(this.toggle,this)):"manual"!=this.options.trigger&&(eventIn="hover"==this.options.trigger?"mouseenter":"focus",eventOut="hover"==this.options.trigger?"mouseleave":"blur",this.$element.on(eventIn+"."+this.type,this.options.selector,$.proxy(this.enter,this)),this.$element.on(eventOut+"."+this.type,this.options.selector,$.proxy(this.leave,this))),this.options.selector?this._options=$.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(options){return options=$.extend({},$.fn[this.type].defaults,options,this.$element.data()),options.delay&&"number"==typeof options.delay&&(options.delay={show:options.delay,hide:options.delay}),options},enter:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);return self.options.delay&&self.options.delay.show?(clearTimeout(this.timeout),self.hoverState="in",this.timeout=setTimeout(function(){"in"==self.hoverState&&self.show()},self.options.delay.show),void 0):self.show()},leave:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);return this.timeout&&clearTimeout(this.timeout),self.options.delay&&self.options.delay.hide?(self.hoverState="out",this.timeout=setTimeout(function(){"out"==self.hoverState&&self.hide()},self.options.delay.hide),void 0):self.hide()},show:function(){var $tip,inside,pos,actualWidth,actualHeight,placement,tp;if(this.hasContent()&&this.enabled){switch($tip=this.tip(),this.setContent(),this.options.animation&&$tip.addClass("fade"),placement="function"==typeof this.options.placement?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement,inside=/in/.test(placement),$tip.detach().css({top:0,left:0,display:"block"}).insertAfter(this.$element),pos=this.getPosition(inside),actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight,inside?placement.split(" ")[1]:placement){case"bottom":tp={top:pos.top+pos.height,left:pos.left+pos.width/2-actualWidth/2};break;case"top":tp={top:pos.top-actualHeight,left:pos.left+pos.width/2-actualWidth/2};break;case"left":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth};break;case"right":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width}}$tip.offset(tp).addClass(placement).addClass("in")}},setContent:function(){var $tip=this.tip(),title=this.getTitle();$tip.find(".tooltip-inner")[this.options.html?"html":"text"](title),$tip.removeClass("fade in top bottom left right")},hide:function(){function removeWithAnimation(){var timeout=setTimeout(function(){$tip.off($.support.transition.end).detach()},500);$tip.one($.support.transition.end,function(){clearTimeout(timeout),$tip.detach()})}var $tip=this.tip();return $tip.removeClass("in"),$.support.transition&&this.$tip.hasClass("fade")?removeWithAnimation():$tip.detach(),this},fixTitle:function(){var $e=this.$element;($e.attr("title")||"string"!=typeof $e.attr("data-original-title"))&&$e.attr("data-original-title",$e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(inside){return $.extend({},inside?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var title,$e=this.$element,o=this.options;return title=$e.attr("data-original-title")||("function"==typeof o.title?o.title.call($e[0]):o.title)},tip:function(){return this.$tip=this.$tip||$(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);self[self.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var old=$.fn.tooltip;$.fn.tooltip=function(option){return this.each(function(){var $this=$(this),data=$this.data("tooltip"),options="object"==typeof option&&option;data||$this.data("tooltip",data=new Tooltip(this,options)),"string"==typeof option&&data[option]()})},$.fn.tooltip.Constructor=Tooltip,$.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover",title:"",delay:0,html:!1},$.fn.tooltip.noConflict=function(){return $.fn.tooltip=old,this}}(window.jQuery),!function($){"use strict";var Popover=function(element,options){this.init("popover",element,options)};Popover.prototype=$.extend({},$.fn.tooltip.Constructor.prototype,{constructor:Popover,setContent:function(){var $tip=this.tip(),title=this.getTitle(),content=this.getContent();$tip.find(".popover-title")[this.options.html?"html":"text"](title),$tip.find(".popover-content")[this.options.html?"html":"text"](content),$tip.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var content,$e=this.$element,o=this.options;return content=$e.attr("data-content")||("function"==typeof o.content?o.content.call($e[0]):o.content)},tip:function(){return this.$tip||(this.$tip=$(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var old=$.fn.popover;$.fn.popover=function(option){return this.each(function(){var $this=$(this),data=$this.data("popover"),options="object"==typeof option&&option;data||$this.data("popover",data=new Popover(this,options)),"string"==typeof option&&data[option]()})},$.fn.popover.Constructor=Popover,$.fn.popover.defaults=$.extend({},$.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:''}),$.fn.popover.noConflict=function(){return $.fn.popover=old,this}}(window.jQuery),!function($){"use strict";function ScrollSpy(element,options){var href,process=$.proxy(this.process,this),$element=$(element).is("body")?$(window):$(element);this.options=$.extend({},$.fn.scrollspy.defaults,options),this.$scrollElement=$element.on("scroll.scroll-spy.data-api",process),this.selector=(this.options.target||(href=$(element).attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=$("body"),this.refresh(),this.process()}ScrollSpy.prototype={constructor:ScrollSpy,refresh:function(){var $targets,self=this;this.offsets=$([]),this.targets=$([]),$targets=this.$body.find(this.selector).map(function(){var $el=$(this),href=$el.data("target")||$el.attr("href"),$href=/^#\w/.test(href)&&$(href);return $href&&$href.length&&[[$href.position().top+self.$scrollElement.scrollTop(),href]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){self.offsets.push(this[0]),self.targets.push(this[1])})},process:function(){var i,scrollTop=this.$scrollElement.scrollTop()+this.options.offset,scrollHeight=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,maxScroll=scrollHeight-this.$scrollElement.height(),offsets=this.offsets,targets=this.targets,activeTarget=this.activeTarget;if(scrollTop>=maxScroll)return activeTarget!=(i=targets.last()[0])&&this.activate(i);for(i=offsets.length;i--;)activeTarget!=targets[i]&&scrollTop>=offsets[i]&&(!offsets[i+1]||offsets[i+1]>=scrollTop)&&this.activate(targets[i])},activate:function(target){var active,selector;this.activeTarget=target,$(this.selector).parent(".active").removeClass("active"),selector=this.selector+'[data-target="'+target+'"],'+this.selector+'[href="'+target+'"]',active=$(selector).parent("li").addClass("active"),active.parent(".dropdown-menu").length&&(active=active.closest("li.dropdown").addClass("active")),active.trigger("activate")}};var old=$.fn.scrollspy;$.fn.scrollspy=function(option){return this.each(function(){var $this=$(this),data=$this.data("scrollspy"),options="object"==typeof option&&option;data||$this.data("scrollspy",data=new ScrollSpy(this,options)),"string"==typeof option&&data[option]()})},$.fn.scrollspy.Constructor=ScrollSpy,$.fn.scrollspy.defaults={offset:10},$.fn.scrollspy.noConflict=function(){return $.fn.scrollspy=old,this},$(window).on("load",function(){$('[data-spy="scroll"]').each(function(){var $spy=$(this);$spy.scrollspy($spy.data())})})}(window.jQuery),!function($){"use strict";var Tab=function(element){this.element=$(element)};Tab.prototype={constructor:Tab,show:function(){var previous,$target,e,$this=this.element,$ul=$this.closest("ul:not(.dropdown-menu)"),selector=$this.attr("data-target");selector||(selector=$this.attr("href"),selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")),$this.parent("li").hasClass("active")||(previous=$ul.find(".active:last a")[0],e=$.Event("show",{relatedTarget:previous}),$this.trigger(e),e.isDefaultPrevented()||($target=$(selector),this.activate($this.parent("li"),$ul),this.activate($target,$target.parent(),function(){$this.trigger({type:"shown",relatedTarget:previous})})))},activate:function(element,container,callback){function next(){$active.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),element.addClass("active"),transition?(element[0].offsetWidth,element.addClass("in")):element.removeClass("fade"),element.parent(".dropdown-menu")&&element.closest("li.dropdown").addClass("active"),callback&&callback()}var $active=container.find("> .active"),transition=callback&&$.support.transition&&$active.hasClass("fade");transition?$active.one($.support.transition.end,next):next(),$active.removeClass("in")}};var old=$.fn.tab;$.fn.tab=function(option){return this.each(function(){var $this=$(this),data=$this.data("tab");data||$this.data("tab",data=new Tab(this)),"string"==typeof option&&data[option]()})},$.fn.tab.Constructor=Tab,$.fn.tab.noConflict=function(){return $.fn.tab=old,this},$(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(e){e.preventDefault(),$(this).tab("show")})}(window.jQuery),!function($){"use strict";var Typeahead=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.typeahead.defaults,options),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=$(this.options.menu),this.shown=!1,this.listen()};Typeahead.prototype={constructor:Typeahead,select:function(){var val=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(val)).change(),this.hide()},updater:function(item){return item},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:pos.top+pos.height,left:pos.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(){var items;return this.query=this.$element.val(),!this.query||this.query.length"+match+""})},render:function(items){var that=this;return items=$(items).map(function(i,item){return i=$(that.options.item).attr("data-value",item),i.find("a").html(that.highlighter(item)),i[0]}),items.first().addClass("active"),this.$menu.html(items),this},next:function(){var active=this.$menu.find(".active").removeClass("active"),next=active.next();next.length||(next=$(this.$menu.find("li")[0])),next.addClass("active")},prev:function(){var active=this.$menu.find(".active").removeClass("active"),prev=active.prev();prev.length||(prev=this.$menu.find("li").last()),prev.addClass("active")},listen:function(){this.$element.on("blur",$.proxy(this.blur,this)).on("keypress",$.proxy(this.keypress,this)).on("keyup",$.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",$.proxy(this.keydown,this)),this.$menu.on("click",$.proxy(this.click,this)).on("mouseenter","li",$.proxy(this.mouseenter,this))},eventSupported:function(eventName){var isSupported=eventName in this.$element;return isSupported||(this.$element.setAttribute(eventName,"return;"),isSupported="function"==typeof this.$element[eventName]),isSupported},move:function(e){if(this.shown){switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()}},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]),this.move(e)},keypress:function(e){this.suppressKeyPressRepeat||this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(){var that=this;setTimeout(function(){that.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(e){this.$menu.find(".active").removeClass("active"),$(e.currentTarget).addClass("active")}};var old=$.fn.typeahead;$.fn.typeahead=function(option){return this.each(function(){var $this=$(this),data=$this.data("typeahead"),options="object"==typeof option&&option;data||$this.data("typeahead",data=new Typeahead(this,options)),"string"==typeof option&&data[option]()})},$.fn.typeahead.defaults={source:[],items:8,menu:'',item:'',minLength:1},$.fn.typeahead.Constructor=Typeahead,$.fn.typeahead.noConflict=function(){return $.fn.typeahead=old,this},$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);$this.data("typeahead")||(e.preventDefault(),$this.typeahead($this.data()))})}(window.jQuery),!function($){"use strict";var Affix=function(element,options){this.options=$.extend({},$.fn.affix.defaults,options),this.$window=$(window).on("scroll.affix.data-api",$.proxy(this.checkPosition,this)).on("click.affix.data-api",$.proxy(function(){setTimeout($.proxy(this.checkPosition,this),1)},this)),this.$element=$(element),this.checkPosition()};Affix.prototype.checkPosition=function(){if(this.$element.is(":visible")){var affix,scrollHeight=$(document).height(),scrollTop=this.$window.scrollTop(),position=this.$element.offset(),offset=this.options.offset,offsetBottom=offset.bottom,offsetTop=offset.top,reset="affix affix-top affix-bottom";"object"!=typeof offset&&(offsetBottom=offsetTop=offset),"function"==typeof offsetTop&&(offsetTop=offset.top()),"function"==typeof offsetBottom&&(offsetBottom=offset.bottom()),affix=null!=this.unpin&&scrollTop+this.unpin<=position.top?!1:null!=offsetBottom&&position.top+this.$element.height()>=scrollHeight-offsetBottom?"bottom":null!=offsetTop&&offsetTop>=scrollTop?"top":!1,this.affixed!==affix&&(this.affixed=affix,this.unpin="bottom"==affix?position.top-scrollTop:null,this.$element.removeClass(reset).addClass("affix"+(affix?"-"+affix:"")))}};var old=$.fn.affix;$.fn.affix=function(option){return this.each(function(){var $this=$(this),data=$this.data("affix"),options="object"==typeof option&&option;data||$this.data("affix",data=new Affix(this,options)),"string"==typeof option&&data[option]()})},$.fn.affix.Constructor=Affix,$.fn.affix.defaults={offset:0},$.fn.affix.noConflict=function(){return $.fn.affix=old,this},$(window).on("load",function(){$('[data-spy="affix"]').each(function(){var $spy=$(this),data=$spy.data();data.offset=data.offset||{},data.offsetBottom&&(data.offset.bottom=data.offsetBottom),data.offsetTop&&(data.offset.top=data.offsetTop),$spy.affix(data)})})}(window.jQuery);
--------------------------------------------------------------------------------
/js/sugar.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Sugar Library v1.2.4
3 | *
4 | * Freely distributable and licensed under the MIT-style license.
5 | * Copyright (c) 2012 Andrew Plummer
6 | * http://sugarjs.com/
7 | *
8 | * ---------------------------- */
9 | (function(context){var i=true,j=null,k=false,n=Object,o=Array,p=RegExp,q=Date,r=String,s=Number,t=n.defineProperty&&n.defineProperties;function v(a,b,c,d){var e=b?a.prototype:a;w(a,b,d);x(d,function(f,g){if(typeof c==="function")y(e,f,aa(e[f],g,c));else if(c===i||!e[f])y(e,f,g);a.SugarMethods[f]={e:b,method:g}})}
10 | function w(a){if(!a.SugarMethods){y(a,"SugarMethods",{});v(a,k,k,{restore:function(){var b=arguments.length===0,c=z(arguments);x(a.SugarMethods,function(d,e){if(b||c.has(d))y(e.e?a.prototype:a,d,e.method)})},extend:function(b,c,d){a===n&&arguments.length===0?A(C.concat(D),Object):v(a,d!==k,c,b)}})}}function aa(a,b,c){return function(){return a&&(c===i||!c.apply(this,arguments))?a.apply(this,arguments):b.apply(this,arguments)}}
11 | function y(a,b,c){if(t)n.defineProperty(a,b,{value:c,configurable:i,enumerable:k,writable:i});else a[b]=c}function x(a,b){for(var c in a)n.prototype.hasOwnProperty.call(a,c)&&b.call(a,c,a[c])}function E(a,b,c,d){var e=i;if(a===b)return i;else if(n.isRegExp(b))return p(b).test(a);else if(n.isFunction(b))return b.apply(c,[a].concat(d));else if(n.isObject(b)&&n.isObject(a)){x(b,function(f){E(a[f],b[f],c,d)||(e=k)});return!n.isEmpty(b)&&e}else return n.equal(a,b)}
12 | function F(a,b){var c,d,e,f,g,h,l=typeof a;if(l==="string")return a;d=n.prototype.toString.call(a);c=d==="[object Object]";e=d==="[object Array]";if(a!=j&&c||e){b||(b=[]);if(b.length>1)for(g=b.length;g--;)if(b[g]===a)return"CYC";b.push(a);c=r(a.constructor);f=e?a:n.keys(a).sort();for(g=0;g0);return n.keys(a).length==0},equal:function(a,b){return F(a)===F(b)},values:function(a,b){var c=[];x(a,function(d,e){c.push(e);b&&b.call(a,e)});return c},clone:function(a,b){if(a==j||typeof a!=="object")return a;if(o.isArray(a))return a.clone();var c=a.constructor===
18 | M?new M:{};return n.merge(c,a,b)},fromQueryString:function(a,b){var c=n.extended();a=a&&a.toString?a.toString():"";a.replace(/^.*?\?/,"").unescapeURL().split("&").each(function(d){d=d.split("=");d.length===2&&ca(c,d[0],d[1],b)});return c},tap:function(a,b){G(a,b,a,[a]);return a},has:function(a,b){return n.prototype.hasOwnProperty.call(a,b)}});
19 | v(n,k,function(){return arguments.length>1},{keys:function(a,b){if(a==j||typeof a!="object"&&!n.isRegExp(a)&&!n.isFunction(a))throw new TypeError("Object required");var c=[];x(a,function(d,e){c.push(d);b&&b.call(a,d,e)});return c}});function K(a,b,c,d,e){var f,g;N(b);if(c<0)c=a.length+c;g=isNaN(c)?0:parseInt(c>>0);for(c=d===i?a.length+g:a.length;g>0);if(c<0)c=e+c;if(!f&&c<0||f&&c>=e)c=g;for(;f&&c>=0||!f&&c>>0==e&&e!=4294967295&&e>=c&&d.push(e.toNumber());d.sort().each(function(f){return b.call(a,a[f],f,a)});return a}function Q(a,b,c,d){var e=c==="max",f=c==="min",g=e?-Infinity:Infinity,h=[];x(a,function(l){var m=a[l];l=G(m,b,a,d?[m,l.toNumber(),a]:[]);if(l===g)h.push(m);else if(e&&l>g||f&&l0&&!n.isFunction(a[0])},{every:function(a,b){var c=this.length,d=0;for(P(arguments);d0?a.reduce(function(b,c){return b+c}):0},average:function(a){a=a?this.map(a):this;return a.length>0?a.sum()/a.length:0},groupBy:function(a,b){var c=this,d=n.extended(),e;K(c,function(f,g){e=G(f,a,c,[f,g,c]);d[e]||(d[e]=[]);d[e].push(f)});return d.each(b)},inGroups:function(a,b){var c=
32 | arguments.length>1,d=this,e=[],f=(this.length/a).ceil();(0).upto(a-1,function(g){g=g*f;var h=d.slice(g,g+f);c&&h.length0&&c.push(d);return c},
33 | compact:function(a){var b=[];K(this,function(c){if(n.isArray(c))b.push(c.compact());else if(a&&c)b.push(c);else!a&&c!=j&&!n.isNaN(c)&&b.push(c)});return b},isEmpty:function(){return this.compact().length==0},flatten:function(a){return J(this,a)},sortBy:function(a,b){var c=this.clone();c.sort(function(d,e){var f,g;f=G(d,a,c,[d]);g=G(e,a,c,[e]);if(n.isString(f)&&n.isString(g)){f=f;g=g;var h,l,m,u,B=0,R=0;f=ia(f);g=ia(g);do{m=la(f,B);u=la(g,B);h=m?o.AlphanumericSortOrder.indexOf(m):j;l=u?o.AlphanumericSortOrder.indexOf(u):
34 | j;if(h===-1||l===-1){h=f.charCodeAt(B)||j;l=g.charCodeAt(B)||j}m=m!==f.charAt(B);u=u!==g.charAt(B);if(m!==u&&R===0)R=m-u;B+=1}while(h!=j&&l!=j&&h===l);f=h===l?R:hg?1:0;return f*(b?-1:1)});return c},randomize:function(){for(var a=this.concat(),b,c,d=a.length;d;b=parseInt(Math.random()*d),c=a[--d],a[d]=a[b],a[b]=c);return a},zip:function(){var a=I(arguments);return this.map(function(b,c){return[b].concat(a.map(function(d){return c in d?d[c]:j}))})},sample:function(a){var b=[],
35 | c=this.clone(),d;for(a>0||(a=1);b.length0?b:b[0]}});v(o,i,k,{all:o.prototype.every,any:o.prototype.some,has:o.prototype.some,insert:o.prototype.add});function S(a,b,c){c=Math[c||"round"];var d=Math.pow(10,(b||0).abs());if(b<0)d=1/d;return c(a*d)/d}function na(a,b,c,d){var e=[];a=parseInt(a);for(var f=d>0;f&&a<=b||!f&&a>=b;){e.push(a);c&&c.call(this,a);a+=d}return e}
36 | function T(a,b,c,d,e,f){var g=a.toFixed(20),h=g.search(/\./);g=g.search(/[1-9]/);h=h-g;if(h>0)h-=1;e=Math.max(Math.min((h/3).floor(),e===k?c.length:e),-d);d=c.charAt(e+d-1);if(h<-9){e=-3;b=h.abs()-9;d=c.first()}return(a/(f?(2).pow(10*e):(10).pow(e*3))).round(b||0).format()+d.trim()}v(s,k,k,{random:function(a,b){var c;if(arguments.length==1){b=a;a=0}c=Math.min(a||0,H(b)?1:b);return S(Math.random()*(Math.max(a||0,H(b)?1:b)-c)+c)}});
37 | v(s,i,k,{toNumber:function(){return parseFloat(this,10)},abbr:function(a){return T(this,a,"kmbt",0,4)},metric:function(a,b){return T(this,a,"n\u03bcm kMGTPE",4,H(b)?1:b)},bytes:function(a,b){return T(this,a,"kMGTPE",0,H(b)?4:b,i)+"B"},isInteger:function(){return this%1==0},ceil:function(a){return S(this,a,"ceil")},floor:function(a){return S(this,a,"floor")},abs:function(){return Math.abs(this)},pow:function(a){if(H(a))a=1;return Math.pow(this,a)},round:function(a){return S(this,a,"round")},chr:function(){return r.fromCharCode(this)},
38 | isOdd:function(){return!this.isMultipleOf(2)},isEven:function(){return this.isMultipleOf(2)},isMultipleOf:function(a){return this%a===0},upto:function(a,b,c){return na(this,a,b,c||1)},downto:function(a,b,c){return na(this,a,b,-(c||1))},times:function(a){if(a)for(var b=0;b=11&&b<=13)a="th";else switch(a%10){case 1:a="st";break;case 2:a="nd";break;case 3:a="rd";break;
39 | default:a="th"}return this.toString()+a},pad:function(a,b,c){c=c||10;c=this.toNumber()===0?"":this.toString(c).replace(/^-/,"");c=U(c,"0",a-c.replace(/\.\d+$/,"").length,0);if(b||this<0)c=(this<0?"-":"+")+c;return c},format:function(a,b,c){var d,e,f=/(\d+)(\d{3})/;if(r(b).match(/\d/))throw new TypeError("Thousands separator cannot contain numbers.");d=n.isNumber(a)?S(this,a).toFixed(Math.max(a,0)):this.toString();b=b||",";c=c||".";e=d.split(".");d=e[0];for(e=e[1]||"";d.match(f);)d=d.replace(f,"$1"+
40 | b+"$2");if(e.length>0)d+=c+U(e,"0",0,a-e.length);return d},hex:function(a){return this.pad(a||1,k,16)}});function V(){return"\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u2028\u2029\u3000\ufeff"}function oa(a,b,c,d){var e=I(b).join("");e=e.replace(/all/,"").replace(/(\w)lphabet|umbers?|atakana|paces?|unctuation/g,"$1");return a.replace(c,function(f){return d[f]&&(!e||e.has(d[f].type))?d[f].to:f})}
41 | var pa=[{type:"a",shift:65248,start:65,end:90},{type:"a",shift:65248,start:97,end:122},{type:"n",shift:65248,start:48,end:57},{type:"p",shift:65248,start:33,end:47},{type:"p",shift:65248,start:58,end:64},{type:"p",shift:65248,start:91,end:96},{type:"p",shift:65248,start:123,end:126}],qa={},ra={},sa=/[\u0020-\u00A5]|[\uFF61-\uFF9F][\uff9e\uff9f]?/g,ta=/[\u3000-\u301C]|[\u301A-\u30FC]|[\uFF01-\uFF60]|[\uFFE0-\uFFE6]/g,ua=/[\u30ab\u30ad\u30af\u30b1\u30b3\u30b5\u30b7\u30b9\u30bb\u30bd\u30bf\u30c1\u30c4\u30c6\u30c8\u30cf\u30d2\u30d5\u30d8\u30db]/,
42 | va=/[\u30cf\u30d2\u30d5\u30d8\u30db\u30f2]/;function W(a,b,c){qa[b]={type:a,to:c};ra[c]={type:a,to:b}}function U(a,b,c,d){var e=String(b);if(e!=b)e="";n.isNumber(c)||(c=1);n.isNumber(d)||(d=1);return e.repeat(c)+a+e.repeat(d)}var X,Y;
43 | v(r,i,k,{escapeRegExp:function(){return p.escape(this)},escapeURL:function(a){return a?encodeURIComponent(this):encodeURI(this)},unescapeURL:function(a){return a?decodeURI(this):decodeURIComponent(this)},escapeHTML:function(){return this.replace(/&/g,"&").replace(//g,">")},unescapeHTML:function(){return this.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")},encodeBase64:function(){return X(this)},decodeBase64:function(){return Y(this)},capitalize:function(a){return this.toLowerCase().replace(a?
44 | /^\S|\s\S/g:/^\S/,function(b){return b.toUpperCase()})},pad:function(a,b){return U(this,a,b,b)},padLeft:function(a,b){return U(this,a,b,0)},padRight:function(a,b){return U(this,a,0,b)},repeat:function(a){var b="",c=0;if(n.isNumber(a)&&a>0)for(;c0?"_":"")+a.toLowerCase()}).replace(/([A-Z\d]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").toLowerCase()},camelize:function(a){return this.underscore().replace(/(^|_)([^_]+)/g,function(b,c,d,e){b=r.Inflector&&r.Inflector.acronyms&&r.Inflector.acronyms[d];e=a!==k||e>0;if(b)return e?b:b.toLowerCase();return e?d.capitalize():d})},spacify:function(){return this.underscore().replace(/_/g," ")},stripTags:function(){var a=
50 | this;z(arguments.length>0?arguments:[""],function(b){a=a.replace(p("?"+b.escapeRegExp()+"[^<>]*>","gi"),"")});return a},removeTags:function(){var a=this;z(arguments.length>0?arguments:["\\S+"],function(b){b=p("<("+b+")[^<>]*(?:\\/>|>.*?<\\/\\1>)","gi");a=a.replace(b,"")});return a},truncate:function(a,b,c){var d;b=H(b)?"...":String(b);a-=b.length;if(this.length<=a)return this.toString();d=b.match(/^(.)\1+$/)?b.slice(0,1):"";for(d=p("[^"+V()+d+"]["+V()+d+"]");a>0&&!d.test(this.slice(a-1,a+1))&&c!==
51 | i;)a--;return this.slice(0,a)+(a>0?b:"")},assign:function(){var a=n.extended();z(arguments,function(b,c){if(n.isObject(b))a.merge(b);else a[c+1]=b});return this.replace(/\{(.+?)\}/g,function(b,c){return n.prototype.hasOwnProperty.call(a,c)?a[c]:b})}});
52 | v(r,i,function(a){return n.isRegExp(a)},{split:function(a,b){var c=[],d=0;a=p(a).addFlag("g");var e,f,g,h;p.c||(e=RegExp("^"+a.source+"$(?!\\s)",a.getFlags()));if(H(b)||b<0)b=Infinity;else{b|=0;if(!b)return[]}for(;f=a.exec(this);){g=f.index+f[0].length;if(g>d){c.push(this.slice(d,f.index));!p.c&&f.length>1&&f[0].replace(e,function(){for(var l=1;l1&&f.index=
53 | b)break}a.lastIndex===f.index&&a.lastIndex++}if(d===this.length){if(h||!a.test(""))c.push("")}else c.push(this.slice(d));return c.length>b?c.slice(0,b):c}});v(r,i,k,{insert:r.prototype.add});p.c=H(p("()??").exec("")[1]);function Z(a,b){var c="";if(b=="g"||a.global)c+="g";if(b=="i"||a.ignoreCase)c+="i";if(b=="m"||a.multiline)c+="m";if(b=="y"||a.g)c+="y";return c}v(p,k,k,{escape:function(a){n.isString(a)||(a=String(a));return a.replace(/([\\/'*+?|()\[\]{}.^$])/g,"\\$1")}});
54 | v(p,i,k,{getFlags:function(){return Z(this)},setFlags:function(a){return p(this.source,a)},addFlag:function(a){return this.setFlags(Z(this,a))},removeFlag:function(a){return this.setFlags(Z(this).replace(a,""))}});function $(a,b,c,d,e){if(!a.b)a.b=[];a.b.push(setTimeout(function(){a.b.removeAt(f);c.apply(d,e||[])},b));var f=a.b.length}
55 | v(Function,i,k,{lazy:function(a,b){function c(){if(!(g||f.length==0)){for(var m=Math.max(f.length-l,0);f.length>m;)Function.prototype.apply.apply(e,f.shift());$(d,h,function(){g=k;c()});g=i}}function d(){if(!(g&&f.length>b-2)){f.push([this,arguments]);c()}}var e=this,f=[],g=k,h,l;a=a||1;b=b||Infinity;h=a.ceil();l=S(h/a);return d},delay:function(a){n.isNumber(a)||(a=0);var b=I(arguments,1);$(this,a,this,this,b);return this},debounce:function(a,b){var c=this;return b===k?this.lazy(a,1):function(){c.cancel();
56 | $(c,a,c,this,arguments)}},cancel:function(){if(n.isArray(this.b))for(;this.b.length>0;)clearTimeout(this.b.shift());return this},after:function(a){var b=this,c=0,d=[];if(n.isNumber(a)){if(a===0){b.call();return b}}else a=1;return function(){var e;d.push(Array.create(arguments));c++;if(c==a){e=b.call(this,d);c=0;d=[];return e}}},once:function(){var a=this;return function(){return n.prototype.hasOwnProperty.call(a,"memo")?a.memo:a.memo=a.apply(this,arguments)}},fill:function(){var a=this,b=I(arguments);
57 | return function(){var c=I(arguments);K(b,function(d,e){if(d!=j||e>=c.length)c.splice(e,0,d)});return a.apply(this,c)}}});(function(){var a={},b;K(["Array","Boolean","Date","Function","Number","String","RegExp"],function(c){b="is"+c;C.push(b);a[b]=function(d){return L(d,c)}});v(Object,k,k,a)})();A(D,M);
58 | (function(a){if(this.btoa){X=this.btoa;Y=this.atob}var b=/[^A-Za-z0-9\+\/\=]/g;X=function(c){var d="",e,f,g,h,l,m,u=0;do{e=c.charCodeAt(u++);f=c.charCodeAt(u++);g=c.charCodeAt(u++);h=e>>2;e=(e&3)<<4|f>>4;l=(f&15)<<2|g>>6;m=g&63;if(isNaN(f))l=m=64;else if(isNaN(g))m=64;d=d+a.charAt(h)+a.charAt(e)+a.charAt(l)+a.charAt(m)}while(u>4;f=(f&15)<<4|h>>2;g=(h&3)<<6|l;d+=e.chr();if(h!=64)d+=f.chr();if(l!=64)d+=g.chr()}while(m0)d.digits+=d.numbers.join("");
88 | else d.numbers=x.split("");d.monthSuffix=e[1]}d.capitalizeUnit=a=="de";d.hasPlural=b(2);d.pastRelativeFormat=d.formats[0];d.futureRelativeFormat=d.formats[b(3)?1:0];d.durationFormat=d.formats[0].replace(/\s*\{sign\}\s*/,"");return d}function P(a){a||(a=Date.currentLocale);return a!="en"&&a!="en-US"}function N(a){q.merge(this,a)}
89 | q.merge(N.prototype,{getMonth:function(a){return q.isNumber(a)?a-1:this.months.findIndex(p(a,"i"))%12},l:function(a){return this.weekdays.findIndex(p(a,"i"))%7},k:function(a){var b;return q.isNumber(a)?a:a&&(b=this.numbers.indexOf(a))!==-1?(b+1)%10:1},o:function(a){var b=this;return a.replace(this.numbers[9],"").each(function(d){return b.k(d)}).join("")},n:function(a){return u.units[this.units.indexOf(a)%8]},r:function(a){return this.j(a,a[2]>0?"futureRelativeFormat":"pastRelativeFormat")},duration:function(a){return this.j(Q(a),
90 | "durationFormat")},j:function(a,b){var d=a[0],e=a[1],g=a[2],f;if(this.code=="ru"){f=d.toString().from(-1);switch(j){case f==1:f=1;break;case f>=2&&f<=4:f=2;break;default:f=3}}else f=this.hasPlural&&d>1?1:0;f=this.units[f*8+e]||this.units[e];if(this.capitalizeUnit)f=f.capitalize();e=this.modifiers.find(function(h){return h.name=="sign"&&h.value==(g>0?1:-1)});return this[b].assign({num:d,unit:f,sign:e.src})},addFormat:function(a,b,d){var e=[],g=this;d!==k&&g.u.push(a);a=a.replace(/\s+/g,"[-,. ]*");
91 | a=a.replace(/\{(.+?)\}/g,function(f,h){var c=h.match(/\?$/),i=h.match(/(\d)(?:-(\d))?/),m=h.match(/^\d+$/),l=h.replace(/[^a-z]+$/,""),n,r;if(l==="time"){e=e.concat(w);return c?"\\s*(?:(?:t|at |\\s+)(\\d{1,2}):?(\\d{2})?:?(\\d{2})?(?:\\.(\\d{1,6}))?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?)?":"(\\d{1,2}):?(\\d{2})?:?(\\d{2})?(?:\\.(\\d{1,6}))?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?"}if(m)n=g.optionals[m[0]];else if(g[l])n=g[l];else if(g[l+"s"]){n=g[l+"s"];if(i){r=[];n.forEach(function(Y,
92 | Z){var O=Z%(g.units?8:n.length);if(O>=i[1]&&O<=(i[2]||i[1]))r.push(Y)});n=r}n=n.compact().join("|")}if(m)return"(?:"+n+")?";else{e.push(l);return"("+n+")"+(c?"?":"")}});J(a,e,b)}});function R(a){var b;if(q.isObject(a[0]))return a;else if(a.length==1&&q.isNumber(a[0]))return[a[0]];b={};B.each(function(d,e){b[d.a]=a[e]});return[b]}function S(a,b){if(b!="date"&&b!="month"&&b!="year")return a;return a.replace(z,function(d){return x.indexOf(d)+1||""})}
93 | function aa(a,b){var d={},e,g;b.each(function(f,h){e=a[h+1];if(!(e===void 0||e==="")){e=S(e.hankaku("n"),f);if(f==="year")d.t=e;if(f==="millisecond")e*=Math.pow(10,3-e.length);g=parseFloat(e);d[f]=!isNaN(g)?g:e.toLowerCase()}});return d}
94 | function T(a,b){var d=new s,e=k,g,f,h,c,i,m,l;if(q.isDate(a))d=a;else if(q.isNumber(a))d=new s(a);else if(q.isObject(a)){d=(new s).set(a,j);c=a}else if(q.isString(a)){I(K(b,j));f=P(b);a=a.trim().replace(/\.+$/,"").replace(/^now$/,"");A.each(function(n){var r=a.match(n.q);if(r){h=n;c=aa(r,h.to);g=K(h.p,j);if(c.timestamp){d.setTime(0);c={milliseconds:c.timestamp};return k}if(h.h&&!q.isString(c.month)&&(q.isString(c.date)||f)){l=c.month;c.month=c.date;c.date=l}if(c.year&&c.t.length===2)c.year=((new s).getFullYear()/
95 | 100).round()*100-(c.year/100).round()*100+c.year;if(c.month){c.month=g.getMonth(c.month);if(c.shift&&!c.unit)c.unit="year"}if(c.weekday&&c.date)delete c.weekday;else if(c.weekday){c.weekday=g.l(c.weekday);if(c.shift&&!c.unit)c.unit="week"}if(c.day&&(l=g.f[c.day])){c.day=l.value;d.resetTime();e=j}else if(c.day&&(l=g.l(c.day))>-1){delete c.day;c.weekday=l}if(c.date&&!q.isNumber(c.date))c.date=g.o(c.date);if(c.meridian)if(c.meridian==="pm"&&c.hour<12)c.hour+=12;if(c.offset_hours||c.offset_minutes){c.utc=
96 | j;c.offset_minutes=c.offset_minutes||0;c.offset_minutes+=c.offset_hours*60;if(c.offset_sign==="-")c.offset_minutes*=-1;c.minute-=c.offset_minutes}if(c.unit){e=j;m=g.k(c.num);i=g.n(c.unit);if(c.shift||c.edge){m*=(l=g.f[c.shift])?l.value:0;if(i==="month"&&v(c.date)){d.set({day:c.date},j);delete c.date}if(i==="year"&&v(c.month)){d.set({month:c.month,day:c.date},j);delete c.month;delete c.date}}if(c.sign&&(l=g.f[c.sign]))m*=l.value;if(v(c.weekday)){d.set({weekday:c.weekday},j);delete c.weekday}c[i]=(c[i]||
97 | 0)+m}if(c.year_sign==="-")c.year*=-1;return k}});if(h)if(e)d.advance(c);else if(c.utc){d.resetTime();d.setUTC(c,j)}else d.set(c,j);else d=a?new s(a):new s;if(c&&c.edge){l=g.f[c.edge];C.slice(4).each(function(n){if(v(c[n.a])){i=n.a;return k}});if(i==="year")c.d="month";else if(i==="month"||i==="week")c.d="day";d[(l.value<0?"endOf":"beginningOf")+i.capitalize()]();l.value===-2&&d.resetTime()}}return{e:d,set:c}}
98 | function U(a,b,d,e){var g,f=K(e,j),h=p(/^[A-Z]/);if(a.isValid())if(Date[b])b=Date[b];else{if(q.isFunction(b)){g=Q(a.millisecondsFromNow());b=b.apply(a,g.concat(f))}}else return"Invalid Date";if(!b&&!d)b=f.outputFormat;else if(!b&&d){g=g||Q(a.millisecondsFromNow());if(g[1]===0){g[1]=1;g[0]=1}return f.r(g)}E.each(function(c){b=b.replace(p("\\{("+c.b+")(\\d)?\\}",c.i?"i":""),function(i,m,l){i=c.format(a,f,l||1,m);l=m.length;var n=m.match(/^(.)\1+$/);if(c.i){if(l===3)i=i.to(3);if(n||m.match(h))i=i.capitalize()}else if(n&&
99 | !c.text)i=(q.isNumber(i)?i.pad(l):i.toString()).last(l);return i})});return b}function ba(a,b,d){var e=T(b),g=0,f=b=0,h;if(d>0){b=f=d;h=j}if(!e.e.isValid())return k;if(e.set&&e.set.d){F.each(function(i){if(i.a===e.set.d)g=i.c(e.e,a-e.e)-1});if(e.set.edge||e.set.shift)e.e["beginningOf"+e.set.d.capitalize()]();if(!h&&e.set.sign&&e.set.d!="millisecond"){b=50;f=-50}}d=a.getTime();h=e.e.getTime();var c=h+g;if(e.set&&e.set.d=="week"&&(new Date(c+1)).getHours()!=0)c+=s.DSTOffset;return d>=h-b&&d<=c+f}
100 | function V(a,b,d,e,g){if(q.isNumber(b)&&g)b={milliseconds:b};else if(q.isNumber(b)){a.setTime(b);return a}if(b.date)b.day=b.date;if(!g&&b.day===void 0&&v(b.weekday)){a["set"+(e?"UTC":"")+"Weekday"](b.weekday);b.day=a["get"+(e?"UTC":"")+"Date"](void 0);delete b.weekday}C.each(function(f){if(v(b[f.a])||v(b[f.a+"s"])){b.d=f.a;return k}else if(d&&f.a!=="week"&&f.a!=="year")a["set"+(e?"UTC":"")+f.method](f.a==="day"?1:0)});F.each(function(f){var h=f.a;f=f.method;var c=v(b[h])?b[h]:b[h+"s"];if(c!==void 0){if(g){if(h===
101 | "week"){c=(b.day||0)+c*7;f="Date"}c=c*g+a["get"+f](void 0)}a["set"+(e?"UTC":"")+f](c);if(h==="month"){h=c;if(h<0)h+=12;h%12!=a.getMonth()&&a.setDate(0)}}});return a}function W(a){a.addDays(4-(a.getDay()||7)).resetTime();return 1+(a.daysSince(a.clone().beginningOfYear())/7|0)}function Q(a){var b,d=a.abs(),e=d,g=0;C.from(1).each(function(f,h){b=(d/f.c()*10).round()/10|0;if(b>=1){e=b;g=h+1}});return[e,g,a]}function X(a){var b;b=q.isNumber(a[1])?R(a)[0]:a[0];return T(b,a[1]).e}
102 | function ca(a,b){function d(){return(this*b).round()}function e(){return X(arguments)[f](this)}function g(){return X(arguments)[f](-this)}var f="add"+a.capitalize()+"s",h={};h[a]=d;h[a+"s"]=d;h[a+"Before"]=g;h[a+"sBefore"]=g;h[a+"Ago"]=g;h[a+"sAgo"]=g;h[a+"After"]=e;h[a+"sAfter"]=e;h[a+"FromNow"]=e;h[a+"sFromNow"]=e;t.extend(h)}
103 | function $(a){var b=new s(s.UTC(1999,11,31)),d={};if(!b[a]||b[a]()!=="1999-12-31T00:00:00.000Z"){d[a]=function(){return U(this.toUTC(),s.ISO8601_DATETIME)};s.extend(d,j)}}s.extend({create:function(){return X(arguments)},now:function(){return(new s).getTime()},setLocale:function(a,b){var d=K(a,k,b);if(d){Date.currentLocale=a;I(d);return d}},getLocale:function(a){return K(a,j)},addFormat:function(a,b,d,e){J(a,b,d,e,"unshift")}},k,k);
104 | s.extend({set:function(){var a=R(arguments);return V(this,a[0],a[1])},setUTC:function(){var a=R(arguments);return V(this,a[0],a[1],j)},setWeekday:function(a){a===void 0||this.setDate(this.getDate()+a-this.getDay())},setUTCWeekday:function(a){a===void 0||this.setDate(this.getUTCDate()+a-this.getDay())},setWeek:function(a){if(a!==void 0){this.setMonth(0);this.setDate(a*7+1)}},setUTCWeek:function(a){if(a!==void 0){this.setMonth(0);this.setUTCDate(a*7+1)}},getWeek:function(){return W(this)},getUTCWeek:function(){return W(this.toUTC())},
105 | getUTCOffset:function(a){var b=this.g?0:this.getTimezoneOffset(),d=a===j?":":"";if(!b&&a)return"Z";return(-b/60).round().pad(2,j)+d+(b%60).pad(2)},toUTC:function(){if(this.g)return this;var a=this.clone().addMinutes(this.getTimezoneOffset());a.g=j;return a},isUTC:function(){return this.g||this.getTimezoneOffset()===0},advance:function(){var a=R(arguments);return V(this,a[0],k,k,1,j)},rewind:function(){var a=R(arguments);return V(this,a[0],k,k,-1)},isValid:function(){return!isNaN(this.getTime())},
106 | isAfter:function(a,b){return this.getTime()>s.create(a).getTime()-(b||0)},isBefore:function(a,b){return this.getTime()e},isLeapYear:function(){var a=this.getFullYear();return a%4===0&&a%100!==0||a%400===0},daysInMonth:function(){return 32-(new s(this.getFullYear(),this.getMonth(),32)).getDate()},format:function(a,
107 | b){return U(this,a,k,b)},relative:function(a,b){if(q.isString(a)){b=a;a=null}return U(this,a,j,b)},is:function(a,b){var d;if(q.isString(a)){a=a.trim().toLowerCase();switch(j){case a==="future":return this.getTime()>(new s).getTime();case a==="past":return this.getTime()<(new s).getTime();case a==="weekday":return this.getDay()>0&&this.getDay()<6;case a==="weekend":return this.getDay()===0||this.getDay()===6;case (d=u.weekdays.indexOf(a)%7)>-1:return this.getDay()===d;case (d=u.months.indexOf(a)%12)>
108 | -1:return this.getMonth()===d}}return ba(this,a,b)},resetTime:function(){return this.set({hour:0,minute:0,second:0,millisecond:0})},clone:function(){return new s(this.getTime())}});s.extend({iso:function(){return this.toISOString()},getWeekday:s.prototype.getDay,getUTCWeekday:s.prototype.getUTCDay});t.extend({duration:function(a){return Date.getLocale(a).duration(this)}});u=s.setLocale("en");
109 | (function(){var a={};F.each(function(b,d){function e(i,m){return((s.create(i,m).getTime()-this.getTime())/c).round()}function g(i,m){return((this.getTime()-s.create(i,m).getTime())/c).round()}var f=b.a,h=f.capitalize(),c=b.c();a[f+"sAgo"]=e;a[f+"sUntil"]=e;a[f+"sSince"]=g;a[f+"sFromNow"]=g;a["add"+h+"s"]=function(i){var m={};m[f]=i;return this.advance(m)};ca(f,c);d<3&&["Last","This","Next"].each(function(i){a["is"+i+h]=function(){return this.is(i+" "+f)}});if(d<4){a["beginningOf"+h]=function(){var i=
110 | {};switch(f){case "year":i.year=this.getFullYear();break;case "month":i.month=this.getMonth();break;case "day":i.day=this.getDate();break;case "week":i.weekday=0}return this.set(i,j)};a["endOf"+h]=function(){var i={hours:23,minutes:59,seconds:59,milliseconds:999};switch(f){case "year":i.month=11;i.day=31;break;case "month":i.day=this.daysInMonth();break;case "week":i.weekday=6}return this.set(i,j)}}});s.extend(a)})();
111 | (function(){B=F.clone().removeAt(2);C=F.clone().reverse();var a="\\d{1,2}|"+u.months.join("|");D.each(function(b){J(b.src.replace(/\{month\}/,a)+(b.s===k?"":"\\s*(?:(?:t|at |\\s+)(\\d{1,2}):?(\\d{2})?:?(\\d{2})?(?:\\.(\\d{1,6}))?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?)?"),b.to.concat(w),"en",b.h)});J("(\\d{1,2}):?(\\d{2})?:?(\\d{2})?(?:\\.(\\d{1,6}))?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?",w)})();
112 | (function(){var a={},b=u.weekdays.slice(0,7),d=u.months.slice(0,12);["today","yesterday","tomorrow","weekday","weekend","future","past"].concat(b).concat(d).each(function(e){a["is"+e.capitalize()]=function(){return this.is(e)}});s.extend(a)})();$("toISOString");$("toJSON");
113 | s.extend({DSTOffset:((new s(2E3,6,1)).getTimezoneOffset()-(new s(2E3,0,1)).getTimezoneOffset())*60*1E3,INTERNATIONAL_TIME:"{h}:{mm}:{ss}",RFC1123:"{Dow}, {dd} {Mon} {yyyy} {HH}:{mm}:{ss} {tz}",RFC1036:"{Weekday}, {dd}-{Mon}-{yy} {HH}:{mm}:{ss} {tz}",ISO8601_DATE:"{yyyy}-{MM}-{dd}",ISO8601_DATETIME:"{yyyy}-{MM}-{dd}T{HH}:{mm}:{ss}.{fff}{isotz}"},k,k);})(this);
114 |
--------------------------------------------------------------------------------