├── src ├── index.js ├── img │ └── heart.svg ├── js │ ├── img │ │ └── heart.svg │ ├── start.js │ ├── lib │ │ ├── xirsys.api.js │ │ ├── xirsys.simplewebrtc.js │ │ ├── xirsys.simplewebrtc.connection.js │ │ ├── xirsys.core.js │ │ └── xirsys.signal.js │ ├── index.js │ └── app.bundle.js ├── css │ ├── main.css │ └── index.css └── html │ ├── start.html │ └── index.html ├── .gitignore ├── LICENSE.md ├── README.md ├── package.json ├── webpack.config.js ├── index.html └── main.js /src/index.js: -------------------------------------------------------------------------------- 1 | require('./css/index.css'); 2 | require('./js/index.js') 3 | require('./img/heart.svg') 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.app 4 | dist 5 | *.nupkg 6 | xirsys_connect.js 7 | .yarnclean 8 | -------------------------------------------------------------------------------- /src/img/heart.svg: -------------------------------------------------------------------------------- 1 | Artboard 1 -------------------------------------------------------------------------------- /src/js/img/heart.svg: -------------------------------------------------------------------------------- 1 | Artboard 1 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT license 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Glaze 3 |
4 | 5 | # Glaze 6 | [![Github All Releases](https://img.shields.io/github/downloads/adamsiwiec/glaze/total.svg)]() 7 | [![GitHub release](https://img.shields.io/github/release/adamsiwiec/glaze.svg)]() 8 | [![license](https://img.shields.io/github/license/adamsiwiec/glaze.svg)]() 9 | 10 | A simple and fast p2p voice chat for gaming (or anything else) 11 | 12 | 13 | [![Imgur](http://i.imgur.com/jTRdGxr.gif)]() 14 | 15 | 16 | 17 | ## To Download 18 | 19 | Glaze is available for Windows, macOS, and Linux. 20 | 21 | 1. Go to the [releases](https://github.com/adamsiwiec/glaze/releases) and find your system's installer there. 22 | 2. Then just click on it, download, and run it to your computer. 23 | 24 | 25 | ## Want to hack on Glaze? 26 | 27 | ``` 28 | $ mkdir glaze 29 | $ cd glaze 30 | $ git clone https://github.com/adamsiwiec/glaze . 31 | $ npm install 32 | $ npm start 33 | ``` 34 | #### Authors 35 | - Adam Siwiec - [Website](https://siwiec.us) 36 | 37 | #### License [MIT License](LICENSE.md) 38 | 39 | ### Glaze is made possible by: 40 | 41 | * [Electron](https://electron.atom.io) 42 | * [SimpleWebRTC](https://simplewebrtc.com) 43 | * And many more awesome open-source projects 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glaze", 3 | "version": "0.3.7", 4 | "description": "A simple and fast P2P voice chat for gaming", 5 | "main": "main.js", 6 | "scripts": { 7 | "pack": "build --dir", 8 | "distwindows": "build -w", 9 | "distlinux": "build -l", 10 | "distmac": "build -m", 11 | "dist": "build -mwl", 12 | "start": "electron .", 13 | "temp": "build -w --ia32", 14 | "pub": "build -mwl -p always", 15 | "release": "build" 16 | }, 17 | "repository": "https://github.com/adamsiwiec/glaze", 18 | "author": "Adam Siwiec", 19 | "license": "MIT", 20 | "devDependencies": { 21 | "css-loader": "^0.28.4", 22 | "devtron": "^1.4.0", 23 | "electron": "^1.5.0", 24 | "electron-builder": "^20.2.0", 25 | "file-loader": "^1.1.5", 26 | "image-webpack-loader": "^4.1.0", 27 | "style-loader": "^0.20.2", 28 | "webpack": "^4.1.0" 29 | }, 30 | "build": { 31 | "publish": [ 32 | { 33 | "provider": "github", 34 | "owner": "adamsiwiec", 35 | "repo": "glaze" 36 | } 37 | ], 38 | "appId": "com.adamsiwiec.glaze", 39 | "mac": { 40 | "target": [ 41 | "dmg", 42 | "zip" 43 | ] 44 | }, 45 | "win": { 46 | "target": "nsis" 47 | }, 48 | "linux": { 49 | "target": "tar.gz" 50 | } 51 | }, 52 | "dependencies": { 53 | "electron-updater": "^2.7.1", 54 | "jquery": "^3.1.1" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/css/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .top, .content { 4 | background-color: rgb(244, 245, 246); 5 | 6 | } 7 | 8 | h2, h3 { 9 | margin-top: 100px; 10 | } 11 | 12 | .btn { 13 | height: 40px !important; 14 | } 15 | 16 | .padding { 17 | padding-top: 40px; 18 | padding-bottom: 40px; 19 | 20 | } 21 | 22 | pre { 23 | background-color: #ededed; 24 | padding: 10px; 25 | } 26 | 27 | 28 | .header { 29 | height: 100vh; 30 | text-align: right; 31 | } 32 | 33 | .cls-1 { 34 | fill: none; 35 | stroke-dasharray: 650; 36 | stroke-dashoffset: 650; 37 | animation: dash 5s linear forwards; 38 | } 39 | 40 | .cls-2 { 41 | 42 | fill: none; 43 | stroke-dasharray: 600; 44 | stroke-dashoffset: 600; 45 | animation: dash 5s linear forwards; 46 | } 47 | 48 | .cls-3 { 49 | fill: none; 50 | stroke-dasharray: 1200; 51 | stroke-dashoffset: 1200; 52 | animation: dash 5s linear forwards; 53 | 54 | } 55 | 56 | @keyframes dash { 57 | 58 | to { 59 | fill-opacity: 1; 60 | stroke-dashoffset: 0; 61 | 62 | 63 | } 64 | 65 | 66 | } 67 | 68 | 69 | .intro { 70 | display: flex; 71 | flex-direction: column; 72 | justify-content: center; 73 | } 74 | 75 | .glaze { 76 | max-height: 500px; 77 | margin: 0 auto; 78 | } 79 | 80 | 81 | @media (max-width: 768px) { 82 | 83 | .header { 84 | text-align: center; 85 | } 86 | 87 | } 88 | 89 | footer { 90 | background-color: rgb(244, 245, 246); 91 | } 92 | -------------------------------------------------------------------------------- /src/html/start.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 36 | 37 |
38 |

Glaze

39 |

Let's get you setup!

40 | 41 |
42 |

Create or Join a Room

43 |
44 | 45 |
46 | 47 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/css/index.css: -------------------------------------------------------------------------------- 1 | h4, h5, p, a { 2 | font-family: 'Lato', sans-serif; 3 | 4 | } 5 | * { 6 | text-shadow: rgba(0,0,0,.01) 0 0 1px; 7 | } 8 | .room-container { 9 | height: 100vh; 10 | background-color: #FDFDFD; 11 | margin:0; 12 | } 13 | 14 | pre { 15 | background-color: green; 16 | } 17 | .right-status-container { 18 | //border-left: 1px solid gray; 19 | height: 100vh; 20 | padding: 0; 21 | } 22 | 23 | #avatar { 24 | height: 70vh; 25 | background-color: #0275d8; 26 | } 27 | 28 | #status-container { 29 | height: 30vh; 30 | background-color: #d3d3d3; 31 | } 32 | 33 | #status { 34 | overflow: auto; 35 | } 36 | 37 | .avatar-div { 38 | background-color: #d3d3d3; 39 | opacity: 0.95; 40 | height: 200px; 41 | display: flex; 42 | flex-direction: column; 43 | justify-content: center; 44 | } 45 | 46 | #me { 47 | position: absolute; 48 | bottom: 0; 49 | left: 10px; 50 | color: #d3d3d3; 51 | } 52 | 53 | a { 54 | color: #d3d3d3; 55 | } 56 | 57 | a:link { 58 | color: #d3d3d3; 59 | text-decoration: none; 60 | } 61 | 62 | a:visited { 63 | color: #d3d3d3; 64 | text-decoration: none; 65 | } 66 | 67 | a:hover { 68 | color: #d3d3d3; 69 | text-decoration: none; 70 | } 71 | 72 | a:active { 73 | color: #d3d3d3; 74 | text-decoration: none; 75 | } 76 | 77 | .heart { 78 | height: 30px; 79 | width: 30px; 80 | } 81 | 82 | .message { 83 | position: absolute; 84 | right: 10px; 85 | bottom: 15px; 86 | background-color: #FFB732; 87 | padding: 5px; 88 | font-size: 12px; 89 | 90 | 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/js/start.js: -------------------------------------------------------------------------------- 1 | const BrowserWindow = require('electron').remote.BrowserWindow; 2 | const path = require('path'); 3 | const url = require('url'); 4 | const remote = require('electron').remote; 5 | const $ = require('jquery'); 6 | const ipc = require('electron').ipcRenderer; 7 | 8 | function validate(room, nick) { 9 | return (room && nick) && nick.indexOf(' ') === -1; 10 | } 11 | 12 | let create = $('#manage-window'); 13 | let createForm = $(` 14 |
15 |
16 | 17 |

18 |

19 |
20 | 21 |

22 |

23 |

24 |

25 |
26 | `); 30 | let win; 31 | 32 | create.on('click', function (event) { 33 | create.replaceWith(createForm); 34 | }); 35 | 36 | createForm.on('submit', function (event) { 37 | event.preventDefault(); 38 | $('.nick-error').text(''); 39 | $('.room-error').text(''); 40 | $('.space-error').text(''); 41 | 42 | if (validate($('.room').val(), $('.nick').val())) { 43 | 44 | ipc.send('close-starter', { 45 | room: $('.room').val(), 46 | nick: $('.nick').val() 47 | 48 | }); 49 | var current = remote.getCurrentWindow(); 50 | current.close(); 51 | 52 | 53 | } else { 54 | if (!$('.nick').val()) { 55 | $('.nick-error').text('Please put in a Username'); 56 | } 57 | if (!$('.room').val()) { 58 | $('.room-error').text('Please put in a room'); 59 | } 60 | if ($('.nick').val().indexOf(' ') !== -1) { 61 | $('.space-error').text('Please remove the space from your Username'); 62 | } 63 | } 64 | }); 65 | -------------------------------------------------------------------------------- /src/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Room:

21 |
22 |

Chat Count:

23 |
24 |

Username:

25 |
26 |
27 |
29 | 30 |
31 |
32 |
33 |

Status:

34 |
35 |
36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/js/lib/xirsys.api.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 XirSys 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | ******************************************************************************** 25 | 26 | This script provides functionality for connecting to the 27 | XirSys API endpoints. 28 | 29 | No external libraries are required. However, if supporting an 30 | older browser (earlier than Internet Explorer 8, Firefox 3.1, 31 | Safari 4, and Chrome 3), then you may want to use the open 32 | source JSON library by Douglas Crockford : 33 | (https://github.com/douglascrockford/JSON-js) 34 | 35 | *********************************************************************************/ 36 | 37 | 'use strict'; 38 | 39 | (function () { 40 | 41 | /********************************************************************************* 42 | * For full use of this class, see the information at the top of this script. 43 | *********************************************************************************/ 44 | 45 | $xirsys.class.create({ 46 | namespace : 'api', 47 | constructor : function ($opts, $url) { 48 | if (!!$url) { 49 | $xirsys.api.iceUrl = $url + "ice"; 50 | } 51 | this.data = $opts; 52 | }, 53 | fields : { 54 | ice : null 55 | }, 56 | methods : { 57 | getIceServers : function ($cb) { 58 | var self = this; 59 | $xirsys.ajax.do({ 60 | url: $xirsys.api.iceUrl, 61 | method: 'POST', // In http://xirsys.com/guide/ it uses a GET rather than a POST ... Should resolve. 62 | data: self.xirsys_opts 63 | }) 64 | .done(function($data) { 65 | self.ice = $data.d; 66 | $cb.apply(this, [self.ice]); 67 | }); 68 | } 69 | }, 70 | statics : { 71 | iceUrl : $xirsys.baseUrl + "ice" 72 | } 73 | }); 74 | 75 | })(); 76 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | var $ = require('jquery'); 2 | 3 | var getUrlParameter = function getUrlParameter(sParam) { 4 | var sPageURL = decodeURIComponent(window.location.search.substring(1)), 5 | sURLVariables = sPageURL.split('&'), 6 | sParameterName, 7 | i; 8 | 9 | for (i = 0; i < sURLVariables.length; i++) { 10 | sParameterName = sURLVariables[i].split('='); 11 | 12 | if (sParameterName[0] === sParam) { 13 | return sParameterName[1] === undefined ? true : sParameterName[1]; 14 | } 15 | } 16 | }; 17 | 18 | var room = getUrlParameter('room'); 19 | var nickname = getUrlParameter('nick'); 20 | var count = 0; 21 | $('.chat-count').text(count); 22 | $('.username').text(nickname); 23 | $('.room-name').text(room); 24 | 25 | 26 | $(document).ready(function() { 27 | $.post("https://service.xirsys.com/room", { 28 | ident: "adamsiwiec", 29 | secret: "138a1524-c7ec-11e6-9123-fb8fc78d0e76", 30 | domain: "www.adamsiwiec.com", 31 | application: "glaze", 32 | room: room, 33 | secure: 1 34 | }, 35 | function(data, status) { 36 | //var url = "https://" + data.d.iceServers[0].url.substring(5); 37 | console.log(data) 38 | 39 | var webrtc = new $xirsys.simplewebrtc(); 40 | webrtc.connect( 41 | xirsysConnect.data, 42 | { 43 | 44 | autoRequestMedia: true, // immediately ask for camera access 45 | media: { 46 | video: false, 47 | audio: true 48 | }, 49 | recieveMedia: { 50 | video: false, 51 | audio: true 52 | }, 53 | nick: nickname, 54 | detectSpeakingEvents: false, 55 | autoAdjustMic: false 56 | }, 57 | application 58 | ); 59 | function application ($inst) { 60 | 61 | webrtc.prepareRoom(room); 62 | webrtc.on('readyToCall', function () { 63 | // you can name it anything 64 | webrtc.joinRoom(room); 65 | }); 66 | 67 | webrtc.on('videoAdded', function(videoEl, peer) { 68 | count += 1; 69 | $('#status').append('

' + peer.nick + ' Joined!

'); 70 | $('#avatar').append('

' + peer.nick + '

'); 71 | 72 | var grammar1; 73 | var grammar2; 74 | if (count === 1) { 75 | grammar1 = 'is'; 76 | grammar2 = 'person'; 77 | } else { 78 | grammar1 = 'are'; 79 | grammar2 = 'people'; 80 | } 81 | $('.chat-count').text(count); 82 | }); 83 | 84 | webrtc.on('videoRemoved', function(videoEl, peer) { 85 | count -= 1; 86 | $('#status').append('

' + peer.nick + ' left!

'); 87 | $('.' + peer.nick).remove(); 88 | $('.chat-count').text(count); 89 | }); 90 | } 91 | }); 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | var SRC = path.join(__dirname, 'src/'); 5 | 6 | module.exports = { 7 | entry: SRC, 8 | output: { 9 | publicPath: 'src/js/', 10 | path: __dirname + '/src/js', 11 | filename: 'app.bundle.js' 12 | }, 13 | module: { 14 | rules: [{ 15 | test: /\.css$/, 16 | use: ['style-loader', 'css-loader'] 17 | }, { 18 | test: /\.(jpg|png)$/, 19 | use: ['file-loader?name=img/[name].[ext]', { 20 | loader: 'image-webpack-loader', 21 | query: { 22 | mozjpeg: { 23 | progressive: true, 24 | }, 25 | gifsicle: { 26 | interlaced: false, 27 | }, 28 | optipng: { 29 | optimizationLevel: 4, 30 | }, 31 | pngquant: { 32 | quality: '75-90', 33 | speed: 3, 34 | }, 35 | }, 36 | }] 37 | 38 | }, { 39 | test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 40 | use: 'url-loader?limit=10000&minetype=application/font-woff' 41 | }, { 42 | test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 43 | use: 'file-loader' 44 | }, { 45 | test: /\.svg(\?v=[0-9]\.[0-9]\.[0-9])?$/, 46 | use: ['file-loader', { 47 | loader: 'image-webpack-loader', 48 | query: { 49 | mozjpeg: { 50 | progressive: true, 51 | }, 52 | gifsicle: { 53 | interlaced: false, 54 | }, 55 | optipng: { 56 | optimizationLevel: 4, 57 | }, 58 | pngquant: { 59 | quality: '75-90', 60 | speed: 3, 61 | }, 62 | }, 63 | }] 64 | }] 65 | }, 66 | node: { 67 | fs: 'empty' 68 | }, 69 | 70 | plugins: [ 71 | new webpack.ProvidePlugin({ 72 | $: 'jquery', 73 | jQuery: 'jquery', 74 | 'window.jQuery': 'jquery', 75 | Tether: 'tether', 76 | 'window.Tether': 'tether', 77 | Tooltip: 'exports?Tooltip!bootstrap/js/dist/tooltip', 78 | Alert: 'exports?Alert!bootstrap/js/dist/alert', 79 | Button: 'exports?Button!bootstrap/js/dist/button', 80 | Carousel: 'exports?Carousel!bootstrap/js/dist/carousel', 81 | Collapse: 'exports?Collapse!bootstrap/js/dist/collapse', 82 | Dropdown: 'exports?Dropdown!bootstrap/js/dist/dropdown', 83 | Modal: 'exports?Modal!bootstrap/js/dist/modal', 84 | Popover: 'exports?Popover!bootstrap/js/dist/popover', 85 | Scrollspy: 'exports?Scrollspy!bootstrap/js/dist/scrollspy', 86 | Tab: 'exports?Tab!bootstrap/js/dist/tab', 87 | Tooltip: 'exports?Tooltip!bootstrap/js/dist/tooltip', 88 | Util: 'exports?Util!bootstrap/js/dist/util' 89 | }) 90 | 91 | 92 | ] 93 | }; 94 | -------------------------------------------------------------------------------- /src/js/lib/xirsys.simplewebrtc.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 XirSys 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | *********************************************************************************/ 25 | 26 | 'use strict'; 27 | 28 | (function () { 29 | 30 | $xirsys.class.create({ 31 | namespace : 'simplewebrtc', 32 | // $url must include a trailing forward stroke 33 | constructor : function ($url) { 34 | var c = $xirsys.simplewebrtc; 35 | if (!!$url) { 36 | c.tokenUrl = $url + 'signal/token'; 37 | c.iceUrl = $url + 'ice'; 38 | c.roomUrl = $url + 'room'; 39 | c.wsUrl = $url + 'signal/list'; 40 | } 41 | }, 42 | fields : { 43 | connectionTypes: { 44 | default: 'default', 45 | direct: 'direct', 46 | server: 'server' 47 | }, 48 | token : "", 49 | ice : [], 50 | xirsys_opts : null 51 | }, 52 | methods : { 53 | connect : function ($opts, $rtcOpts, $resp) { 54 | this.xirsys_opts = $opts; 55 | $rtcOpts = $rtcOpts || {}; 56 | var self = this; 57 | self.xirsysRequest($xirsys.simplewebrtc.wsUrl, function ($wdata) { 58 | self.ws = $wdata.d.value; 59 | $rtcOpts.url = "ws" + self.ws.substr(2, self.ws.length); 60 | $rtcOpts.connection = new $xirsys.connection(self, null, $opts); 61 | self.ref = new SimpleWebRTC($rtcOpts); 62 | $resp.apply(self, [self.ref]); 63 | }); 64 | }, 65 | on : function ($ev, $fun) { 66 | this.ref.on($ev, $fun); 67 | }, 68 | getDomId : function ($peer) { 69 | return this.ref.getDomId($peer); 70 | }, 71 | capabilities : function () { 72 | return this.ref.capabilities; 73 | }, 74 | createRoom : function ($room, $fun) { 75 | var self = this; 76 | if (!!$room) { 77 | this.xirsys_opts.room = $room; 78 | } 79 | self.ref.createRoom($room, $fun); 80 | }, 81 | prepareRoom : function ($room) { 82 | if (!!$room) { 83 | this.prepare_room = $room; 84 | this.ref.sessionReady = true; 85 | } 86 | }, 87 | joinRoom : function ($room) { 88 | var self = this; 89 | if (!!$room) { 90 | this.xirsys_opts.room = $room; 91 | } 92 | self.ref.joinRoom($room); 93 | }, 94 | leaveRoom : function() { 95 | this.ref.leaveRoom(); 96 | }, 97 | xirsysRequest : function ($url, $cb) { 98 | var self = this; 99 | $xirsys.ajax.do({ 100 | url: $url, 101 | method: 'POST', 102 | data: self.xirsys_opts 103 | }) 104 | .done($cb); 105 | }, 106 | getLocalScreen : function () { 107 | return this.ref.getLocalScreen(); 108 | }, 109 | stopScreenShare : function () { 110 | this.ref.stopScreenShare(); 111 | }, 112 | shareScreen : function ($handle) { 113 | this.ref.shareScreen($handle); 114 | } 115 | }, 116 | statics : { 117 | tokenUrl : $xirsys.baseUrl + "signal/token", 118 | iceUrl : $xirsys.baseUrl + "ice", 119 | wsUrl : $xirsys.baseUrl + "signal/list", 120 | roomUrl : $xirsys.baseUrl + "room" 121 | } 122 | }); 123 | 124 | })(); 125 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Glaze 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |

Glaze

23 |

A simple and fast P2P audio chat

24 |
25 | 26 |
27 |
28 | 29 |
30 | glazeG 31 |
32 |
33 | 34 | 35 |
36 |
37 |
38 |
39 |

Github All Releases 40 | GitHub release 41 | license

42 |
43 | Imgur 44 | 45 |
46 | 47 |
48 |
49 | 50 |

To Download

51 | 52 |

Glaze is available for Windows, macOS, and Linux.

53 | 54 |

For the latest build (unstable):

55 | 56 |
    57 |
  1. Check out the dist directory and find your system's installer.
  2. 58 | 59 |
  3. Then just click on it and download and run it to your computer.
  4. 60 |
61 | 62 |

For the latest release (stable):

63 | 64 |
    65 |
  1. Go to the releases and find your system's installer there.
  2. 66 | 67 |
  3. Then just click on it and download and run it to your computer.
  4. 68 |
69 | 70 |

Want to hack on Glaze?

71 | 72 |
$ mkdir glaze
 73 | $ cd glaze
 74 | $ git clone https://github.com/adamsiwiec/glaze .
 75 | $ npm install
 76 | $ npm start
 77 | 
78 | 79 |

License MIT License

80 | 81 |

Glaze is made possible by:

82 | 83 | 90 |
91 |
92 | 93 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/js/lib/xirsys.simplewebrtc.connection.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 XirSys 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | ******************************************************************************** 25 | 26 | This script provides functionality for connecting to the 27 | XirSys signalling platform. 28 | 29 | No external libraries are required. However, if supporting an 30 | older browser (earlier than Internet Explorer 8, Firefox 3.1, 31 | Safari 4, and Chrome 3), then you may want to use the open 32 | source JSON library by Douglas Crockford : 33 | (https://github.com/douglascrockford/JSON-js) 34 | 35 | If using the XirSys signalling for testing, you may want to forgo 36 | using a secure server based token handler (see the XirSys example 37 | getToken.php script) for acquiring data from the XirSys service 38 | endpoints. Therefore, when connecting to the signalling, you will 39 | need to provide all the information needed by that endpoint. 40 | 41 | For example: 42 | 43 | var s = new $xirsys.signal(); 44 | s.connect({ 45 | 'username' : 'name_of_user_connecting', 46 | 'ident' : 'your_ident', 47 | 'secret' : 'your_secret_key', 48 | 'domain' : 'your_domain', 49 | 'application' : 'your_application_name', 50 | 'room' : 'your_room_name' 51 | }); 52 | 53 | However, if you wish to connect via your own token handler, then you 54 | will need to provide the URL to the class constructor, and connect 55 | only with the data needed by your token handler. 56 | 57 | var s = new $xirsys.signal("/getToken.php"); 58 | s.connect({ 59 | 'username' : 'name_of_user_connecting', 60 | 'password' : 'users_password', 61 | 'room' : 'your_room_name' 62 | }); 63 | 64 | The XirSys signal client provides a number of callback handlers for 65 | intercepting data. If you are using the signal class with one of the 66 | XirSys WebRTC classes, you will probably not need to extend many of 67 | these. However, they are there for your use. See at the end of this 68 | script for a list of these. 69 | 70 | *********************************************************************************/ 71 | 72 | 'use strict'; 73 | 74 | (function () { 75 | 76 | var cls = $xirsys.class.create({ 77 | namespace : 'connection', 78 | inherits: $xirsys.signal, 79 | constructor : function ($inst, $url, $opts) { 80 | cls.Super.constructor.call(this, $url); 81 | this.inst = $inst; 82 | this.opts = $opts || {}; 83 | this.opts.secure = $opts.secure || 1; 84 | this.peers = {}; 85 | }, 86 | methods : { 87 | disconnect: function () { 88 | this.close(); 89 | }, 90 | emit: function ($type, $payload, $cb) { 91 | switch ($type) { 92 | case 'message': 93 | if (!!$payload.to) 94 | this.send($type, $payload, $payload.to, $payload.type); 95 | else 96 | this.send($type, $payload); 97 | break; 98 | case 'create': 99 | this.createRoom($payload, $cb); 100 | break; 101 | case 'join': 102 | this.joinRoom($payload, $cb); 103 | break; 104 | case 'leave': 105 | this.disconnect(); 106 | break; 107 | default: 108 | this.send($type, $payload); 109 | } 110 | }, 111 | on: function ($evt, $fn) { 112 | $xirsys.events.getInstance().on($evt, $fn); 113 | }, 114 | getSessionid: function () { 115 | this.sessionId = this.sessionId || ((this.xirsys_opts && this.xirsys_opts.username) || new Date().getTime()); 116 | return this.sessionId; 117 | }, 118 | createRoom: function ($name, $cb) { 119 | var self = this; 120 | this.inst.xirsysRequest($xirsys.simplewebrtc.roomUrl, function ($a) { 121 | self.inst.xirsysRequest($xirsys.simplewebrtc.iceUrl, function ($i) { 122 | if (!!$i.e) { 123 | console.error("Could not get ICE string", $i.e); 124 | return; 125 | } 126 | self.setupRoom($name, $i.d.iceServers); 127 | $cb.apply(self, [(!!$a.e && $a.e != "room_exists") ? $a.e : null, $name]); 128 | }); 129 | }); 130 | }, 131 | joinRoom: function ($name, $cb) { 132 | var self = this; 133 | this.inst.xirsysRequest($xirsys.simplewebrtc.iceUrl, function ($i) { 134 | if (!!$i.e) { 135 | console.error("Could not get ICE string", $i.e); 136 | return; 137 | } 138 | self.setupRoom($name, $i.d.iceServers); 139 | self.joinCB = $cb; 140 | }); 141 | }, 142 | setupRoom: function ($room, $ice) { 143 | this.opts.room = $room; 144 | this.opts.username = this.opts.username || this.getSessionid(); 145 | this.peers = {}; 146 | this.connect(this.opts); 147 | var stun = $ice.filter(function(i) { 148 | return i.url.startsWith('stun'); 149 | }); 150 | var turn = $ice.filter(function(i) { 151 | return i.url.startsWith('turn'); 152 | }); 153 | $xirsys.events.getInstance().emit('stunservers', stun); 154 | $xirsys.events.getInstance().emit('turnservers', turn); 155 | }, 156 | getIceServers: function () { 157 | this.inst.xirsysRequest($xirsys.simplewebrtc.iceUrl, function ($idata) { 158 | var ice = $idata.d.iceServers, len = ice.length, s = [], t = []; 159 | for (var i = 0; i < len; i++) { 160 | if (ice[i].url.startsWith("stun")) 161 | s.push(ice[i]); 162 | else 163 | t.push(ice[i]); 164 | } 165 | $xirsys.events.getInstance().emit('stunservers', s); 166 | setInterval(function() { 167 | $xirsys.events.getInstance().emit('turnservers', t); 168 | }, 50); 169 | }); 170 | }, 171 | addPeer : function ($peer) { 172 | if ($peer == this.opts.username) return; 173 | for (var i in this.peers) { 174 | if (i == $peer) 175 | return; 176 | } 177 | this.peers[$peer] = {type: "video"}; 178 | }, 179 | removePeer : function ($peer) { 180 | for (var i in this.peers) { 181 | if (i == $peer) { 182 | this.peers[i] = null; 183 | return; 184 | } 185 | } 186 | }, 187 | onMessage : function ($pkt) { 188 | cls.Super.onMessage.call(); 189 | $xirsys.events.getInstance().emit($pkt.type, $pkt.data); 190 | }, 191 | onOpen : function () { 192 | cls.Super.onOpen.call(); 193 | $xirsys.events.getInstance().emit('open'); 194 | }, 195 | onPeers : function ($peers) { 196 | cls.Super.onPeers.call(this, $peers); 197 | for (var i = 0, l = $peers.users.length; i < l; i++) { 198 | this.addPeer($peers.users[i]); 199 | } 200 | if (!!this.joinCB) 201 | this.joinCB.apply(this, [null, {clients:this.peers}]); 202 | }, 203 | onPeerConnected : function ($peer) { 204 | cls.Super.onPeerConnected.call(this, $peer); 205 | this.addPeer($peer); 206 | }, 207 | onPeerRemoved : function ($peer) { 208 | cls.Super.onPeerRemoved.call(this, $peer); 209 | $xirsys.events.getInstance().emit('remove', $peer); 210 | } 211 | } 212 | }); 213 | 214 | })(); -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron') 2 | const app = electron.app 3 | const BrowserWindow = electron.BrowserWindow 4 | const Menu = electron.Menu 5 | const path = require('path') 6 | const url = require('url') 7 | const ipc = require('electron').ipcMain 8 | const autoUpdater = require("electron-updater").autoUpdater 9 | 10 | let template = [{ 11 | label: 'Edit', 12 | submenu: [{ 13 | label: 'Undo', 14 | accelerator: 'CmdOrCtrl+Z', 15 | role: 'undo' 16 | }, { 17 | label: 'Redo', 18 | accelerator: 'Shift+CmdOrCtrl+Z', 19 | role: 'redo' 20 | }, { 21 | type: 'separator' 22 | }, { 23 | label: 'Cut', 24 | accelerator: 'CmdOrCtrl+X', 25 | role: 'cut' 26 | }, { 27 | label: 'Copy', 28 | accelerator: 'CmdOrCtrl+C', 29 | role: 'copy' 30 | }, { 31 | label: 'Paste', 32 | accelerator: 'CmdOrCtrl+V', 33 | role: 'paste' 34 | }, { 35 | label: 'Select All', 36 | accelerator: 'CmdOrCtrl+A', 37 | role: 'selectall' 38 | }] 39 | }, { 40 | label: 'View', 41 | submenu: [{ 42 | label: 'Reload', 43 | accelerator: 'CmdOrCtrl+R', 44 | click: function(item, focusedWindow) { 45 | if (focusedWindow) { 46 | // on reload, start fresh and close any old 47 | // open secondary windows 48 | if (focusedWindow.id === 1) { 49 | BrowserWindow.getAllWindows().forEach(function(win) { 50 | if (win.id > 1) { 51 | win.close() 52 | } 53 | }) 54 | } 55 | focusedWindow.reload() 56 | } 57 | } 58 | }, { 59 | label: 'Toggle Full Screen', 60 | accelerator: (function() { 61 | if (process.platform === 'darwin') { 62 | return 'Ctrl+Command+F' 63 | } else { 64 | return 'F11' 65 | } 66 | })(), 67 | click: function(item, focusedWindow) { 68 | if (focusedWindow) { 69 | focusedWindow.setFullScreen(!focusedWindow.isFullScreen()) 70 | } 71 | } 72 | }, { 73 | label: 'Toggle Developer Tools', 74 | accelerator: (function() { 75 | if (process.platform === 'darwin') { 76 | return 'Alt+Command+I' 77 | } else { 78 | return 'Ctrl+Shift+I' 79 | } 80 | })(), 81 | click: function(item, focusedWindow) { 82 | if (focusedWindow) { 83 | focusedWindow.toggleDevTools() 84 | } 85 | } 86 | }, { 87 | type: 'separator' 88 | }, { 89 | label: 'App Menu Demo', 90 | click: function(item, focusedWindow) { 91 | if (focusedWindow) { 92 | const options = { 93 | type: 'info', 94 | title: 'Application Menu Demo', 95 | buttons: ['Ok'], 96 | message: 'This demo is for the Menu section, showing how to create a clickable menu item in the application menu.' 97 | } 98 | electron.dialog.showMessageBox(focusedWindow, options, function() {}) 99 | } 100 | } 101 | }] 102 | }, { 103 | label: 'Window', 104 | role: 'window', 105 | submenu: [{ 106 | label: 'Minimize', 107 | accelerator: 'CmdOrCtrl+M', 108 | role: 'minimize' 109 | }, { 110 | label: 'Close', 111 | accelerator: 'CmdOrCtrl+W', 112 | role: 'close' 113 | }, { 114 | type: 'separator' 115 | }, { 116 | label: 'Reopen Window', 117 | accelerator: 'CmdOrCtrl+Shift+T', 118 | enabled: false, 119 | key: 'reopenMenuItem', 120 | click: function() { 121 | app.emit('activate') 122 | } 123 | }] 124 | }, { 125 | label: 'Help', 126 | role: 'help', 127 | submenu: [{ 128 | label: 'Learn More', 129 | click: function() { 130 | electron.shell.openExternal('https://siwiec.us/glaze') 131 | } 132 | }] 133 | }] 134 | 135 | function addUpdateMenuItems(items, position) { 136 | if (process.mas) return 137 | 138 | const version = electron.app.getVersion() 139 | let updateItems = [{ 140 | label: `Version ${version}`, 141 | enabled: false 142 | }, { 143 | label: 'Checking for Update', 144 | enabled: false, 145 | key: 'checkingForUpdate' 146 | }, { 147 | label: 'Check for Update', 148 | visible: false, 149 | key: 'checkForUpdate', 150 | click: function() { 151 | require('electron').autoUpdater.checkForUpdates() 152 | } 153 | }, { 154 | label: 'Restart and Install Update', 155 | enabled: true, 156 | visible: false, 157 | key: 'restartToUpdate', 158 | click: function() { 159 | require('electron').autoUpdater.quitAndInstall() 160 | } 161 | }] 162 | 163 | items.splice.apply(items, [position, 0].concat(updateItems)) 164 | } 165 | 166 | function findReopenMenuItem() { 167 | const menu = Menu.getApplicationMenu() 168 | if (!menu) return 169 | 170 | let reopenMenuItem 171 | menu.items.forEach(function(item) { 172 | if (item.submenu) { 173 | item.submenu.items.forEach(function(item) { 174 | if (item.key === 'reopenMenuItem') { 175 | reopenMenuItem = item 176 | } 177 | }) 178 | } 179 | }) 180 | return reopenMenuItem 181 | } 182 | 183 | if (process.platform === 'darwin') { 184 | const name = electron.app.getName() 185 | template.unshift({ 186 | label: name, 187 | submenu: [{ 188 | label: `About ${name}`, 189 | role: 'about' 190 | }, { 191 | type: 'separator' 192 | }, { 193 | label: 'Services', 194 | role: 'services', 195 | submenu: [] 196 | }, { 197 | type: 'separator' 198 | }, { 199 | label: `Hide ${name}`, 200 | accelerator: 'Command+H', 201 | role: 'hide' 202 | }, { 203 | label: 'Hide Others', 204 | accelerator: 'Command+Alt+H', 205 | role: 'hideothers' 206 | }, { 207 | label: 'Show All', 208 | role: 'unhide' 209 | }, { 210 | type: 'separator' 211 | }, { 212 | label: 'Quit', 213 | accelerator: 'Command+Q', 214 | click: function() { 215 | app.quit() 216 | } 217 | }] 218 | }) 219 | 220 | // Window menu. 221 | template[3].submenu.push({ 222 | type: 'separator' 223 | }, { 224 | label: 'Bring All to Front', 225 | role: 'front' 226 | }) 227 | 228 | addUpdateMenuItems(template[0].submenu, 1) 229 | } 230 | 231 | if (process.platform === 'win32') { 232 | const helpMenu = template[template.length - 1].submenu 233 | addUpdateMenuItems(helpMenu, 0) 234 | } 235 | 236 | 237 | 238 | // Keep a global reference of the window object, if you don't, the window will 239 | // be closed automatically when the JavaScript object is garbage collected. 240 | let introWindow 241 | let win = null 242 | 243 | function createWindow() { 244 | // Create the browser window. 245 | introWindow = new BrowserWindow({ 246 | width: 600, 247 | height: 480, 248 | title: "Glaze", 249 | resizable: false 250 | }) 251 | // and load the index.html of the app. 252 | 253 | 254 | introWindow.loadURL(url.format({ 255 | pathname: path.join(__dirname, 'src/html/start.html'), 256 | protocol: 'file:', 257 | slashes: true 258 | })) 259 | 260 | // Emitted when the window is closed. 261 | introWindow.on('closed', function() { 262 | // Dereference the window object, usually you would store windows 263 | // in an array if your app supports multi windows, this is the time 264 | // when you should delete the corresponding element. 265 | introWindow = null 266 | }) 267 | } 268 | 269 | function createMainWindow(arg) { 270 | const htmlPath = path.join('file://', __dirname, 'src/html/index.html?room=' + arg.room + "&nick=" + arg.nick) 271 | win = new BrowserWindow({ 272 | width: 800, 273 | height: 700, 274 | title: "Glaze" 275 | }) 276 | win.on('closed', function () { 277 | win = null; 278 | }) 279 | 280 | win.loadURL(htmlPath) 281 | win.show() 282 | 283 | win.webContents.on('dom-ready', () => { 284 | 285 | 286 | autoUpdater.on('update-available', (ev, info) => { 287 | win.webContents.send('message', "Update Available") 288 | 289 | }) 290 | autoUpdater.on('download-progress', (ev, progressObj) => { 291 | win.webContents.send('message', "Download in progress") 292 | }) 293 | autoUpdater.on('update-downloaded', (ev, info) => { 294 | win.webContents.send('message', 'Update downloaded. Will quit and install in 5 seconds.'); 295 | // Wait 5 seconds, then quit and install 296 | setTimeout(function() { 297 | autoUpdater.quitAndInstall(); 298 | }, 5000) 299 | }) 300 | // Wait a second for the window to exist before checking for updates. 301 | setTimeout(function() { 302 | autoUpdater.checkForUpdates() 303 | }, 3000); 304 | }) 305 | 306 | 307 | } 308 | 309 | // This method will be called when Electron has finished 310 | // initialization and is ready to create browser windows. 311 | // Some APIs can only be used after this event occurs. 312 | app.on('ready', function() { 313 | const menu = Menu.buildFromTemplate(template) 314 | Menu.setApplicationMenu(menu) 315 | createWindow() 316 | 317 | }) 318 | 319 | // Quit when all windows are closed. 320 | app.on('window-all-closed', function() { 321 | let reopenMenuItem = findReopenMenuItem() 322 | if (reopenMenuItem) reopenMenuItem.enabled = true 323 | // On OS X it is common for applications and their menu bar 324 | // to stay active until the user quits explicitly with Cmd + Q 325 | if (process.platform !== 'darwin') { 326 | app.quit() 327 | } 328 | }) 329 | 330 | app.on('activate', function() { 331 | // On OS X it's common to re-create a window in the app when the 332 | // dock icon is clicked and there are no other windows open. 333 | if (introWindow === null && win === null) { 334 | createWindow() 335 | } 336 | }) 337 | 338 | // In this file you can include the rest of your app's specific main process 339 | // code. You can also put them in separate files and require them here. 340 | 341 | app.on('browser-window-created', function() { 342 | let reopenMenuItem = findReopenMenuItem() 343 | if (reopenMenuItem) reopenMenuItem.enabled = false 344 | }) 345 | 346 | 347 | 348 | ipc.on('close-starter', function(event, arg) { 349 | createMainWindow(arg); 350 | }) 351 | 352 | 353 | 354 | 355 | 356 | function sendStatus(text) { 357 | log.info(text); 358 | win.webContents.on('dom-ready', () => { 359 | win.webContents.send('message', text); 360 | 361 | }) 362 | } 363 | 364 | function getWindow(windowName) { 365 | for (var i = 0; i < windowArray.length; i++) { 366 | if (windowArray[i].name == windowName) { 367 | return windowArray[i].window; 368 | } 369 | } 370 | return null; 371 | } 372 | -------------------------------------------------------------------------------- /src/js/lib/xirsys.core.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 XirSys 5 | 6 | @author: Lee Sylvester 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | *********************************************************************************/ 27 | 28 | var $xirsys = { 29 | class : {}, 30 | baseUrl : "https://service.xirsys.com/" 31 | }; 32 | 33 | (function () { 34 | 35 | $xirsys.extend = function (dest, src) { 36 | for (var prop in src) { 37 | if (typeof src[prop] === "object" && src[prop] !== null) { 38 | dest[prop] = dest[prop] || {}; 39 | arguments.callee(dest[prop], src[prop]); 40 | } else { 41 | dest[prop] = src[prop]; 42 | } 43 | } 44 | return dest; 45 | }; 46 | 47 | $xirsys.isArray = function ($val) { 48 | return (!!$val) ? 49 | $val.constructor == Array : false; 50 | }; 51 | 52 | $xirsys.isString = function ($val) { 53 | return (typeof $val == 'string'); 54 | }; 55 | 56 | $xirsys.class.create = function( param ) { 57 | var i, namespace, m, part, n, 58 | segs = [], f = function(){}, ctor = {}, e = {}, o = {}, 59 | t = $xirsys, 60 | h = Object.prototype.hasOwnProperty; 61 | if ( !param ) { 62 | return function() {}; 63 | } 64 | namespace = param.namespace; 65 | if ( !namespace ) { 66 | throw new Error( "Please specify the Namespace." ); 67 | } 68 | if ( 69 | namespace.length == 0 || 70 | namespace.indexOf( " " ) != -1 || 71 | namespace.charAt( 0 ) == '.' || 72 | namespace.charAt( namespace.length - 1 ) == '.' || 73 | namespace.indexOf( ".." ) != -1 74 | ) { 75 | throw new Error( "Illegal Namespace: " + namespace ); 76 | } 77 | segs = namespace.split( '.' ); 78 | for ( i = 0; i < segs.length; i++ ) { 79 | if ( !!t ) t = t[segs[i]]; 80 | } 81 | if ( !!t ) { 82 | return t; 83 | } 84 | if ( h.call( param, 'constructor' ) ) { 85 | if ( typeof param.constructor != "function" ) { 86 | throw new TypeError("Illegal function [" + namespace + ".constructor]!"); 87 | } 88 | f = param.constructor; 89 | } 90 | if ( param['inherits'] ) { 91 | this['inherits'] = function ( c, p ) { 92 | for ( m in p) { 93 | if ( h.call( p, m ) ) { 94 | c[m] = p[m]; 95 | } 96 | } 97 | ctor = function () { this.constructor = c; }; 98 | ctor.prototype = p.prototype; 99 | c.prototype = new ctor(); 100 | c.__super__ = c.Super = p.prototype; 101 | m = p = ctor = c = null; // release memory 102 | }; 103 | this['inherits']( f, param['inherits'] ); 104 | } 105 | e = function( obj, params, isStatic ) { 106 | for ( m in params ) { 107 | if ( h.call( params, m ) ) { 108 | if (!isStatic) { 109 | obj.prototype[m] = params[m]; 110 | } else { 111 | obj[m] = params[m]; 112 | } 113 | } 114 | } 115 | }; 116 | if ( param.methods ) { 117 | e( f, param.methods ); 118 | } 119 | if ( !param.fields ) { 120 | param.fields = {}; 121 | } 122 | param.fields.className = namespace; 123 | e( f, param.fields ); 124 | if ( param.statics ) { 125 | e( f, param.statics, true ); 126 | } 127 | if ( param.props ) { // styles 128 | o = f.prototype.props = $.extend( true, {}, f.prototype.props ); 129 | e( o, $.extend( true, {}, param.props ), true ); 130 | } 131 | // create the specified namespace and append the class to it. 132 | t = $xirsys; 133 | for( i = 0; i < segs.length - 1; i++ ) { 134 | part = segs[i]; 135 | // If there is no property of t with this name, create an empty object. 136 | if (!t[part]) { 137 | t[part] = {}; 138 | } else if (typeof t[part] != "object") { 139 | // If there is already a property, make sure it is an object 140 | n = segs.slice(0, i).join('.'); 141 | throw new Error(n + " already exists and is not an object"); 142 | } 143 | t = t[part]; 144 | } 145 | t[segs[segs.length - 1]] = f; 146 | namespace = segs = h = t = e = i = null; // release memory 147 | return f; 148 | }; 149 | 150 | $xirsys.class.create ({ 151 | namespace : 'ajax', 152 | fields : { 153 | host : {}, 154 | xhr : null 155 | }, 156 | methods : { 157 | request : function ($opts) { 158 | if (typeof $opts == 'string') { 159 | $opts = { url: $opts }; 160 | } 161 | $opts.url = $opts.url || ''; 162 | $opts.method = $opts.method || 'get'; 163 | $opts.data = $opts.data || {}; 164 | return this.process($opts); 165 | }, 166 | getParams : function ($data, $url) { 167 | var arr = [], str; 168 | for (var n in $data) { 169 | arr.push(n + '=' + encodeURIComponent($data[n])); 170 | } 171 | str = arr.join('&'); 172 | if (str != '') { 173 | return $url ? ($url.indexOf('?') < 0 ? '?' + str : '&' + str) : str; 174 | } 175 | return ''; 176 | }, 177 | extend : $xirsys.extend, 178 | done : function ($cb) { 179 | this.doneCallback = $cb; 180 | return this; 181 | }, 182 | fail : function ($cb) { 183 | this.failCallback = $cb; 184 | return this; 185 | }, 186 | always : function ($cb) { 187 | this.alwaysCallback = $cb; 188 | return this; 189 | }, 190 | setHeaders : function ($headers) { 191 | for (var n in $headers) { 192 | this.xhr && this.xhr.setRequestHeader(n, $headers[n]); 193 | } 194 | }, 195 | process : function ($opts) { 196 | var self = this; 197 | if (window.ActiveXObject) { 198 | this.xhr = new ActiveXObject('Microsoft.XMLHTTP'); 199 | } else if (window.XMLHttpRequest) { 200 | this.xhr = new XMLHttpRequest(); 201 | } 202 | if (this.xhr) { 203 | this.xhr.onreadystatechange = function () { 204 | if (self.xhr.readyState == 4 && self.xhr.status >= 200 && self.xhr.status < 300) { 205 | var result = self.xhr.responseText; 206 | if ((!$opts.json || $opts.json === true) && typeof JSON != 'undefined') { 207 | result = JSON.parse(result); 208 | } 209 | self.doneCallback && self.doneCallback.apply(self.host, [result, self.xhr]); 210 | } else if (self.xhr.readyState == 4) { 211 | self.failCallback && self.failCallback.apply(self.host, [self.xhr]); 212 | } 213 | self.alwaysCallback && self.alwaysCallback.apply(self.host, [self.xhr]); 214 | } 215 | } 216 | if ($opts.method.toLowerCase() == 'get') { 217 | this.xhr.open("GET", $opts.url + self.getParams($opts.data, $opts.url), true); 218 | } else { 219 | this.xhr.open($opts.method, $opts.url, true); 220 | this.setHeaders({ 221 | 'X-Requested-With': 'XMLHttpRequest', 222 | 'Content-Type': 'application/json' 223 | }); 224 | } 225 | if ($opts.headers && typeof $opts.headers == 'object') { 226 | this.setHeaders($opts.headers); 227 | } 228 | setTimeout (function () { 229 | $opts.method == 'get' ? self.xhr.send() : self.xhr.send(self.getParams($opts.data)); 230 | }, 20); 231 | return this; 232 | } 233 | }, 234 | statics : { 235 | inst : null, 236 | do : function ($opts) { 237 | var a = new $xirsys.ajax(); 238 | return a.request($opts); 239 | } 240 | } 241 | }); 242 | 243 | /** 244 | * Events class 245 | * Events collecting and notifications functions. 246 | **/ 247 | 248 | $xirsys.class.create ({ 249 | namespace : 'events', 250 | fields : { 251 | delimiter : '.', 252 | wildcard : '*', 253 | _stack : {} 254 | }, 255 | methods : { 256 | // Add an individual listener handler. 257 | on : function ($evt, $handler) { 258 | var pntr = $xirsys.events.getInstance()._getNamespaceSegment($evt); 259 | if (!this.has($evt, $handler)) { 260 | pntr._handlers.push($handler); 261 | } 262 | }, 263 | // Remove a listener handler. 264 | remove : function ($evt, $handler) { 265 | var $pntr = $xirsys.events.getInstance()._getNamespaceSegment($evt); 266 | $pntr._handlers = $pntr._handlers || []; 267 | for (var i = 0; i < $pntr._handlers.length; i++) { 268 | if ($pntr._handlers[i] == $handler || $handler === -1) { 269 | $pntr._handlers.splice(i); 270 | return; 271 | } 272 | } 273 | }, 274 | // Removes all listeners for a given event 275 | flush : function ($events) { 276 | if ($xirsys.isArray($events)) { 277 | for (var i = 0; i < $events.length; i++) { 278 | if (!!$events[i]) { 279 | this.removeAllListeners($events[i]); 280 | } 281 | } 282 | } else { 283 | if (!!$events[i]) { //todo: what does it mean? 284 | this.removeListener($events[i], -1); 285 | } 286 | } 287 | }, 288 | // Check for a listener, returning true or false. 289 | has : function ($evt, $handler) { 290 | if (!$handler || typeof $handler != 'function') { 291 | throw 'Event handler must be supplied as a function'; 292 | } 293 | var pntr = $xirsys.events.getInstance()._getNamespaceSegment ($evt); 294 | if (!pntr._handlers) { 295 | pntr._handlers = []; 296 | } 297 | var f = false; 298 | for (var t = 0; t < pntr._handlers.length; t++) { 299 | if (pntr._handlers[t] == $handler) f = true; 300 | } 301 | return f; 302 | }, 303 | emit : function ($evt /* additional params will be passed to event handlers */) { 304 | var pntr = $xirsys.events.getInstance()._getNamespaceSegment($evt, true), 305 | args = Array.prototype.slice.call(arguments, 0); 306 | args.shift(); 307 | for (var i = 0; i < pntr.length; i++) { 308 | for (var j = 0; j < pntr[i]._handlers.length; j++) { 309 | pntr[i]._handlers[j].apply(this, args); 310 | } 311 | } 312 | }, 313 | // Splits down the passed events into constituent segments, seperated by periods. 314 | _getNamespaceSegment : function ($evt, $includeWildcards, $arr) { 315 | var e = $xirsys.isString($evt) ? 316 | $evt.split(this.delimiter) : $xirsys.isArray($evt) ? 317 | $evt : null; 318 | 319 | if (!e) { 320 | throw 'Event listener assigned to unknown type'; 321 | } 322 | 323 | var pntr = this._stack; 324 | for (var i = 0; i < e.length; i++) { 325 | if (!$xirsys.isString(e[i])) { 326 | throw 'Event identifier segment not a string value'; 327 | } 328 | if (e[i] == "_handlers" || (e[i] == this.wildcard && i < e.length - 1)) { 329 | throw 'Invalid name used in event namespace.'; 330 | } 331 | pntr = pntr[e[i]] = pntr[e[i]] || {}; 332 | } 333 | 334 | pntr._handlers = pntr._handlers || []; 335 | if ($includeWildcards) { 336 | if (!$arr || !$xirsys.isArray($arr)) { 337 | $arr = []; 338 | } 339 | $arr.push(pntr); 340 | 341 | if (e[e.length - 1] == this.wildcard) { 342 | e.pop(); 343 | } 344 | 345 | if (e.length > 0) { 346 | e.pop(); 347 | e.push(this.wildcard); 348 | this._getNamespaceSegment(e, $includeWildcards, $arr); 349 | } 350 | return $arr; 351 | } 352 | return pntr; 353 | } 354 | }, 355 | statics : { 356 | _instance : null, 357 | getInstance : function () { 358 | return $xirsys.events._instance = $xirsys.events._instance || new $xirsys.events(); 359 | } 360 | } 361 | }); 362 | 363 | })(); 364 | -------------------------------------------------------------------------------- /src/js/lib/xirsys.signal.js: -------------------------------------------------------------------------------- 1 | /********************************************************************************* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 XirSys 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | ******************************************************************************** 25 | 26 | This script provides functionality for connecting to the 27 | XirSys signalling platform. 28 | 29 | No external libraries are required. However, if supporting an 30 | older browser (earlier than Internet Explorer 8, Firefox 3.1, 31 | Safari 4, and Chrome 3), then you may want to use the open 32 | source JSON library by Douglas Crockford : 33 | (https://github.com/douglascrockford/JSON-js) 34 | 35 | If using the XirSys signalling for testing, you may want to forgo 36 | using a secure server based token handler (see the XirSys example 37 | getToken.php script) for acquiring data from the XirSys service 38 | endpoints. Therefore, when connecting to the signalling, you will 39 | need to provide all the information needed by that endpoint. 40 | 41 | For example: 42 | 43 | var s = new $xirsys.signal(); 44 | s.connect({ 45 | 'username' : 'name_of_user_connecting', 46 | 'ident' : 'your_ident', 47 | 'secret' : 'your_secret_key', 48 | 'domain' : 'your_domain', 49 | 'application' : 'your_application_name', 50 | 'room' : 'your_room_name' 51 | }); 52 | 53 | However, if you wish to connect via your own token handler, then you 54 | will need to provide the URL to the class constructor, and connect 55 | only with the data needed by your token handler. 56 | 57 | var s = new $xirsys.signal("/getToken.php"); 58 | s.connect({ 59 | 'username' : 'name_of_user_connecting', 60 | 'password' : 'users_password', 61 | 'room' : 'your_room_name' 62 | }); 63 | 64 | The XirSys signal client provides a number of callback handlers for 65 | intercepting data. If you are using the signal class with one of the 66 | XirSys WebRTC classes, you will probably not need to extend many of 67 | these. However, they are there for your use. See at the end of this 68 | script for a list of these. 69 | 70 | *********************************************************************************/ 71 | 72 | 'use strict'; 73 | 74 | (function () { 75 | 76 | /* 77 | The following class is a heavily modified version of the bullet script. 78 | Copyright (c) 2011-2012, Loïc Hoguin 79 | */ 80 | 81 | $xirsys.class.create({ 82 | namespace : 'socket', 83 | constructor : function ($url, $httpUrl, $options) { 84 | this.url = $url; 85 | this.httpUrl = (!!$httpUrl) ? $httpUrl : $url.replace('ws:', 'http:').replace('wss:', 'https:'); 86 | this.options = $xirsys.extend(this.options, $options); 87 | this.openSocket(); 88 | }, 89 | fields : { 90 | isClosed : true, 91 | readyState : 3, 92 | url : "", 93 | httpUrl : "", 94 | options : {}, 95 | transport : null, 96 | tn : 0 97 | }, 98 | methods : { 99 | xhrSend : function ($data) { 100 | if (this.readyState != $xirsys.signal.CONNECTING && this.readyState != $xirsys.signal.OPEN) { 101 | return false 102 | } 103 | var self = this; 104 | $xirsys.ajax.do({ 105 | url: self.httpUrl, 106 | method: 'POST', 107 | data: $data, 108 | headers: { 109 | 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf-8', 110 | 'X-Socket-Transport' : 'xhrPolling' 111 | } 112 | }) 113 | .done(function ($data) { 114 | if ($data && $data.length !== 0) { 115 | self.onmessage({'data': $data}); 116 | } 117 | }); 118 | return true; 119 | }, 120 | websocket : function () { 121 | if (!!this.options && this.options.disableWebSocket) { 122 | return false; 123 | } 124 | if (window.WebSocket) { 125 | this.transport = window.WebSocket; 126 | } 127 | if (window.MozWebSocket && navigator.userAgent.indexOf("Firefox/6.0") == -1) { 128 | this.transport = window.MozWebSocket; 129 | } 130 | if (!!this.transport) { 131 | return {'heart': true, 'transport': this.transport}; 132 | } 133 | return null; 134 | }, 135 | eventPolling : function () { 136 | if (!!this.options && this.options.disableEventSource) { 137 | return false; 138 | } 139 | if (!window.EventSource) { 140 | return false; 141 | } 142 | var source = new window.EventSource(this.httpUrl); 143 | source.onopen = function () { 144 | fake.readyState = $xirsys.signal.OPEN; 145 | fake.onopen(); 146 | }; 147 | source.onmessage = function ($event) { 148 | fake.onmessage($event); 149 | }; 150 | source.onerror = function () { 151 | source.close(); 152 | source = undefined; 153 | fake.onerror(); 154 | }; 155 | var fake = { 156 | readyState: $xirsys.signal.CONNECTING, 157 | send: this.xhrSend, 158 | close: function () { 159 | fake.readyState = $xirsys.signal.CLOSED; 160 | source.close(); 161 | source = undefined; 162 | fake.onclose(); 163 | } 164 | }; 165 | return {'heart': false, 'transport': function () { 166 | return fake; 167 | }}; 168 | }, 169 | xhrPolling : function () { 170 | if (!!this.options && this.options.disableXHRPolling) { 171 | return false; 172 | } 173 | var timeout; 174 | var xhr = null; 175 | var fake = { 176 | readyState: $xirsys.signal.CONNECTING, 177 | send: xhrSend, 178 | close: function () { 179 | this.readyState = $xirsys.signal.CLOSED; 180 | if (xhr) { 181 | xhr.abort(); 182 | xhr = null; 183 | } 184 | clearTimeout(timeout); 185 | fake.onclose(); 186 | }, 187 | onopen: function () {}, 188 | onmessage: function () {}, 189 | onerror: function () {}, 190 | onclose: function () {} 191 | }; 192 | self.nextPoll(); 193 | return {'heart': false, 'transport': function () { 194 | return fake; 195 | }}; 196 | }, 197 | poll : function () { 198 | xhr = $xirsys.ajax.do({ 199 | url: this.httpUrl, 200 | method: 'GET', 201 | data: {}, 202 | headers: {'X-Socket-Transport' : 'xhrPolling'} 203 | }) 204 | .done(function ($data) { 205 | xhr = null; 206 | if (fake.readyState == $xirsys.signal.CONNECTING) { 207 | fake.readyState = $xirsys.signal.OPEN; 208 | fake.onopen(fake); 209 | } 210 | if ($data && $data.length !== 0) { 211 | fake.onmessage({'data' : $data}); 212 | } 213 | if (fake.readyState == $xirsys.signal.OPEN) { 214 | this.nextPoll(); 215 | } 216 | }) 217 | .fail(function (xhr) { 218 | xhr = null; 219 | fake.onerror(); 220 | }); 221 | }, 222 | nextPoll : function () { 223 | timeout = setTimeout(function () { 224 | this.poll(); 225 | }, 100); 226 | }, 227 | next : function () { 228 | var c = 0, 229 | s = { 230 | websocket: this.websocket, 231 | eventPolling : this.eventPolling, 232 | xhrPolling : this.xhrPolling 233 | }; 234 | for (var f in s) { 235 | if (this.tn == c) { 236 | var t = s[f](); 237 | if (t) { 238 | var ret = new t.transport(this.url); 239 | ret.heart = t.heart; 240 | return ret; 241 | } 242 | this.tn++; 243 | } 244 | c++; 245 | } 246 | return false; 247 | }, 248 | openSocket : function () { 249 | var self = this, 250 | heartbeat, 251 | delay = 80, 252 | delayDefault = 80, 253 | delayMax = 10000; 254 | 255 | 256 | self.readyState = $xirsys.signal.CLOSED, 257 | self.isClosed = true; 258 | 259 | function init() { 260 | self.isClosed = false; 261 | self.readyState = $xirsys.signal.CONNECTING; // Should this be readyState or self.readyState? 262 | self.transport = self.next(); 263 | 264 | if (!self.transport) { 265 | delay = delayDefault; 266 | self.tn = 0; 267 | self.ondisconnect(); 268 | setTimeout(function () {init();}, delayMax); 269 | return false; 270 | } 271 | 272 | self.transport.onopen = function () { 273 | delay = delayDefault; 274 | 275 | if (self.transport.heart) { 276 | heartbeat = setInterval(function () { 277 | self.send('ping'); 278 | self.onheartbeat(); 279 | }, 20000); 280 | } 281 | 282 | if (self.readyState != $xirsys.signal.OPEN) { 283 | self.readyState = $xirsys.signal.OPEN; // Should this be readyState or self.readyState? 284 | self.onopen(); 285 | } 286 | }; 287 | self.transport.onclose = function () { 288 | if (self.isClosed || self.readyState == $xirsys.signal.CLOSED) { 289 | return; 290 | } 291 | 292 | self.transport = null; 293 | clearInterval(heartbeat); 294 | 295 | if (self.readyState == $xirsys.signal.CLOSING) { 296 | self.readyState = $xirsys.signal.CLOSED; 297 | self.transport = false; 298 | self.onclose(); 299 | } else{ 300 | if (self.readyState == $xirsys.signal.CONNECTING) { 301 | self.tn++; 302 | } 303 | delay *= 2; 304 | if (delay > delayMax) { 305 | delay = delayMax; 306 | } 307 | self.isClosed = true; 308 | setTimeout(function () { 309 | init(); 310 | }, delay); 311 | } 312 | }; 313 | self.transport.onerror = function ($e) { 314 | self.onerror($e); 315 | }; 316 | self.transport.onmessage = function ($e) { 317 | self.onmessage($e); 318 | }; 319 | } 320 | init(); 321 | 322 | this.onopen = function () {}; 323 | this.onmessage = function () {}; 324 | this.ondisconnect = function () {}; 325 | this.onclose = function () {}; 326 | this.onheartbeat = function () {}; 327 | this.onerror = function () {}; 328 | }, 329 | send : function ($data) { 330 | if (!!this.transport) { 331 | return this.transport.send($data); 332 | } else { 333 | return false; 334 | } 335 | }, 336 | close : function () { 337 | this.readyState = $xirsys.signal.CLOSING; 338 | if (this.transport) { 339 | this.transport.close(); 340 | } 341 | }, 342 | setURL : function ($newURL) { 343 | this.url = $newURL; 344 | } 345 | }, 346 | statics : { 347 | CONNECTING : 0, 348 | OPEN : 1, 349 | CLOSING : 2, 350 | CLOSED : 3 351 | } 352 | }); 353 | 354 | /********************************************************************************* 355 | * For full use of this class, see the information at the top of this script. 356 | *********************************************************************************/ 357 | 358 | $xirsys.class.create({ 359 | namespace : 'signal', 360 | constructor : function ($url) { 361 | if (!!$url) { 362 | $xirsys.signal.wsList = $url + "signal/list?secure=0"; 363 | $xirsys.signal.tokenUrl = $url + "signal/token"; 364 | } 365 | }, 366 | inherits : $xirsys.socket, 367 | fields : { 368 | token : "", 369 | wsUrl : "", 370 | sock : null, 371 | xirsys_opts : null, 372 | room_key : '' 373 | }, 374 | methods : { 375 | connect : function ($opts) { 376 | var self = this; 377 | this.room_key = "/" + $opts.domain +"/" + $opts.application + "/" + $opts.room; 378 | this.xirsys_opts = $opts; 379 | self.getToken(null, null, function (td) { 380 | self.getSocketEndpoints(function (sd) { 381 | self.sock = new $xirsys.socket(sd + "/" + td); //, {disableWebsocket:true, disableEventSource:true}); 382 | self.sock.onmessage = self.handleService.bind(self); 383 | self.sock.onopen = self.onOpen.bind(self); 384 | self.sock.ondisconnect = self.onDisconnect.bind(self); 385 | self.sock.onclose = self.onClose.bind(self); 386 | self.sock.onerror = self.onError.bind(self); 387 | }); 388 | }); 389 | }, 390 | close : function () { 391 | this.sock.close(); 392 | }, 393 | send : function ($event, $data, $targetUser, $type) { 394 | var service_pkt = { 395 | t: "u", // user message service 396 | m: { 397 | f: this.room_key + "/" + this.xirsys_opts.username, 398 | t: $targetUser, 399 | o: $event 400 | }, 401 | p: $data 402 | } 403 | if (!!$type && ($type == "pub" || $type == "sub")) { 404 | service_pkt.t = "tm"; 405 | service_pkt.m.o = $type; 406 | } 407 | 408 | var pkt = JSON.stringify(service_pkt) 409 | this.sock.send(pkt); 410 | }, 411 | // signal_mcu: function ($event,$targetUser) { 412 | // var service_pkt = { 413 | // t: "tm" // turn mcu 414 | // p: { 415 | // f: this.room_key + "/" + this.xirsys_opts.username, 416 | // t: $targetUser, 417 | // }, 418 | // m: $event 419 | // } 420 | // var pkt = JSON.stringify(service_pkt) 421 | // console.log("sending mcu "+pkt); 422 | // this.sock.send(pkt); 423 | // }, 424 | handleService: function (evt) { 425 | var pkt = JSON.parse(evt.data); 426 | if (!pkt.t) { 427 | this.onError({message : "invalid message received", data : pkt}); 428 | } 429 | switch (pkt.t) { 430 | case "u": 431 | //user signal 432 | this.handleUserService(pkt); 433 | break; 434 | case "tm": 435 | // turn mcu packet 436 | this.handleMCUAck(pkt); 437 | break; 438 | default: 439 | console.log("don't know this packet type "+pkt.t); 440 | } 441 | }, 442 | handleUserService : function (pkt) { 443 | //console.log('handleUserService ',pkt); 444 | var peer = null; 445 | if (pkt.m.f) { 446 | peer = pkt.m.f.split("/"); 447 | peer = peer[peer.length -1]; 448 | } 449 | switch (pkt.m.o) { 450 | case "peers": 451 | this.onPeers(pkt.p); 452 | break; 453 | case "peer_connected": 454 | this.onPeerConnected(pkt.m.f); 455 | break; 456 | case "peer_removed": 457 | this.onPeerRemoved(peer); 458 | break; 459 | default: 460 | this.onMessage({type:pkt.m.o, sender:pkt.m.f, data:pkt.p, peer:peer}); 461 | break; 462 | } 463 | }, 464 | handleMCUAck : function (pkt) { 465 | console.log("got an ack from MCU"); 466 | }, 467 | getToken : function ($url, $data, $cb) { 468 | var self = this; 469 | $xirsys.ajax.do({ 470 | url: $url || $xirsys.signal.tokenUrl, 471 | method: 'POST', 472 | data: $data || self.xirsys_opts 473 | }) 474 | .done(function ($data) { 475 | if (!!$data.e) { 476 | self.onError($data.e); 477 | return; 478 | } 479 | self.token = $data.d.token; 480 | $cb.apply(this, [self.token]); 481 | }); 482 | }, 483 | getSocketEndpoints : function ($cb) { 484 | var self = this; 485 | var p = $xirsys.ajax.do({ 486 | url: $xirsys.signal.wsList, 487 | method: 'GET', 488 | data: {} 489 | }) 490 | .done(function ($data) { 491 | if (!!$data.e) { 492 | self.onError($data.e); 493 | return; 494 | } 495 | self.wsUrl = $data.d.value + "/v2"; 496 | $cb.apply(this, [self.wsUrl]); 497 | }); 498 | }, 499 | /********************************************************************************* 500 | * Any of these handlers may be overidden for your own functionality. 501 | *********************************************************************************/ 502 | onOpen : function () { 503 | $xirsys.events.getInstance().emit($xirsys.signal.open); 504 | }, 505 | onPeers : function ($peers) { 506 | $xirsys.events.getInstance().emit($xirsys.signal.peers, $peers); 507 | }, 508 | onPeerConnected : function ($peer) { 509 | $xirsys.events.getInstance().emit($xirsys.signal.peerConnected, $peer); 510 | }, 511 | onPeerRemoved : function ($peer) { 512 | $xirsys.events.getInstance().emit($xirsys.signal.peerRemoved, $peer); 513 | }, 514 | onMessage : function ($msg) { 515 | $xirsys.events.getInstance().emit($xirsys.signal.message, $msg); 516 | }, 517 | onDisconnect : function () { 518 | $xirsys.events.getInstance().emit($xirsys.signal.disconnected); 519 | }, 520 | onClose : function () { 521 | $xirsys.events.getInstance().emit($xirsys.signal.closed); 522 | }, 523 | onError : function ($error) { 524 | $xirsys.events.getInstance().emit($xirsys.signal.error, $error); 525 | } 526 | /*********************************************************************************/ 527 | }, 528 | statics : { 529 | wsList : $xirsys.baseUrl + "signal/list?secure=1", 530 | tokenUrl : $xirsys.baseUrl + "signal/token", 531 | /* events */ 532 | open : "signalling.open", 533 | peers : "signalling.peers", 534 | peerConnected : "signalling.peer.connected", 535 | peerRemoved : "signalling.peer.removed", 536 | message : "signalling.message", 537 | disconnected : "signalling.disconnected", 538 | closed : "signalling.closed", 539 | error : "signalling.error" 540 | } 541 | }); 542 | 543 | })(); 544 | -------------------------------------------------------------------------------- /src/js/app.bundle.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="src/js/",t(t.s=0)}([function(e,t,n){n(1),n(6),n(8)},function(e,t,n){var r=n(2);"string"==typeof r&&(r=[[e.i,r,""]]);var i={hmr:!0};i.transform=void 0,n(4)(r,i),r.locals&&(e.exports=r.locals)},function(e,t,n){t=e.exports=n(3)(void 0),t.push([e.i,"a,h4,h5,p{font-family:Lato,sans-serif}*{text-shadow:rgba(0,0,0,.01) 0 0 1px}.room-container{height:100vh;background-color:#fdfdfd;margin:0}pre{background-color:green}.right-status-container{//border-left:1px solid gray;height:100vh;padding:0}#avatar{height:70vh;background-color:#0275d8}#status-container{height:30vh;background-color:#d3d3d3}#status{overflow:auto}.avatar-div{background-color:#d3d3d3;opacity:.95;height:200px;display:flex;flex-direction:column;justify-content:center}#me{position:absolute;bottom:0;left:10px}#me,a{color:#d3d3d3}a:active,a:hover,a:link,a:visited{color:#d3d3d3;text-decoration:none}.heart{height:30px;width:30px}.message{position:absolute;right:10px;bottom:15px;background-color:#ffb732;padding:5px;font-size:12px}",""])},function(e,t){function n(e,t){var n=e[1]||"",i=e[3];if(!i)return n;if(t&&"function"==typeof btoa){var o=r(i);return[n].concat(i.sources.map(function(e){return"/*# sourceURL="+i.sourceRoot+e+" */"})).concat([o]).join("\n")}return[n].join("\n")}function r(e){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(e))))+" */"}e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var r=n(t,e);return t[2]?"@media "+t[2]+"{"+r+"}":r}).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},i=0;i=0&&x.splice(t,1)}function s(e){var t=document.createElement("style");return e.attrs.type="text/css",c(t,e.attrs),o(e,t),t}function u(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",c(t,e.attrs),o(e,t),t}function c(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function l(e,t){var n,r,i,o;if(t.transform&&e.css){if(!(o=t.transform(e.css)))return function(){};e.css=o}if(t.singleton){var c=y++;n=m||(m=s(t)),r=f.bind(null,n,c,!1),i=f.bind(null,n,c,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=u(t),r=d.bind(null,n,t),i=function(){a(n),n.href&&URL.revokeObjectURL(n.href)}):(n=s(t),r=p.bind(null,n),i=function(){a(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else i()}}function f(e,t,n,r){var i=n?"":r.css;if(e.styleSheet)e.styleSheet.cssText=w(t,i);else{var o=document.createTextNode(i),a=e.childNodes;a[t]&&e.removeChild(a[t]),a.length?e.insertBefore(o,a[t]):e.appendChild(o)}}function p(e,t){var n=t.css,r=t.media;if(r&&e.setAttribute("media",r),e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}function d(e,t,n){var r=n.css,i=n.sourceMap,o=void 0===t.convertToAbsoluteUrls&&i;(t.convertToAbsoluteUrls||o)&&(r=b(r)),i&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(i))))+" */");var a=new Blob([r],{type:"text/css"}),s=e.href;e.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}var h={},g=function(e){var t;return function(){return void 0===t&&(t=e.apply(this,arguments)),t}}(function(){return window&&document&&document.all&&!window.atob}),v=function(e){var t={};return function(n){if(void 0===t[n]){var r=e.call(this,n);if(r instanceof window.HTMLIFrameElement)try{r=r.contentDocument.head}catch(e){r=null}t[n]=r}return t[n]}}(function(e){return document.querySelector(e)}),m=null,y=0,x=[],b=n(5);e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");t=t||{},t.attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||(t.singleton=g()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=i(e,t);return r(n,t),function(e){for(var o=[],a=0;a"+t.nick+" Joined!

"),r("#avatar").append("

"+t.nick+"

"),r(".chat-count").text(s)}),i.on("videoRemoved",function(e,t){s-=1,r("#status").append("

"+t.nick+" left!

"),r("."+t.nick).remove(),r(".chat-count").text(s)})}console.log(e);var i=new $xirsys.simplewebrtc;i.connect(xirsysConnect.data,{autoRequestMedia:!0,media:{video:!1,audio:!0},recieveMedia:{video:!1,audio:!0},nick:a,detectSpeakingEvents:!1,autoAdjustMic:!1},n)})})},function(e,t,n){var r,i;/*! 2 | * jQuery JavaScript Library v3.2.1 3 | * https://jquery.com/ 4 | * 5 | * Includes Sizzle.js 6 | * https://sizzlejs.com/ 7 | * 8 | * Copyright JS Foundation and other contributors 9 | * Released under the MIT license 10 | * https://jquery.org/license 11 | * 12 | * Date: 2017-03-20T18:59Z 13 | */ 14 | !function(t,n){"use strict";"object"==typeof e&&"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,function(n,o){"use strict";function a(e,t){t=t||ae;var n=t.createElement("script");n.text=e,t.head.appendChild(n).parentNode.removeChild(n)}function s(e){var t=!!e&&"length"in e&&e.length,n=ye.type(e);return"function"!==n&&!ye.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}function u(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}function c(e,t,n){return ye.isFunction(t)?ye.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?ye.grep(e,function(e){return e===t!==n}):"string"!=typeof t?ye.grep(e,function(e){return fe.call(t,e)>-1!==n}):Ne.test(t)?ye.filter(t,e,n):(t=ye.filter(t,e),ye.grep(e,function(e){return fe.call(t,e)>-1!==n&&1===e.nodeType}))}function l(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function f(e){var t={};return ye.each(e.match(Oe)||[],function(e,n){t[n]=!0}),t}function p(e){return e}function d(e){throw e}function h(e,t,n,r){var i;try{e&&ye.isFunction(i=e.promise)?i.call(e).done(t).fail(n):e&&ye.isFunction(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}function g(){ae.removeEventListener("DOMContentLoaded",g),n.removeEventListener("load",g),ye.ready()}function v(){this.expando=ye.expando+v.uid++}function m(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:We.test(e)?JSON.parse(e):e)}function y(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(Be,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n=m(n)}catch(e){}Ie.set(e,t,n)}else n=void 0;return n}function x(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return ye.css(e,t,"")},u=s(),c=n&&n[3]||(ye.cssNumber[t]?"":"px"),l=(ye.cssNumber[t]||"px"!==c&&+u)&&Ue.exec(ye.css(e,t));if(l&&l[3]!==c){c=c||l[3],n=n||[],l=+u||1;do{o=o||".5",l/=o,ye.style(e,t,l+c)}while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(l=+l||+u||0,i=n[1]?l+(n[1]+1)*n[2]:+n[2],r&&(r.unit=c,r.start=l,r.end=i)),i}function b(e){var t,n=e.ownerDocument,r=e.nodeName,i=Ve[r];return i||(t=n.body.appendChild(n.createElement(r)),i=ye.css(t,"display"),t.parentNode.removeChild(t),"none"===i&&(i="block"),Ve[r]=i,i)}function w(e,t){for(var n,r,i=[],o=0,a=e.length;o-1)i&&i.push(o);else if(c=ye.contains(o.ownerDocument,o),a=T(f.appendChild(o),"script"),c&&C(a),n)for(l=0;o=a[l++];)Ye.test(o.type||"")&&n.push(o);return f}function E(){return!0}function S(){return!1}function j(){try{return ae.activeElement}catch(e){}}function N(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)N(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=S;else if(!i)return e;return 1===o&&(a=i,i=function(e){return ye().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=ye.guid++)),e.each(function(){ye.event.add(this,t,i,r,n)})}function A(e,t){return u(e,"table")&&u(11!==t.nodeType?t:t.firstChild,"tr")?ye(">tbody",e)[0]||e:e}function D(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function L(e){var t=at.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function q(e,t){var n,r,i,o,a,s,u,c;if(1===t.nodeType){if(Pe.hasData(e)&&(o=Pe.access(e),a=Pe.set(t,o),c=o.events)){delete a.handle,a.events={};for(i in c)for(n=0,r=c[i].length;n1&&"string"==typeof h&&!me.checkClone&&ot.test(h))return e.each(function(i){var o=e.eq(i);g&&(t[0]=h.call(this,i,o.html())),H(o,t,n,r)});if(p&&(i=k(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(s=ye.map(T(i,"script"),D),u=s.length;f=0&&nw.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=L.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)w.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&Te(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function u(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&void 0!==e.getElementsByTagName&&e}function l(){}function f(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function h(e,n,r){for(var i=0,o=n.length;i-1&&(r[c]=!(a[c]=f))}}else x=g(x===a?x.splice(v,x.length):x),o?o(null,a,x,u):Y.apply(a,x)})}function m(e){for(var t,n,r,i=e.length,o=w.relative[e[0].type],a=o||w.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),c=p(function(e){return K(t,e)>-1},a,!0),l=[function(e,n,r){var i=!o&&(r||n!==j)||((t=n).nodeType?u(e,n,r):c(e,n,r));return t=null,i}];s1&&d(l),s>1&&f(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(oe,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,c){var l,f,p,d=0,h="0",v=r&&[],m=[],y=j,x=r||o&&w.find.TAG("*",c),b=W+=null==y?1:Math.random()||.1,T=x.length;for(c&&(j=a===L||a||c);h!==T&&null!=(l=x[h]);h++){if(o&&l){for(f=0,a||l.ownerDocument===L||(D(l),s=!O);p=e[f++];)if(p(l,a||L,s)){u.push(l);break}c&&(W=b)}i&&((l=!p&&l)&&d--,r&&v.push(l))}if(d+=h,i&&h!==d){for(f=0;p=n[f++];)p(v,m,a,s);if(r){if(d>0)for(;h--;)v[h]||m[h]||(m[h]=G.call(u));m=g(m)}Y.apply(u,m),c&&!r&&m.length>0&&d+n.length>1&&t.uniqueSort(u)}return c&&(W=b,j=y),v};return i?r(a):a}var x,b,w,T,C,k,E,S,j,N,A,D,L,q,O,H,R,F,M,P="sizzle"+1*new Date,I=e.document,W=0,B=0,$=n(),U=n(),_=n(),z=function(e,t){return e===t&&(A=!0),0},X={}.hasOwnProperty,V=[],G=V.pop,J=V.push,Y=V.push,Q=V.slice,K=function(e,t){for(var n=0,r=e.length;n+~]|"+ee+")"+ee+"*"),ue=new RegExp("="+ee+"*([^\\]'\"]*?)"+ee+"*\\]","g"),ce=new RegExp(re),le=new RegExp("^"+te+"$"),fe={ID:new RegExp("^#("+te+")"),CLASS:new RegExp("^\\.("+te+")"),TAG:new RegExp("^("+te+"|[*])"),ATTR:new RegExp("^"+ne),PSEUDO:new RegExp("^"+re),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ee+"*(even|odd|(([+-]|)(\\d*)n|)"+ee+"*(?:([+-]|)"+ee+"*(\\d+)|))"+ee+"*\\)|)","i"),bool:new RegExp("^(?:"+Z+")$","i"),needsContext:new RegExp("^"+ee+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ee+"*((?:-\\d)?\\d*)"+ee+"*\\)|)(?=[^-]|$)","i")},pe=/^(?:input|select|textarea|button)$/i,de=/^h\d$/i,he=/^[^{]+\{\s*\[native \w/,ge=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,me=new RegExp("\\\\([\\da-f]{1,6}"+ee+"?|("+ee+")|.)","ig"),ye=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},xe=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,be=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},we=function(){D()},Te=p(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{Y.apply(V=Q.call(I.childNodes),I.childNodes),V[I.childNodes.length].nodeType}catch(e){Y={apply:V.length?function(e,t){J.apply(e,Q.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}b=t.support={},C=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},D=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:I;return r!==L&&9===r.nodeType&&r.documentElement?(L=r,q=L.documentElement,O=!C(L),I!==L&&(n=L.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",we,!1):n.attachEvent&&n.attachEvent("onunload",we)),b.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),b.getElementsByTagName=i(function(e){return e.appendChild(L.createComment("")),!e.getElementsByTagName("*").length}),b.getElementsByClassName=he.test(L.getElementsByClassName),b.getById=i(function(e){return q.appendChild(e).id=P,!L.getElementsByName||!L.getElementsByName(P).length}),b.getById?(w.filter.ID=function(e){var t=e.replace(me,ye);return function(e){return e.getAttribute("id")===t}},w.find.ID=function(e,t){if(void 0!==t.getElementById&&O){var n=t.getElementById(e);return n?[n]:[]}}):(w.filter.ID=function(e){var t=e.replace(me,ye);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},w.find.ID=function(e,t){if(void 0!==t.getElementById&&O){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),w.find.TAG=b.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):b.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},w.find.CLASS=b.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&O)return t.getElementsByClassName(e)},R=[],H=[],(b.qsa=he.test(L.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&H.push("[*^$]="+ee+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||H.push("\\["+ee+"*(?:value|"+Z+")"),e.querySelectorAll("[id~="+P+"-]").length||H.push("~="),e.querySelectorAll(":checked").length||H.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||H.push(".#.+[+~]")}),i(function(e){e.innerHTML="";var t=L.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&H.push("name"+ee+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&H.push(":enabled",":disabled"),q.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&H.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),H.push(",.*:")})),(b.matchesSelector=he.test(F=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){b.disconnectedMatch=F.call(e,"*"),F.call(e,"[s!='']:x"),R.push("!=",re)}),H=H.length&&new RegExp(H.join("|")),R=R.length&&new RegExp(R.join("|")),t=he.test(q.compareDocumentPosition),M=t||he.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},z=t?function(e,t){if(e===t)return A=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!b.sortDetached&&t.compareDocumentPosition(e)===n?e===L||e.ownerDocument===I&&M(I,e)?-1:t===L||t.ownerDocument===I&&M(I,t)?1:N?K(N,e)-K(N,t):0:4&n?-1:1)}:function(e,t){if(e===t)return A=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===L?-1:t===L?1:i?-1:o?1:N?K(N,e)-K(N,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===I?-1:u[r]===I?1:0},L):L},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==L&&D(e),n=n.replace(ue,"='$1']"),b.matchesSelector&&O&&!_[n+" "]&&(!R||!R.test(n))&&(!H||!H.test(n)))try{var r=F.call(e,n);if(r||b.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return t(n,L,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==L&&D(e),M(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==L&&D(e);var n=w.attrHandle[t.toLowerCase()],r=n&&X.call(w.attrHandle,t.toLowerCase())?n(e,t,!O):void 0;return void 0!==r?r:b.attributes||!O?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.escape=function(e){return(e+"").replace(xe,be)},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(A=!b.detectDuplicates,N=!b.sortStable&&e.slice(0),e.sort(z),A){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return N=null,e},T=t.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=T(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=T(t);return n},w=t.selectors={cacheLength:50,createPseudo:r,match:fe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(me,ye),e[3]=(e[3]||e[4]||e[5]||"").replace(me,ye),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return fe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&ce.test(n)&&(t=k(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(me,ye).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ee+")"+e+"("+ee+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ie," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var c,l,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",v=t.parentNode,m=s&&t.nodeName.toLowerCase(),y=!u&&!s,x=!1;if(v){if(o){for(;g;){for(p=t;p=p[g];)if(s?p.nodeName.toLowerCase()===m:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?v.firstChild:v.lastChild],a&&y){for(p=v,f=p[P]||(p[P]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),c=l[e]||[],d=c[0]===W&&c[1],x=d&&c[2],p=d&&v.childNodes[d];p=++d&&p&&p[g]||(x=d=0)||h.pop();)if(1===p.nodeType&&++x&&p===t){l[e]=[W,d,x];break}}else if(y&&(p=t,f=p[P]||(p[P]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),c=l[e]||[],d=c[0]===W&&c[1],x=d),!1===x)for(;(p=++d&&p&&p[g]||(x=d=0)||h.pop())&&((s?p.nodeName.toLowerCase()!==m:1!==p.nodeType)||!++x||(y&&(f=p[P]||(p[P]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),l[e]=[W,x]),p!==t)););return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=w.pseudos[e]||w.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],w.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=K(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=E(e.replace(oe,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(me,ye),function(t){return(t.textContent||t.innerText||T(t)).indexOf(e)>-1}}),lang:r(function(e){return le.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(me,ye).toLowerCase(),function(t){var n;do{if(n=O?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===L.activeElement&&(!L.hasFocus||L.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:s(!1),disabled:s(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!w.pseudos.empty(e)},header:function(e){return de.test(e.nodeName)},input:function(e){return pe.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:u(function(){return[0]}),last:u(function(e,t){return[t-1]}),eq:u(function(e,t,n){return[n<0?n+t:n]}),even:u(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:u(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&9===t.nodeType&&O&&w.relative[o[1].type]){if(!(t=(w.find.ID(a.matches[0].replace(me,ye),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=fe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!w.relative[s=a.type]);)if((u=w.find[s])&&(r=u(a.matches[0].replace(me,ye),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&f(o)))return Y.apply(n,r),n;break}}return(l||E(e,p))(r,t,!O,n,!t||ve.test(e)&&c(t.parentNode)||t),n},b.sortStable=P.split("").sort(z).join("")===P,b.detectDuplicates=!!A,D(),b.sortDetached=i(function(e){return 1&e.compareDocumentPosition(L.createElement("fieldset"))}),i(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),b.attributes&&i(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(Z,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(n);ye.find=Ce,ye.expr=Ce.selectors,ye.expr[":"]=ye.expr.pseudos,ye.uniqueSort=ye.unique=Ce.uniqueSort,ye.text=Ce.getText,ye.isXMLDoc=Ce.isXML,ye.contains=Ce.contains,ye.escapeSelector=Ce.escape;var ke=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&ye(e).is(n))break;r.push(e)}return r},Ee=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},Se=ye.expr.match.needsContext,je=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,Ne=/^.[^:#\[\.,]*$/;ye.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?ye.find.matchesSelector(r,e)?[r]:[]:ye.find.matches(e,ye.grep(t,function(e){return 1===e.nodeType}))},ye.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(ye(e).filter(function(){for(t=0;t1?ye.uniqueSort(n):n},filter:function(e){return this.pushStack(c(this,e||[],!1))},not:function(e){return this.pushStack(c(this,e||[],!0))},is:function(e){return!!c(this,"string"==typeof e&&Se.test(e)?ye(e):e||[],!1).length}});var Ae,De=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(ye.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ae,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:De.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ye?t[0]:t,ye.merge(this,ye.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:ae,!0)),je.test(r[1])&&ye.isPlainObject(t))for(r in t)ye.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=ae.getElementById(r[2]),i&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):ye.isFunction(e)?void 0!==n.ready?n.ready(e):e(ye):ye.makeArray(e,this)}).prototype=ye.fn,Ae=ye(ae);var Le=/^(?:parents|prev(?:Until|All))/,qe={children:!0,contents:!0,next:!0,prev:!0};ye.fn.extend({has:function(e){var t=ye(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&ye.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?ye.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?fe.call(ye(e),this[0]):fe.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ye.uniqueSort(ye.merge(this.get(),ye(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ye.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return ke(e,"parentNode")},parentsUntil:function(e,t,n){return ke(e,"parentNode",n)},next:function(e){return l(e,"nextSibling")},prev:function(e){return l(e,"previousSibling")},nextAll:function(e){return ke(e,"nextSibling")},prevAll:function(e){return ke(e,"previousSibling")},nextUntil:function(e,t,n){return ke(e,"nextSibling",n)},prevUntil:function(e,t,n){return ke(e,"previousSibling",n)},siblings:function(e){return Ee((e.parentNode||{}).firstChild,e)},children:function(e){return Ee(e.firstChild)},contents:function(e){return u(e,"iframe")?e.contentDocument:(u(e,"template")&&(e=e.content||e),ye.merge([],e.childNodes))}},function(e,t){ye.fn[e]=function(n,r){var i=ye.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=ye.filter(r,i)),this.length>1&&(qe[e]||ye.uniqueSort(i),Le.test(e)&&i.reverse()),this.pushStack(i)}});var Oe=/[^\x20\t\r\n\f]+/g;ye.Callbacks=function(e){e="string"==typeof e?f(e):ye.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1)for(n=a.shift();++s-1;)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?ye.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},ye.extend({Deferred:function(e){var t=[["notify","progress",ye.Callbacks("memory"),ye.Callbacks("memory"),2],["resolve","done",ye.Callbacks("once memory"),ye.Callbacks("once memory"),0,"resolved"],["reject","fail",ye.Callbacks("once memory"),ye.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return ye.Deferred(function(n){ye.each(t,function(t,r){var i=ye.isFunction(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&ye.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(e,r,i){function o(e,t,r,i){return function(){var s=this,u=arguments,c=function(){var n,c;if(!(e=a&&(r!==d&&(s=void 0,u=[n]),t.rejectWith(s,u))}};e?l():(ye.Deferred.getStackHook&&(l.stackTrace=ye.Deferred.getStackHook()),n.setTimeout(l))}}var a=0;return ye.Deferred(function(n){t[0][3].add(o(0,n,ye.isFunction(i)?i:p,n.notifyWith)),t[1][3].add(o(0,n,ye.isFunction(e)?e:p)),t[2][3].add(o(0,n,ye.isFunction(r)?r:d))}).promise()},promise:function(e){return null!=e?ye.extend(e,i):i}},o={};return ye.each(t,function(e,n){var a=n[2],s=n[5];i[n[1]]=a.add,s&&a.add(function(){r=s},t[3-e][2].disable,t[0][2].lock),a.add(n[3].fire),o[n[0]]=function(){return o[n[0]+"With"](this===o?void 0:this,arguments),this},o[n[0]+"With"]=a.fireWith}),i.promise(o),e&&e.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=ue.call(arguments),o=ye.Deferred(),a=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?ue.call(arguments):n,--t||o.resolveWith(r,i)}};if(t<=1&&(h(e,o.done(a(n)).resolve,o.reject,!t),"pending"===o.state()||ye.isFunction(i[n]&&i[n].then)))return o.then();for(;n--;)h(i[n],a(n),o.reject);return o.promise()}});var He=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;ye.Deferred.exceptionHook=function(e,t){n.console&&n.console.warn&&e&&He.test(e.name)&&n.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},ye.readyException=function(e){n.setTimeout(function(){throw e})};var Re=ye.Deferred();ye.fn.ready=function(e){return Re.then(e).catch(function(e){ye.readyException(e)}),this},ye.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--ye.readyWait:ye.isReady)||(ye.isReady=!0,!0!==e&&--ye.readyWait>0||Re.resolveWith(ae,[ye]))}}),ye.ready.then=Re.then,"complete"===ae.readyState||"loading"!==ae.readyState&&!ae.documentElement.doScroll?n.setTimeout(ye.ready):(ae.addEventListener("DOMContentLoaded",g),n.addEventListener("load",g));var Fe=function(e,t,n,r,i,o,a){var s=0,u=e.length,c=null==n;if("object"===ye.type(n)){i=!0;for(s in n)Fe(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,ye.isFunction(r)||(a=!0),c&&(a?(t.call(e,r),t=null):(c=t,t=function(e,t,n){return c.call(ye(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){Ie.remove(this,e)})}}),ye.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Pe.get(e,t),n&&(!r||Array.isArray(n)?r=Pe.access(e,t,ye.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=ye.queue(e,t),r=n.length,i=n.shift(),o=ye._queueHooks(e,t),a=function(){ye.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Pe.get(e,n)||Pe.access(e,n,{empty:ye.Callbacks("once memory").add(function(){Pe.remove(e,[t+"queue",n])})})}}),ye.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,Ye=/^$|\/(?:java|ecma)script/i,Qe={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};Qe.optgroup=Qe.option,Qe.tbody=Qe.tfoot=Qe.colgroup=Qe.caption=Qe.thead,Qe.th=Qe.td;var Ke=/<|&#?\w+;/;!function(){var e=ae.createDocumentFragment(),t=e.appendChild(ae.createElement("div")),n=ae.createElement("input");n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),t.appendChild(n),me.checkClone=t.cloneNode(!0).cloneNode(!0).lastChild.checked,t.innerHTML="",me.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue}();var Ze=ae.documentElement,et=/^key/,tt=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,nt=/^([^.]*)(?:\.(.+)|)/;ye.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,c,l,f,p,d,h,g,v=Pe.get(e);if(v)for(n.handler&&(o=n,n=o.handler,i=o.selector),i&&ye.find.matchesSelector(Ze,i),n.guid||(n.guid=ye.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(t){return void 0!==ye&&ye.event.triggered!==t.type?ye.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(Oe)||[""],c=t.length;c--;)s=nt.exec(t[c])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d&&(f=ye.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=ye.event.special[d]||{},l=ye.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&ye.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||(p=u[d]=[],p.delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,l),l.handler.guid||(l.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,l):p.push(l),ye.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,a,s,u,c,l,f,p,d,h,g,v=Pe.hasData(e)&&Pe.get(e);if(v&&(u=v.events)){for(t=(t||"").match(Oe)||[""],c=t.length;c--;)if(s=nt.exec(t[c])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){for(f=ye.event.special[d]||{},d=(r?f.delegateType:f.bindType)||d,p=u[d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;o--;)l=p[o],!i&&g!==l.origType||n&&n.guid!==l.guid||s&&!s.test(l.namespace)||r&&r!==l.selector&&("**"!==r||!l.selector)||(p.splice(o,1),l.selector&&p.delegateCount--,f.remove&&f.remove.call(e,l));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||ye.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)ye.event.remove(e,d+t[c],n,r,!0);ye.isEmptyObject(u)&&Pe.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=ye.event.fix(e),u=new Array(arguments.length),c=(Pe.get(this,"events")||{})[s.type]||[],l=ye.event.special[s.type]||{};for(u[0]=s,t=1;t=1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&("click"!==e.type||!0!==c.disabled)){for(o=[],a={},n=0;n-1:ye.find(i,this,null,[c]).length),a[i]&&o.push(r);o.length&&s.push({elem:c,handlers:o})}return c=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,it=/\s*$/g;ye.extend({htmlPrefilter:function(e){return e.replace(rt,"<$1>")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=ye.contains(e.ownerDocument,e);if(!(me.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ye.isXMLDoc(e)))for(a=T(s),o=T(e),r=0,i=o.length;r0&&C(a,!u&&T(e,"script")),s},cleanData:function(e){for(var t,n,r,i=ye.event.special,o=0;void 0!==(n=e[o]);o++)if(Me(n)){if(t=n[Pe.expando]){if(t.events)for(r in t.events)i[r]?ye.event.remove(n,r):ye.removeEvent(n,r,t.handle);n[Pe.expando]=void 0}n[Ie.expando]&&(n[Ie.expando]=void 0)}}}),ye.fn.extend({detach:function(e){return R(this,e,!0)},remove:function(e){return R(this,e)},text:function(e){return Fe(this,function(e){return void 0===e?ye.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return H(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||A(this,e).appendChild(e)})},prepend:function(){return H(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=A(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return H(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return H(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(ye.cleanData(T(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ye.clone(this,e,t)})},html:function(e){return Fe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!Qe[(Je.exec(e)||["",""])[1].toLowerCase()]){e=ye.htmlPrefilter(e);try{for(;n1)}}),ye.Tween=U,U.prototype={constructor:U,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||ye.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ye.cssNumber[n]?"":"px")},cur:function(){var e=U.propHooks[this.prop];return e&&e.get?e.get(this):U.propHooks._default.get(this)},run:function(e){var t,n=U.propHooks[this.prop];return this.options.duration?this.pos=t=ye.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):U.propHooks._default.set(this),this}},U.prototype.init.prototype=U.prototype,U.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=ye.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){ye.fx.step[e.prop]?ye.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[ye.cssProps[e.prop]]&&!ye.cssHooks[e.prop]?e.elem[e.prop]=e.now:ye.style(e.elem,e.prop,e.now+e.unit)}}},U.propHooks.scrollTop=U.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ye.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},ye.fx=U.prototype.init,ye.fx.step={};var mt,yt,xt=/^(?:toggle|show|hide)$/,bt=/queueHooks$/;ye.Animation=ye.extend(Y,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return x(n.elem,e,Ue.exec(t),n),n}]},tweener:function(e,t){ye.isFunction(e)?(t=e,e=["*"]):e=e.match(Oe);for(var n,r=0,i=e.length;r1)},removeAttr:function(e){return this.each(function(){ye.removeAttr(this,e)})}}),ye.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?ye.prop(e,t,n):(1===o&&ye.isXMLDoc(e)||(i=ye.attrHooks[t.toLowerCase()]||(ye.expr.match.bool.test(t)?wt:void 0)),void 0!==n?null===n?void ye.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:(r=ye.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!me.radioValue&&"radio"===t&&u(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(Oe);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),wt={set:function(e,t,n){return!1===t?ye.removeAttr(e,n):e.setAttribute(n,n),n}},ye.each(ye.expr.match.bool.source.match(/\w+/g),function(e,t){var n=Tt[t]||ye.find.attr;Tt[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=Tt[a],Tt[a]=i,i=null!=n(e,t,r)?a:null,Tt[a]=o),i}});var Ct=/^(?:input|select|textarea|button)$/i,kt=/^(?:a|area)$/i;ye.fn.extend({prop:function(e,t){return Fe(this,ye.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[ye.propFix[e]||e]})}}),ye.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&ye.isXMLDoc(e)||(t=ye.propFix[t]||t,i=ye.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=ye.find.attr(e,"tabindex");return t?parseInt(t,10):Ct.test(e.nodeName)||kt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),me.optSelected||(ye.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),ye.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ye.propFix[this.toLowerCase()]=this}),ye.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(ye.isFunction(e))return this.each(function(t){ye(this).addClass(e.call(this,t,K(this)))});if("string"==typeof e&&e)for(t=e.match(Oe)||[];n=this[u++];)if(i=K(n),r=1===n.nodeType&&" "+Q(i)+" "){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");s=Q(r),i!==s&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(ye.isFunction(e))return this.each(function(t){ye(this).removeClass(e.call(this,t,K(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(Oe)||[];n=this[u++];)if(i=K(n),r=1===n.nodeType&&" "+Q(i)+" "){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");s=Q(r),i!==s&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):ye.isFunction(e)?this.each(function(n){ye(this).toggleClass(e.call(this,n,K(this),t),t)}):this.each(function(){var t,r,i,o;if("string"===n)for(r=0,i=ye(this),o=e.match(Oe)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&"boolean"!==n||(t=K(this),t&&Pe.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":Pe.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+Q(K(n))+" ").indexOf(t)>-1)return!0;return!1}});var Et=/\r/g;ye.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=ye.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,ye(this).val()):e,null==i?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=ye.map(i,function(e){return null==e?"":e+""})),(t=ye.valHooks[this.type]||ye.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))})):i?(t=ye.valHooks[i.type]||ye.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:(n=i.value,"string"==typeof n?n.replace(Et,""):null==n?"":n):void 0}}),ye.extend({valHooks:{option:{get:function(e){var t=ye.find.attr(e,"value");return null!=t?t:Q(ye.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],c=a?o+1:i.length;for(r=o<0?c:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),ye.each(["radio","checkbox"],function(){ye.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=ye.inArray(ye(e).val(),t)>-1}},me.checkOn||(ye.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var St=/^(?:focusinfocus|focusoutblur)$/;ye.extend(ye.event,{trigger:function(e,t,r,i){var o,a,s,u,c,l,f,p=[r||ae],d=he.call(e,"type")?e.type:e,h=he.call(e,"namespace")?e.namespace.split("."):[];if(a=s=r=r||ae,3!==r.nodeType&&8!==r.nodeType&&!St.test(d+ye.event.triggered)&&(d.indexOf(".")>-1&&(h=d.split("."),d=h.shift(),h.sort()),c=d.indexOf(":")<0&&"on"+d,e=e[ye.expando]?e:new ye.Event(d,"object"==typeof e&&e),e.isTrigger=i?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=r),t=null==t?[e]:ye.makeArray(t,[e]),f=ye.event.special[d]||{},i||!f.trigger||!1!==f.trigger.apply(r,t))){if(!i&&!f.noBubble&&!ye.isWindow(r)){for(u=f.delegateType||d,St.test(u+d)||(a=a.parentNode);a;a=a.parentNode)p.push(a),s=a;s===(r.ownerDocument||ae)&&p.push(s.defaultView||s.parentWindow||n)}for(o=0;(a=p[o++])&&!e.isPropagationStopped();)e.type=o>1?u:f.bindType||d,l=(Pe.get(a,"events")||{})[e.type]&&Pe.get(a,"handle"),l&&l.apply(a,t),(l=c&&a[c])&&l.apply&&Me(a)&&(e.result=l.apply(a,t),!1===e.result&&e.preventDefault());return e.type=d,i||e.isDefaultPrevented()||f._default&&!1!==f._default.apply(p.pop(),t)||!Me(r)||c&&ye.isFunction(r[d])&&!ye.isWindow(r)&&(s=r[c],s&&(r[c]=null),ye.event.triggered=d,r[d](),ye.event.triggered=void 0,s&&(r[c]=s)),e.result}},simulate:function(e,t,n){var r=ye.extend(new ye.Event,n,{type:e,isSimulated:!0});ye.event.trigger(r,null,t)}}),ye.fn.extend({trigger:function(e,t){return this.each(function(){ye.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ye.event.trigger(e,t,n,!0)}}),ye.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){ye.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),ye.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),me.focusin="onfocusin"in n,me.focusin||ye.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){ye.event.simulate(t,e.target,ye.event.fix(e))};ye.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=Pe.access(r,t);i||r.addEventListener(e,n,!0),Pe.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=Pe.access(r,t)-1;i?Pe.access(r,t,i):(r.removeEventListener(e,n,!0),Pe.remove(r,t))}}});var jt=n.location,Nt=ye.now(),At=/\?/;ye.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new n.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||ye.error("Invalid XML: "+e),t};var Dt=/\[\]$/,Lt=/\r?\n/g,qt=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;ye.param=function(e,t){var n,r=[],i=function(e,t){var n=ye.isFunction(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!ye.isPlainObject(e))ye.each(e,function(){i(this.name,this.value)});else for(n in e)Z(n,e[n],t,i);return r.join("&")},ye.fn.extend({serialize:function(){return ye.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ye.prop(this,"elements");return e?ye.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ye(this).is(":disabled")&&Ot.test(this.nodeName)&&!qt.test(e)&&(this.checked||!Ge.test(e))}).map(function(e,t){var n=ye(this).val();return null==n?null:Array.isArray(n)?ye.map(n,function(e){return{name:t.name,value:e.replace(Lt,"\r\n")}}):{name:t.name,value:n.replace(Lt,"\r\n")}}).get()}});var Ht=/%20/g,Rt=/#.*$/,Ft=/([?&])_=[^&]*/,Mt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,It=/^(?:GET|HEAD)$/,Wt=/^\/\//,Bt={},$t={},Ut="*/".concat("*"),_t=ae.createElement("a");_t.href=jt.href,ye.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:jt.href,type:"GET",isLocal:Pt.test(jt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Ut,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":ye.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?ne(ne(e,ye.ajaxSettings),t):ne(ye.ajaxSettings,e)},ajaxPrefilter:ee(Bt),ajaxTransport:ee($t),ajax:function(e,t){function r(e,t,r,s){var c,p,d,b,w,T=t;l||(l=!0,u&&n.clearTimeout(u),i=void 0,a=s||"",C.readyState=e>0?4:0,c=e>=200&&e<300||304===e,r&&(b=re(h,C,r)),b=ie(h,b,C,c),c?(h.ifModified&&(w=C.getResponseHeader("Last-Modified"),w&&(ye.lastModified[o]=w),(w=C.getResponseHeader("etag"))&&(ye.etag[o]=w)),204===e||"HEAD"===h.type?T="nocontent":304===e?T="notmodified":(T=b.state,p=b.data,d=b.error,c=!d)):(d=T,!e&&T||(T="error",e<0&&(e=0))),C.status=e,C.statusText=(t||T)+"",c?m.resolveWith(g,[p,T,C]):m.rejectWith(g,[C,T,d]),C.statusCode(x),x=void 0,f&&v.trigger(c?"ajaxSuccess":"ajaxError",[C,h,c?p:d]),y.fireWith(g,[C,T]),f&&(v.trigger("ajaxComplete",[C,h]),--ye.active||ye.event.trigger("ajaxStop")))}"object"==typeof e&&(t=e,e=void 0),t=t||{};var i,o,a,s,u,c,l,f,p,d,h=ye.ajaxSetup({},t),g=h.context||h,v=h.context&&(g.nodeType||g.jquery)?ye(g):ye.event,m=ye.Deferred(),y=ye.Callbacks("once memory"),x=h.statusCode||{},b={},w={},T="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(l){if(!s)for(s={};t=Mt.exec(a);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return l?a:null},setRequestHeader:function(e,t){return null==l&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==l&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)C.always(e[C.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||T;return i&&i.abort(t),r(0,t),this}};if(m.promise(C),h.url=((e||h.url||jt.href)+"").replace(Wt,jt.protocol+"//"),h.type=t.method||t.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(Oe)||[""],null==h.crossDomain){c=ae.createElement("a");try{c.href=h.url,c.href=c.href,h.crossDomain=_t.protocol+"//"+_t.host!=c.protocol+"//"+c.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=ye.param(h.data,h.traditional)),te(Bt,h,t,C),l)return C;f=ye.event&&h.global,f&&0==ye.active++&&ye.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!It.test(h.type),o=h.url.replace(Rt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(Ht,"+")):(d=h.url.slice(o.length),h.data&&(o+=(At.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ft,"$1"),d=(At.test(o)?"&":"?")+"_="+Nt+++d),h.url=o+d),h.ifModified&&(ye.lastModified[o]&&C.setRequestHeader("If-Modified-Since",ye.lastModified[o]),ye.etag[o]&&C.setRequestHeader("If-None-Match",ye.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||t.contentType)&&C.setRequestHeader("Content-Type",h.contentType),C.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+Ut+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)C.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,C,h)||l))return C.abort();if(T="abort",y.add(h.complete),C.done(h.success),C.fail(h.error),i=te($t,h,t,C)){if(C.readyState=1,f&&v.trigger("ajaxSend",[C,h]),l)return C;h.async&&h.timeout>0&&(u=n.setTimeout(function(){C.abort("timeout")},h.timeout));try{l=!1,i.send(b,r)}catch(e){if(l)throw e;r(-1,e)}}else r(-1,"No Transport");return C},getJSON:function(e,t,n){return ye.get(e,t,n,"json")},getScript:function(e,t){return ye.get(e,void 0,t,"script")}}),ye.each(["get","post"],function(e,t){ye[t]=function(e,n,r,i){return ye.isFunction(n)&&(i=i||r,r=n,n=void 0),ye.ajax(ye.extend({url:e,type:t,dataType:i,data:n,success:r},ye.isPlainObject(e)&&e))}}),ye._evalUrl=function(e){return ye.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,throws:!0})},ye.fn.extend({wrapAll:function(e){var t;return this[0]&&(ye.isFunction(e)&&(e=e.call(this[0])),t=ye(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return ye.isFunction(e)?this.each(function(t){ye(this).wrapInner(e.call(this,t))}):this.each(function(){var t=ye(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=ye.isFunction(e);return this.each(function(n){ye(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){ye(this).replaceWith(this.childNodes)}),this}}),ye.expr.pseudos.hidden=function(e){return!ye.expr.pseudos.visible(e)},ye.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},ye.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(e){}};var zt={0:200,1223:204},Xt=ye.ajaxSettings.xhr();me.cors=!!Xt&&"withCredentials"in Xt,me.ajax=Xt=!!Xt,ye.ajaxTransport(function(e){var t,r;if(me.cors||Xt&&!e.crossDomain)return{send:function(i,o){var a,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(a in e.xhrFields)s[a]=e.xhrFields[a];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);t=function(e){return function(){t&&(t=r=s.onload=s.onerror=s.onabort=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(zt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=t(),r=s.onerror=t("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&n.setTimeout(function(){t&&r()})},t=t("abort");try{s.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}}),ye.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),ye.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return ye.globalEval(e),e}}}),ye.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),ye.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=ye("