ggerganov commited on
Commit
cff6aed
1 Parent(s): d05e7af
css/chessboard-1.0.0.css ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */
2
+
3
+ .clearfix-7da63 {
4
+ clear: both;
5
+ }
6
+
7
+ .board-b72b1 {
8
+ border: 2px solid #404040;
9
+ box-sizing: content-box;
10
+ }
11
+
12
+ .square-55d63 {
13
+ float: left;
14
+ position: relative;
15
+
16
+ /* disable any native browser highlighting */
17
+ -webkit-touch-callout: none;
18
+ -webkit-user-select: none;
19
+ -khtml-user-select: none;
20
+ -moz-user-select: none;
21
+ -ms-user-select: none;
22
+ user-select: none;
23
+ }
24
+
25
+ .white-1e1d7 {
26
+ background-color: #f0d9b5;
27
+ color: #b58863;
28
+ }
29
+
30
+ .black-3c85d {
31
+ background-color: #b58863;
32
+ color: #f0d9b5;
33
+ }
34
+
35
+ .highlight1-32417, .highlight2-9c5d2 {
36
+ box-shadow: inset 0 0 3px 3px yellow;
37
+ }
38
+
39
+ .notation-322f9 {
40
+ cursor: default;
41
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
42
+ font-size: 14px;
43
+ position: absolute;
44
+ }
45
+
46
+ .alpha-d2270 {
47
+ bottom: 1px;
48
+ right: 3px;
49
+ }
50
+
51
+ .numeric-fc462 {
52
+ top: 2px;
53
+ left: 2px;
54
+ }
css/chessboard-1.0.0.min.css ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */
2
+ .clearfix-7da63{clear:both}.board-b72b1{border:2px solid #404040;box-sizing:content-box}.square-55d63{float:left;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.white-1e1d7{background-color:#f0d9b5;color:#b58863}.black-3c85d{background-color:#b58863;color:#f0d9b5}.highlight1-32417,.highlight2-9c5d2{box-shadow:inset 0 0 3px 3px #ff0}.notation-322f9{cursor:default;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;position:absolute}.alpha-d2270{bottom:1px;right:3px}.numeric-fc462{top:2px;left:2px}
ggml-tiny.en.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:921e4cf8686fdd993dcd081a5da5b6c365bfde1162e72b08d75ac75289920b1f
3
- size 77704715
 
 
 
 
img/chesspieces/wikipedia/bB.png ADDED
img/chesspieces/wikipedia/bK.png ADDED
img/chesspieces/wikipedia/bN.png ADDED
img/chesspieces/wikipedia/bP.png ADDED
img/chesspieces/wikipedia/bQ.png ADDED
img/chesspieces/wikipedia/bR.png ADDED
img/chesspieces/wikipedia/wB.png ADDED
img/chesspieces/wikipedia/wK.png ADDED
img/chesspieces/wikipedia/wN.png ADDED
img/chesspieces/wikipedia/wP.png ADDED
img/chesspieces/wikipedia/wQ.png ADDED
img/chesspieces/wikipedia/wR.png ADDED
index.html CHANGED
@@ -1,886 +1,441 @@
1
  <!doctype html>
2
  <html lang="en-us">
3
- <head>
4
- <title>whisper.cpp : WASM example</title>
5
- <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
6
-
7
- <style>
8
- #output {
9
- width: 100%;
10
- height: 100%;
11
- margin: 0 auto;
12
- margin-top: 10px;
13
- border-left: 0px;
14
- border-right: 0px;
15
- padding-left: 0px;
16
- padding-right: 0px;
17
- display: block;
18
- background-color: black;
19
- color: white;
20
- font-size: 10px;
21
- font-family: "Lucida Console", Monaco, monospace;
22
- outline: none;
23
- white-space: pre;
24
- overflow-wrap: normal;
25
- overflow-x: scroll;
26
- }
27
- </style>
28
- </head>
29
- <body>
30
- <div id="main-container">
31
- <div id="warning" style="display: none; padding: 1rem">
32
- <b style="color: red; font-size: large"
33
- >Warning: your browser does not support SharedArrayBuffer please try
34
- open the page in a new tab.
35
- </b>
36
- <!-- <a target="_blank" href="https://radames-whisper-wasm.hf.space" target="_blank"
37
- >https://radames-whisper-wasm.hf.space</a
38
- > -->
39
- </div>
40
- <b
41
- >Minimal
42
- <a target="_blank" href="https://github.com/ggerganov/whisper.cpp">whisper.cpp</a>
43
- example running fully in the browser</b
44
- >
45
-
46
- <br /><br />
47
-
48
- Usage instructions:<br />
49
- <ul>
50
- <li>
51
- Load a ggml model file (you can obtain one from
52
- <a target="_blank" href="https://ggml.ggerganov.com/">here</a>, recommended:
53
- <b>tiny</b> or <b>base</b>)
54
- </li>
55
- <li>
56
- Select audio file to transcribe or record audio from the microphone
57
- (sample: <a target="_blank" href="https://whisper.ggerganov.com/jfk.wav">jfk.wav</a>)
58
- </li>
59
- <li>Click on the "Transcribe" button to start the transcription</li>
60
- </ul>
61
-
62
- Note that the computation is quite heavy and may take a few seconds to
63
- complete.<br />
64
- The transcription results will be displayed in the text area below.<br /><br />
65
- <b>Important:</b>
66
- <ul>
67
- <li>
68
- your browser must support WASM SIMD instructions for this to work
69
- </li>
70
- <li>
71
- Firefox cannot load files larger than 256 MB - use Chrome instead
72
- </li>
73
- </ul>
74
-
75
- <b>More examples:</b>
76
- <a target="_blank" href="https://whisper.ggerganov.com/">main</a> |
77
- <a target="_blank" href="https://whisper.ggerganov.com/bench">bench</a> |
78
- <a target="_blank" href="https://whisper.ggerganov.com/stream">stream</a> |
79
- <a target="_blank" href="https://whisper.ggerganov.com/command">command</a> |
80
- <a target="_blank" href="https://whisper.ggerganov.com/talk">talk</a> |
81
-
82
- <hr />
83
-
84
- <div id="model">
85
- Whisper models: <span id="model-whisper-status"></span><br /><br />
86
- <button id="fetch-whisper-tiny-en" onclick="loadWhisper('tiny.en')">
87
- tiny.en (75 MB)
88
- </button>
89
- <button id="fetch-whisper-tiny" onclick="loadWhisper('tiny')">
90
- tiny (75 MB)
91
- </button>
92
- <button id="fetch-whisper-base-en" onclick="loadWhisper('base.en')">
93
- base.en (142 MB)
94
- </button>
95
- <button id="fetch-whisper-base" onclick="loadWhisper('base')">
96
- base (142 MB)
97
- </button>
98
- <button id="fetch-whisper-small-en" onclick="loadWhisper('small.en')">
99
- small.en (466 MB)
100
- </button>
101
- <button id="fetch-whisper-small" onclick="loadWhisper('small')">
102
- small (466 MB)
103
- </button>
104
- <input
105
- type="file"
106
- id="whisper-file"
107
- name="file"
108
- onchange="loadFile(event, 'whisper.bin')"
109
- />
110
- <br /><br />
111
- Quantized models:<br /><br />
112
- <button
113
- id="fetch-whisper-tiny-en-q5_1"
114
- onclick="loadWhisper('tiny-en-q5_1')"
115
- >
116
- tiny.en (Q5_1, 31 MB)
117
- </button>
118
- <button id="fetch-whisper-tiny-q5_1" onclick="loadWhisper('tiny-q5_1')">
119
- tiny (Q5_1, 31 MB)
120
- </button>
121
- <button
122
- id="fetch-whisper-base-en-q5_1"
123
- onclick="loadWhisper('base-en-q5_1')"
124
- >
125
- base.en (Q5_1, 57 MB)
126
- </button>
127
- <button id="fetch-whisper-base-q5_1" onclick="loadWhisper('base-q5_1')">
128
- base (Q5_1, 57 MB)
129
- </button>
130
- <button
131
- id="fetch-whisper-small-en-q5_1"
132
- onclick="loadWhisper('small-en-q5_1')"
133
- >
134
- small.en (Q5_1, 182 MB)
135
- </button>
136
- <button
137
- id="fetch-whisper-small-q5_1"
138
- onclick="loadWhisper('small-q5_1')"
139
- >
140
- small (Q5_1, 182 MB)</button
141
- ><br />
142
- <button
143
- id="fetch-whisper-medium-en-q5_0"
144
- onclick="loadWhisper('medium-en-q5_0')"
145
- >
146
- medium.en (Q5_0, 515 MB)
147
- </button>
148
- <button
149
- id="fetch-whisper-medium-q5_0"
150
- onclick="loadWhisper('medium-q5_0')"
151
- >
152
- medium (Q5_0, 515 MB)
153
- </button>
154
- <button
155
- id="fetch-whisper-large-q5_0"
156
- onclick="loadWhisper('large-q5_0')"
157
- >
158
- large (Q5_0, 1030 MB)
159
- </button>
160
- <span id="fetch-whisper-progress"></span>
161
- </div>
162
-
163
- <br />
164
-
165
- <!-- radio button to select between file upload or microphone -->
166
- <div id="input">
167
- Input:
168
- <input
169
- type="radio"
170
- id="file"
171
- name="input"
172
- value="file"
173
- checked="checked"
174
- onchange="changeInput('file')"
175
- />
176
- <label for="file">File</label>
177
- <input
178
- type="radio"
179
- id="mic"
180
- name="input"
181
- value="mic"
182
- onchange="changeInput('mic')"
183
- />
184
- <label for="mic">Microphone</label>
185
- </div>
186
-
187
- <br />
188
-
189
- <div id="input_file">
190
- Audio file:
191
- <input type="file" id="file" name="file" onchange="loadAudio(event)" />
192
- </div>
193
-
194
- <div id="input_mic" style="display: none">
195
- Microphone:
196
- <button id="start" onclick="startRecording()">Start</button>
197
- <button id="stop" onclick="stopRecording()" disabled>Stop</button>
198
-
199
- <!-- progress bar to show recording progress -->
200
- <br /><br />
201
- <div id="progress" style="display: none">
202
- <div
203
- id="progress-bar"
204
- style="width: 0%; height: 10px; background-color: #4caf50"
205
- ></div>
206
- <div id="progress-text">0%</div>
207
  </div>
208
- </div>
209
-
210
- <a target="_blank"udio controls="controls" id="audio" loop hidden>
211
- Your browser does not support the &lt;audio&gt; tag.
212
- <source id="source" src="" type="audio/wav" />
213
- </audio>
214
-
215
- <hr />
216
- <br />
217
-
218
- <table>
219
- <tr>
220
- <td>
221
- Language:
222
- <select id="language" name="language">
223
- <option value="en">English</option>
224
- <option value="ar">Arabic</option>
225
- <option value="hy">Armenian</option>
226
- <option value="az">Azerbaijani</option>
227
- <option value="eu">Basque</option>
228
- <option value="be">Belarusian</option>
229
- <option value="bn">Bengali</option>
230
- <option value="bg">Bulgarian</option>
231
- <option value="ca">Catalan</option>
232
- <option value="zh">Chinese</option>
233
- <option value="hr">Croatian</option>
234
- <option value="cs">Czech</option>
235
- <option value="da">Danish</option>
236
- <option value="nl">Dutch</option>
237
- <option value="en">English</option>
238
- <option value="et">Estonian</option>
239
- <option value="tl">Filipino</option>
240
- <option value="fi">Finnish</option>
241
- <option value="fr">French</option>
242
- <option value="gl">Galician</option>
243
- <option value="ka">Georgian</option>
244
- <option value="de">German</option>
245
- <option value="el">Greek</option>
246
- <option value="gu">Gujarati</option>
247
- <option value="iw">Hebrew</option>
248
- <option value="hi">Hindi</option>
249
- <option value="hu">Hungarian</option>
250
- <option value="is">Icelandic</option>
251
- <option value="id">Indonesian</option>
252
- <option value="ga">Irish</option>
253
- <option value="it">Italian</option>
254
- <option value="ja">Japanese</option>
255
- <option value="kn">Kannada</option>
256
- <option value="ko">Korean</option>
257
- <option value="la">Latin</option>
258
- <option value="lv">Latvian</option>
259
- <option value="lt">Lithuanian</option>
260
- <option value="mk">Macedonian</option>
261
- <option value="ms">Malay</option>
262
- <option value="mt">Maltese</option>
263
- <option value="no">Norwegian</option>
264
- <option value="fa">Persian</option>
265
- <option value="pl">Polish</option>
266
- <option value="pt">Portuguese</option>
267
- <option value="ro">Romanian</option>
268
- <option value="ru">Russian</option>
269
- <option value="sr">Serbian</option>
270
- <option value="sk">Slovak</option>
271
- <option value="sl">Slovenian</option>
272
- <option value="es">Spanish</option>
273
- <option value="sw">Swahili</option>
274
- <option value="sv">Swedish</option>
275
- <option value="ta">Tamil</option>
276
- <option value="te">Telugu</option>
277
- <option value="th">Thai</option>
278
- <option value="tr">Turkish</option>
279
- <option value="uk">Ukrainian</option>
280
- <option value="ur">Urdu</option>
281
- <option value="vi">Vietnamese</option>
282
- <option value="cy">Welsh</option>
283
- <option value="yi">Yiddish</option>
284
- </select>
285
- </td>
286
- <!-- Slider to select number of threads between 1 and 16 -->
287
- <td>
288
- Threads:
289
- <input
290
- type="range"
291
- id="threads"
292
- name="threads"
293
- min="1"
294
- max="16"
295
- value="8"
296
- onchange="changeThreads(this.value)"
297
- />
298
- <span id="threads-value">8</span>
299
- </td>
300
- <td>
301
- <button onclick="onProcess(false);">Transcribe</button>
302
- </td>
303
- <td>
304
- <button onclick="onProcess(true);">Translate</button>
305
- </td>
306
- </tr>
307
- </table>
308
-
309
- <br />
310
-
311
- <!-- textarea with height filling the rest of the page -->
312
- <textarea id="output" rows="20"></textarea>
313
-
314
- <br /><br />
315
-
316
- <div class="cell-version">
317
- <span>
318
- | Build time: <span class="nav-link">@GIT_DATE@</span> | Commit hash:
319
- <a target="_blank"
320
- class="nav-link"
321
- href="https://github.com/ggerganov/whisper.cpp/commit/@GIT_SHA1@"
322
- >@GIT_SHA1@</a
323
- >
324
- | Commit subject: <span class="nav-link">@GIT_COMMIT_SUBJECT@</span> |
325
- <a target="_blank"
326
- class="nav-link"
327
- href="https://github.com/ggerganov/whisper.cpp/tree/master/examples/whisper.wasm"
328
- >Source Code</a
329
- >
330
- |
331
- </span>
332
- </div>
333
- </div>
334
-
335
- <script type="text/javascript" src="helpers.js"></script>
336
- <script type="text/javascript">
337
- document.addEventListener("DOMContentLoaded", () => {
338
- //check is shared array buffer is supported
339
- if (!window.SharedArrayBuffer) {
340
- document.querySelector("#warning").style.display = "block";
341
- }
342
- });
343
- // TODO: convert audio buffer to WAV
344
- function setAudio(audio) {
345
- //if (audio) {
346
- // // convert to 16-bit PCM
347
- // var blob = new Blob([audio], { type: 'audio/wav' });
348
- // var url = URL.createObjectURL(blob);
349
- // document.getElementById('source').src = url;
350
- // document.getElementById('audio').hidden = false;
351
- // document.getElementById('audio').loop = false;
352
- // document.getElementById('audio').load();
353
- //} else {
354
- // document.getElementById('audio').hidden = true;
355
- //}
356
- }
357
-
358
- function changeInput(input) {
359
- if (input == "file") {
360
- document.getElementById("input_file").style.display = "block";
361
- document.getElementById("input_mic").style.display = "none";
362
- document.getElementById("progress").style.display = "none";
363
- } else {
364
- document.getElementById("input_file").style.display = "none";
365
- document.getElementById("input_mic").style.display = "block";
366
- document.getElementById("progress").style.display = "block";
367
- }
368
- }
369
-
370
- var Module = {
371
- print: printTextarea,
372
- printErr: printTextarea,
373
- setStatus: function (text) {
374
- printTextarea("js: " + text);
375
- },
376
- monitorRunDependencies: function (left) {},
377
- };
378
-
379
- // web audio context
380
- var context = null;
381
-
382
- // audio data
383
- var audio = null;
384
-
385
- // the whisper instance
386
- var instance = null;
387
- var model_whisper = "";
388
-
389
- // helper function
390
- function convertTypedArray(src, type) {
391
- var buffer = new ArrayBuffer(src.byteLength);
392
- var baseView = new src.constructor(buffer).set(src);
393
- return new type(buffer);
394
- }
395
-
396
- //
397
- // load model
398
- //
399
-
400
- let dbVersion = 1;
401
- let dbName = "whisper.ggerganov.com";
402
- let indexedDB =
403
- window.indexedDB ||
404
- window.mozIndexedDB ||
405
- window.webkitIndexedDB ||
406
- window.msIndexedDB;
407
-
408
- function storeFS(fname, buf) {
409
- // write to WASM file using FS_createDataFile
410
- // if the file exists, delete it
411
- try {
412
- Module.FS_unlink(fname);
413
- } catch (e) {
414
- // ignore
415
- }
416
-
417
- Module.FS_createDataFile("/", fname, buf, true, true);
418
-
419
- //model_whisper = fname;
420
-
421
- document.getElementById("model-whisper-status").innerHTML =
422
- 'loaded "' + model_whisper + '"!';
423
-
424
- printTextarea(
425
- "storeFS: stored model: " + fname + " size: " + buf.length
426
- );
427
-
428
- document.getElementById("model").innerHTML =
429
- "Model fetched: " + model_whisper;
430
- }
431
-
432
- function loadFile(event, fname) {
433
- var file = event.target.files[0] || null;
434
- if (file == null) {
435
- return;
436
- }
437
-
438
- printTextarea(
439
- "loadFile: loading model: " +
440
- file.name +
441
- ", size: " +
442
- file.size +
443
- " bytes"
444
- );
445
- printTextarea("loadFile: please wait ...");
446
-
447
- var reader = new FileReader();
448
- reader.onload = function (event) {
449
- var buf = new Uint8Array(reader.result);
450
- storeFS(fname, buf);
451
- };
452
- reader.readAsArrayBuffer(file);
453
-
454
- document.getElementById("fetch-whisper-tiny-en").style.display = "none";
455
- document.getElementById("fetch-whisper-base-en").style.display = "none";
456
- document.getElementById("fetch-whisper-small-en").style.display =
457
- "none";
458
- document.getElementById("fetch-whisper-tiny").style.display = "none";
459
- document.getElementById("fetch-whisper-base").style.display = "none";
460
- document.getElementById("fetch-whisper-small").style.display = "none";
461
-
462
- document.getElementById("fetch-whisper-tiny-en-q5_1").style.display =
463
- "none";
464
- document.getElementById("fetch-whisper-tiny-q5_1").style.display =
465
- "none";
466
- document.getElementById("fetch-whisper-base-en-q5_1").style.display =
467
- "none";
468
- document.getElementById("fetch-whisper-base-q5_1").style.display =
469
- "none";
470
- document.getElementById("fetch-whisper-small-en-q5_1").style.display =
471
- "none";
472
- document.getElementById("fetch-whisper-small-q5_1").style.display =
473
- "none";
474
- document.getElementById("fetch-whisper-medium-en-q5_0").style.display =
475
- "none";
476
- document.getElementById("fetch-whisper-medium-q5_0").style.display =
477
- "none";
478
- document.getElementById("fetch-whisper-large-q5_0").style.display =
479
- "none";
480
-
481
- document.getElementById("whisper-file").style.display = "none";
482
- document.getElementById("model-whisper-status").innerHTML =
483
- "loaded model: " + file.name;
484
- }
485
-
486
- function loadWhisper(model) {
487
- const baseURL =
488
- "https://huggingface.co/ggerganov/whisper.cpp/resolve/main";
489
- let urls = {
490
- "tiny.en": `${baseURL}/ggml-tiny.en.bin`,
491
- tiny: `${baseURL}/ggml-tiny.bin`,
492
- "base.en": `${baseURL}/ggml-base.en.bin`,
493
- base: `${baseURL}/ggml-base.bin`,
494
- "small.en": `${baseURL}/ggml-small.en.bin`,
495
- small: `${baseURL}/ggml-small.bin`,
496
-
497
- "tiny-en-q5_1": `${baseURL}/ggml-model-whisper-tiny.en-q5_1.bin`,
498
- "tiny-q5_1": `${baseURL}/ggml-model-whisper-tiny-q5_1.bin`,
499
- "base-en-q5_1": `${baseURL}/ggml-model-whisper-base.en-q5_1.bin`,
500
- "base-q5_1": `${baseURL}/ggml-model-whisper-base-q5_1.bin`,
501
- "small-en-q5_1": `${baseURL}/ggml-model-whisper-small.en-q5_1.bin`,
502
- "small-q5_1": `${baseURL}/ggml-model-whisper-small-q5_1.bin`,
503
- "medium-en-q5_0": `${baseURL}/ggml-model-whisper-medium.en-q5_0.bin`,
504
- "medium-q5_0": `${baseURL}/ggml-model-whisper-medium-q5_0.bin`,
505
- "large-q5_0": `${baseURL}/ggml-model-whisper-large-q5_0.bin`,
506
- };
507
-
508
- let sizes = {
509
- "tiny.en": 75,
510
- tiny: 75,
511
- "base.en": 142,
512
- base: 142,
513
- "small.en": 466,
514
- small: 466,
515
-
516
- "tiny-en-q5_1": 31,
517
- "tiny-q5_1": 31,
518
- "base-en-q5_1": 57,
519
- "base-q5_1": 57,
520
- "small-en-q5_1": 182,
521
- "small-q5_1": 182,
522
- "medium-en-q5_0": 515,
523
- "medium-q5_0": 515,
524
- "large-q5_0": 1030,
525
- };
526
-
527
- let url = urls[model];
528
- let dst = "whisper.bin";
529
- let size_mb = sizes[model];
530
-
531
- model_whisper = model;
532
-
533
- document.getElementById("fetch-whisper-tiny-en").style.display = "none";
534
- document.getElementById("fetch-whisper-base-en").style.display = "none";
535
- document.getElementById("fetch-whisper-small-en").style.display =
536
- "none";
537
- document.getElementById("fetch-whisper-tiny").style.display = "none";
538
- document.getElementById("fetch-whisper-base").style.display = "none";
539
- document.getElementById("fetch-whisper-small").style.display = "none";
540
-
541
- document.getElementById("fetch-whisper-tiny-en-q5_1").style.display =
542
- "none";
543
- document.getElementById("fetch-whisper-tiny-q5_1").style.display =
544
- "none";
545
- document.getElementById("fetch-whisper-base-en-q5_1").style.display =
546
- "none";
547
- document.getElementById("fetch-whisper-base-q5_1").style.display =
548
- "none";
549
- document.getElementById("fetch-whisper-small-en-q5_1").style.display =
550
- "none";
551
- document.getElementById("fetch-whisper-small-q5_1").style.display =
552
- "none";
553
- document.getElementById("fetch-whisper-medium-en-q5_0").style.display =
554
- "none";
555
- document.getElementById("fetch-whisper-medium-q5_0").style.display =
556
- "none";
557
- document.getElementById("fetch-whisper-large-q5_0").style.display =
558
- "none";
559
-
560
- document.getElementById("whisper-file").style.display = "none";
561
- document.getElementById("model-whisper-status").innerHTML =
562
- "loading model: " + model;
563
-
564
- cbProgress = function (p) {
565
- let el = document.getElementById("fetch-whisper-progress");
566
- el.innerHTML = Math.round(100 * p) + "%";
567
- };
568
-
569
- cbCancel = function () {
570
- var el;
571
-
572
- el = document.getElementById("fetch-whisper-tiny-en");
573
- if (el) el.style.display = "inline-block";
574
- el = document.getElementById("fetch-whisper-base-en");
575
- if (el) el.style.display = "inline-block";
576
- el = document.getElementById("fetch-whisper-small-en");
577
- if (el) el.style.display = "inline-block";
578
- el = document.getElementById("fetch-whisper-tiny");
579
- if (el) el.style.display = "inline-block";
580
- el = document.getElementById("fetch-whisper-base");
581
- if (el) el.style.display = "inline-block";
582
- el = document.getElementById("fetch-whisper-small");
583
- if (el) el.style.display = "inline-block";
584
-
585
- el = document.getElementById("fetch-whisper-tiny-en-q5_1");
586
- if (el) el.style.display = "inline-block";
587
- el = document.getElementById("fetch-whisper-tiny-q5_1");
588
- if (el) el.style.display = "inline-block";
589
- el = document.getElementById("fetch-whisper-base-en-q5_1");
590
- if (el) el.style.display = "inline-block";
591
- el = document.getElementById("fetch-whisper-base-q5_1");
592
- if (el) el.style.display = "inline-block";
593
- el = document.getElementById("fetch-whisper-small-en-q5_1");
594
- if (el) el.style.display = "inline-block";
595
- el = document.getElementById("fetch-whisper-small-q5_1");
596
- if (el) el.style.display = "inline-block";
597
- el = document.getElementById("fetch-whisper-medium-en-q5_0");
598
- if (el) el.style.display = "inline-block";
599
- el = document.getElementById("fetch-whisper-medium-q5_0");
600
- if (el) el.style.display = "inline-block";
601
- el = document.getElementById("fetch-whisper-large-q5_0");
602
- if (el) el.style.display = "inline-block";
603
-
604
- el = document.getElementById("whisper-file");
605
- if (el) el.style.display = "inline-block";
606
- el = document.getElementById("model-whisper-status");
607
- if (el) el.innerHTML = "";
608
- };
609
-
610
- loadRemote(
611
- url,
612
- dst,
613
- size_mb,
614
- cbProgress,
615
- storeFS,
616
- cbCancel,
617
- printTextarea
618
- );
619
- }
620
-
621
- //
622
- // audio file
623
- //
624
-
625
- const kMaxAudio_s = 30 * 60;
626
- const kMaxRecording_s = 2 * 60;
627
- const kSampleRate = 16000;
628
-
629
- window.AudioContext = window.AudioContext || window.webkitAudioContext;
630
- window.OfflineAudioContext =
631
- window.OfflineAudioContext || window.webkitOfflineAudioContext;
632
-
633
- function loadAudio(event) {
634
- if (!context) {
635
- context = new AudioContext({
636
- sampleRate: kSampleRate,
637
- channelCount: 1,
638
- echoCancellation: false,
639
- autoGainControl: true,
640
- noiseSuppression: true,
641
- });
642
- }
643
-
644
- var file = event.target.files[0] || null;
645
- if (file == null) {
646
- return;
647
- }
648
-
649
- printTextarea(
650
- "js: loading audio: " + file.name + ", size: " + file.size + " bytes"
651
- );
652
- printTextarea("js: please wait ...");
653
-
654
- var reader = new FileReader();
655
- reader.onload = function (event) {
656
- var buf = new Uint8Array(reader.result);
657
-
658
- context.decodeAudioData(
659
- buf.buffer,
660
- function (audioBuffer) {
661
- var offlineContext = new OfflineAudioContext(
662
- audioBuffer.numberOfChannels,
663
- audioBuffer.length,
664
- audioBuffer.sampleRate
665
- );
666
- var source = offlineContext.createBufferSource();
667
- source.buffer = audioBuffer;
668
- source.connect(offlineContext.destination);
669
- source.start(0);
670
-
671
- offlineContext.startRendering().then(function (renderedBuffer) {
672
- audio = renderedBuffer.getChannelData(0);
673
- printTextarea("js: audio loaded, size: " + audio.length);
674
-
675
- // truncate to first 30 seconds
676
- if (audio.length > kMaxAudio_s * kSampleRate) {
677
- audio = audio.slice(0, kMaxAudio_s * kSampleRate);
678
- printTextarea(
679
- "js: truncated audio to first " + kMaxAudio_s + " seconds"
680
- );
681
  }
 
682
 
683
- setAudio(audio);
684
- });
685
- },
686
- function (e) {
687
- printTextarea("js: error decoding audio: " + e);
688
- audio = null;
689
- setAudio(audio);
690
  }
691
- );
692
- };
693
- reader.readAsArrayBuffer(file);
694
- }
695
-
696
- //
697
- // microphone
698
- //
699
-
700
- var mediaRecorder = null;
701
- var doRecording = false;
702
- var startTime = 0;
703
-
704
- function stopRecording() {
705
- doRecording = false;
706
- }
707
-
708
- // record up to kMaxRecording_s seconds of audio from the microphone
709
- // check if doRecording is false every 1000 ms and stop recording if so
710
- // update progress information
711
- function startRecording() {
712
- if (!context) {
713
- context = new AudioContext({
714
- sampleRate: kSampleRate,
715
- channelCount: 1,
716
- echoCancellation: false,
717
- autoGainControl: true,
718
- noiseSuppression: true,
719
- });
720
- }
721
-
722
- document.getElementById("start").disabled = true;
723
- document.getElementById("stop").disabled = false;
724
-
725
- document.getElementById("progress-bar").style.width = "0%";
726
- document.getElementById("progress-text").innerHTML = "0%";
727
-
728
- doRecording = true;
729
- startTime = Date.now();
730
-
731
- var chunks = [];
732
- var stream = null;
733
-
734
- navigator.mediaDevices
735
- .getUserMedia({ audio: true, video: false })
736
- .then(function (s) {
737
- stream = s;
738
- mediaRecorder = new MediaRecorder(stream);
739
- mediaRecorder.ondataavailable = function (e) {
740
- chunks.push(e.data);
741
- };
742
- mediaRecorder.onstop = function (e) {
743
- var blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
744
- chunks = [];
745
-
746
- document.getElementById("start").disabled = false;
747
- document.getElementById("stop").disabled = true;
748
-
749
- var reader = new FileReader();
750
- reader.onload = function (event) {
751
- var buf = new Uint8Array(reader.result);
752
-
753
- context.decodeAudioData(
754
- buf.buffer,
755
- function (audioBuffer) {
756
- var offlineContext = new OfflineAudioContext(
757
- audioBuffer.numberOfChannels,
758
- audioBuffer.length,
759
- audioBuffer.sampleRate
760
- );
761
- var source = offlineContext.createBufferSource();
762
- source.buffer = audioBuffer;
763
- source.connect(offlineContext.destination);
764
- source.start(0);
765
-
766
- offlineContext
767
- .startRendering()
768
- .then(function (renderedBuffer) {
769
- audio = renderedBuffer.getChannelData(0);
770
- printTextarea(
771
- "js: audio recorded, size: " + audio.length
772
- );
773
-
774
- // truncate to first 30 seconds
775
- if (audio.length > kMaxRecording_s * kSampleRate) {
776
- audio = audio.slice(0, kMaxRecording_s * kSampleRate);
777
- printTextarea(
778
- "js: truncated audio to first " +
779
- kMaxRecording_s +
780
- " seconds"
781
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
782
  }
783
- setAudio(audio);
784
- });
785
- },
786
- function (e) {
787
- printTextarea("js: error decoding audio: " + e);
788
- audio = null;
789
- setAudio(audio);
790
- }
791
- );
792
- };
793
-
794
- reader.readAsArrayBuffer(blob);
795
- };
796
- mediaRecorder.start();
797
- })
798
- .catch(function (err) {
799
- printTextarea("js: error getting audio stream: " + err);
800
- });
801
-
802
- var interval = setInterval(function () {
803
- if (!doRecording) {
804
- clearInterval(interval);
805
- mediaRecorder.stop();
806
- stream.getTracks().forEach(function (track) {
807
- track.stop();
808
- });
809
- }
810
-
811
- document.getElementById("progress-bar").style.width =
812
- (100 * (Date.now() - startTime)) / 1000 / kMaxRecording_s + "%";
813
- document.getElementById("progress-text").innerHTML =
814
- ((100 * (Date.now() - startTime)) / 1000 / kMaxRecording_s).toFixed(
815
- 0
816
- ) + "%";
817
- }, 1000);
818
-
819
- printTextarea("js: recording ...");
820
-
821
- setTimeout(function () {
822
- if (doRecording) {
823
- printTextarea(
824
- "js: recording stopped after " + kMaxRecording_s + " seconds"
825
- );
826
- stopRecording();
827
- }
828
- }, kMaxRecording_s * 1000);
829
- }
830
-
831
- //
832
- // transcribe
833
- //
834
-
835
- var nthreads = 8;
836
-
837
- function changeThreads(value) {
838
- nthreads = value;
839
- document.getElementById("threads-value").innerHTML = nthreads;
840
- }
841
-
842
- function onProcess(translate) {
843
- if (!instance) {
844
- instance = Module.init("whisper.bin");
845
-
846
- if (instance) {
847
- printTextarea("js: whisper initialized, instance: " + instance);
848
- document.getElementById("model").innerHTML =
849
- "Model loaded: " + model_whisper;
850
- }
851
- }
852
-
853
- if (!instance) {
854
- printTextarea("js: failed to initialize whisper");
855
- return;
856
- }
857
-
858
- if (!audio) {
859
- printTextarea("js: no audio data");
860
- return;
861
- }
862
-
863
- if (instance) {
864
- printTextarea("");
865
- printTextarea("js: processing - this might take a while ...");
866
- printTextarea("");
867
-
868
- setTimeout(function () {
869
- var ret = Module.full_default(
870
- instance,
871
- audio,
872
- document.getElementById("language").value,
873
- nthreads,
874
- translate
875
- );
876
- console.log("js: full_default returned: " + ret);
877
- if (ret) {
878
- printTextarea("js: whisper returned: " + ret);
879
  }
880
- }, 100);
881
- }
882
- }
883
- </script>
884
- <script type="text/javascript" src="main.js"></script>
885
- </body>
886
  </html>
 
1
  <!doctype html>
2
  <html lang="en-us">
3
+ <head>
4
+ <title>wchess : voice-controlled chess using Whisper + WebAssembly</title>
5
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
6
+
7
+ <meta name="viewport" content="width=device-width, initial-scale=0.4, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
8
+ <meta name="apple-mobile-web-app-capable" content="yes" />
9
+
10
+ <style>
11
+ #output {
12
+ width: 100%;
13
+ height: 100%;
14
+ margin: 0 auto;
15
+ margin-top: 10px;
16
+ border-left: 0px;
17
+ border-right: 0px;
18
+ padding-left: 0px;
19
+ padding-right: 0px;
20
+ display: block;
21
+ background-color: black;
22
+ color: white;
23
+ font-size: 10px;
24
+ font-family: 'Lucida Console', Monaco, monospace;
25
+ outline: none;
26
+ white-space: pre;
27
+ overflow-wrap: normal;
28
+ overflow-x: scroll;
29
+ }
30
+ .button {
31
+ background-color: #000000;
32
+ color: #FFFFFF;
33
+ padding: 20px;
34
+ border-radius: 10px;
35
+ -moz-border-radius: 10px;
36
+ -webkit-border-radius: 10px;
37
+ margin:10px;
38
+ width: 100px;
39
+ height: 50px;
40
+ -webkit-touch-callout: none; /* Safari */
41
+ -webkit-user-select: none; /* Chrome */
42
+ -moz-user-select: none; /* Firefox */
43
+ -ms-user-select: none; /* Internet Explorer/Edge */
44
+ user-select: none;
45
+ }
46
+ .center {
47
+ display: flex;
48
+ justify-content: center;
49
+ align-items: center;
50
+ width: 300px;
51
+ }
52
+ </style>
53
+ <link rel="stylesheet" href="css/chessboard-1.0.0.min.css" integrity="sha384-q94+BZtLrkL1/ohfjR8c6L+A6qzNH9R2hBLwyoAfu3i/WCvQjzL2RQJ3uNHDISdU" crossorigin="anonymous">
54
+ </head>
55
+ <body onload="loadWhisper()">
56
+ <div id="main-container">
57
+ <b>wchess : voice-controlled chess using Whisper + WebAssembly</b>
58
+
59
+ <br><br>
60
+
61
+ This is a demonstration of using Whisper to recognize voice commands in the browser.
62
+
63
+ <br><br>
64
+
65
+ Usage:<br>
66
+
67
+ <ul>
68
+ <li>Hold the button and say a chess move (e.g. "e2-e4")</li>
69
+ <li>Release the button and wait for the move to be recognized</li>
70
+ <li>Repeat</li>
71
+ </ul>
72
+
73
+ Examples:<br>
74
+
75
+ <ul>
76
+ <li><b>"d4"</b></li>
77
+ <li><b>"e2 e4"</b></li>
78
+ <li><b>"Knight to f3"</b></li>
79
+ <li><b>"Bishop to b5"</b></li>
80
+ </ul>
81
+
82
+ Note that not all chess moves are supported. For example, castling and pawn promotion<br>
83
+ currently do not work, but can be easily implemented. The main purpose of this example<br>
84
+ is to demonstrate the capabilities of Whisper and it's application in the browser.
85
+
86
+ <br><br>
87
+
88
+ Features:<br>
89
+
90
+ <ul>
91
+ <li>Model quantization for reduced memory footprint (~42MB)</li>
92
+ <li><a href="https://github.com/ggerganov/whisper.cpp/pull/1229">Grammar-based sampling</a> for improved recognition accuracy</li>
93
+ </ul>
94
+
95
+ You can find more about this project on <a href="https://github.com/ggerganov/whisper.cpp/tree/master/examples/wchess">GitHub</a>.
96
+
97
+ <br><br>
98
+
99
+ <b>More examples:</b>
100
+ <a href="https://whisper.ggerganov.com/">main</a> |
101
+ <a href="https://whisper.ggerganov.com/bench">bench</a> |
102
+ <a href="https://whisper.ggerganov.com/stream">stream</a> |
103
+ <a href="https://whisper.ggerganov.com/command">command</a> |
104
+ <a href="https://whisper.ggerganov.com/talk">talk</a> |
105
+
106
+ <br><br>
107
+
108
+ <hr>
109
+
110
+ <div id="model-whisper">
111
+ Whisper model: <span id="model-whisper-status"></span>
112
+ <span id="fetch-whisper-progress"></span>
113
+ <br><br>
114
+ <button id="clear" onclick="clearCache()">Clear Cache</button>
115
+ <!--
116
+ <input type="file" id="file" name="file" onchange="loadFile(event, 'whisper.bin')" />
117
+ -->
118
+ </div>
119
+
120
+ <br>
121
+ <div id="chessboard" style="width: 300px"></div>
122
+ <script src="js/jquery-3.7.1.min.js"></script>
123
+ <script src="js/chessboard-1.0.0.min.js"></script>
124
+ <script>
125
+ var board = Chessboard('chessboard', 'start')
126
+ var move_count = 0;
127
+ </script>
128
+
129
+ <br>
130
+
131
+ <div id="input" class="center">
132
+ <button id="toggler" class="button" onselectstart="return false" disabled>Hold</button>
133
+ </div>
134
+
135
+ <br>
136
+
137
+ <div id="state">
138
+ Status: <b><span id="state-status">not started</span></b>
139
+
140
+ <pre id="state-moves">[The moves will be displayed here]</pre>
141
+ </div>
142
+
143
+ <hr>
144
+
145
+ Debug output:
146
+ <textarea id="output" rows="20"></textarea>
147
+
148
+ <br>
149
+
150
+ <b>Troubleshooting</b>
151
+
152
+ <br><br>
153
+
154
+ The page does some heavy computations, so make sure:
155
+
156
+ <ul>
157
+ <li>To use a modern web browser (e.g. Chrome, Firefox)</li>
158
+ <li>Your browser supports WASM <a href="https://webassembly.org/roadmap/">Fixed-width SIMD</a></li>
159
+ </ul>
160
+
161
+ <div class="cell-version">
162
+ <span>
163
+ |
164
+ Build time: <span class="nav-link">Fri Dec 8 10:03:41 2023</span> |
165
+ Commit hash: <a class="nav-link" href="https://github.com/ggerganov/whisper.cpp/commit/be5cd736">be5cd736</a> |
166
+ Commit subject: <span class="nav-link">wchess: touchstart, touchend events</span> |
167
+ <a class="nav-link" href="https://github.com/ggerganov/whisper.cpp/tree/master/examples/command.wasm">Source Code</a> |
168
+ </span>
169
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  </div>
171
+
172
+ <script type="text/javascript" src="js/helpers.js"></script>
173
+ <script type='text/javascript'>
174
+ // web audio context
175
+ var context = null;
176
+
177
+ // the command instance
178
+ var instance = null;
179
+
180
+ // model name
181
+ var model_whisper = null;
182
+ var model_file = null;
183
+
184
+ var module_ready = null;
185
+
186
+ var Module = {
187
+ print: printTextarea,
188
+ printErr: printTextarea,
189
+ setStatus: function(text) {
190
+ printTextarea('js: ' + text);
191
+ },
192
+ monitorRunDependencies: function(left) {
193
+ },
194
+ preRun: function() {
195
+ printTextarea('js: Preparing ...');
196
+ },
197
+ postRun: function() {
198
+ printTextarea('js: Module initialized successfully!');
199
+ module_ready = true;
200
+ initInstance();
201
+ }
202
+ };
203
+
204
+ function initInstance() {
205
+ if (!module_ready || !model_file || instance) return
206
+
207
+ instance = Module.init(model_file);
208
+
209
+ if (instance) {
210
+ document.getElementById('toggler').disabled = false;
211
+ setStatus('Ready');
212
+ printTextarea("js: whisper initialized, instance: " + instance);
213
+ }
214
+ else {
215
+ printTextarea("js: failed to initialize whisper");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
217
+ }
218
 
219
+ function setStatus(text) {
220
+ document.getElementById('state-status').innerHTML = text;
 
 
 
 
 
221
  }
222
+
223
+ //
224
+ // fetch models
225
+ //
226
+
227
+ let dbVersion = 1
228
+ let dbName = 'whisper.ggerganov.com';
229
+ let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB
230
+
231
+ function storeFS(fname, buf) {
232
+ // write to WASM file using FS_createDataFile
233
+ // if the file exists, delete it
234
+ try {
235
+ Module.FS_unlink(fname);
236
+ } catch (e) {
237
+ // ignore
238
+ }
239
+
240
+ Module.FS_createDataFile("/", fname, buf, true, true);
241
+
242
+ printTextarea('storeFS: stored model: ' + fname + ' size: ' + buf.length);
243
+
244
+ document.getElementById('model-whisper-status').innerHTML = 'loaded "' + model_whisper + '"!';
245
+
246
+ model_file = fname;
247
+ initInstance();
248
+ }
249
+
250
+ function loadWhisper() {
251
+ setStatus('Loading')
252
+ //let url = 'https://whisper.ggerganov.com/ggml-model-whisper-tiny.en-q8_0.bin';
253
+ let url = 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q8_0.bin';
254
+ let dst = 'whisper.bin';
255
+ let size_mb = 42;
256
+
257
+ model_whisper = 'tiny.en-q8_0';
258
+
259
+ document.getElementById('model-whisper-status').innerHTML = 'loading "' + model_whisper + '" ... ';
260
+
261
+ cbProgress = function(p) {
262
+ let el = document.getElementById('fetch-whisper-progress');
263
+ el.innerHTML = Math.round(100*p) + '%';
264
+ };
265
+
266
+ cbCancel = function() {
267
+ var el;
268
+ el = document.getElementById('model-whisper-status'); if (el) el.innerHTML = '';
269
+ };
270
+
271
+ loadRemote(url, dst, size_mb, cbProgress, storeFS, cbCancel, printTextarea);
272
+ }
273
+
274
+ //
275
+ // microphone
276
+ //
277
+
278
+ const kSampleRate = 16000;
279
+ const kRestartRecording_s = 120;
280
+ const kIntervalAudio_ms = 250; // pass the recorded audio to the C++ instance at this rate
281
+
282
+ var mediaRecorder = null;
283
+ var doRecording = false;
284
+ var startTime = 0;
285
+
286
+ window.AudioContext = window.AudioContext || window.webkitAudioContext;
287
+ window.OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;
288
+
289
+ function stopRecording() {
290
+ mediaRecorder.stop();
291
+ }
292
+
293
+ function startRecording() {
294
+ if (!context) {
295
+ context = new AudioContext({
296
+ sampleRate: kSampleRate,
297
+ channelCount: 1,
298
+ echoCancellation: false,
299
+ autoGainControl: true,
300
+ noiseSuppression: true,
301
+ });
302
+ }
303
+
304
+ startTime = Date.now();
305
+
306
+ var chunks = [];
307
+ var stream = null;
308
+
309
+ navigator.mediaDevices.getUserMedia({audio: true, video: false})
310
+ .then(function(s) {
311
+ stream = s;
312
+ mediaRecorder = new MediaRecorder(stream);
313
+ mediaRecorder.ondataavailable = function(e) {
314
+ chunks.push(e.data);
315
+
316
+ var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
317
+ var reader = new FileReader();
318
+
319
+ reader.onload = function(event) {
320
+ var buf = new Uint8Array(reader.result);
321
+ context.decodeAudioData(buf.buffer, function(audioBuffer) {
322
+ var offlineContext = new OfflineAudioContext(audioBuffer.numberOfChannels, audioBuffer.length, audioBuffer.sampleRate);
323
+ var source = offlineContext.createBufferSource();
324
+ source.buffer = audioBuffer;
325
+ source.connect(offlineContext.destination);
326
+ source.start(0);
327
+
328
+ offlineContext.startRendering().then(function(renderedBuffer) {
329
+ let audio = renderedBuffer.getChannelData(0);
330
+ printTextarea('js: number of samples: ' + audio.length);
331
+ Module.set_audio(instance, audio);
332
+ });
333
+
334
+ mediaRecorder = null;
335
+ context = null;
336
+ });
337
+ }
338
+
339
+ reader.readAsArrayBuffer(blob);
340
+ };
341
+
342
+ mediaRecorder.onstop = function(e) {
343
+ stream.getTracks().forEach(function(track) {
344
+ track.stop();
345
+ });
346
+ };
347
+
348
+ mediaRecorder.start();
349
+ })
350
+ .catch(function(err) {
351
+ printTextarea('js: error getting audio stream: ' + err);
352
+ });
353
+ }
354
+
355
+ //
356
+ // main
357
+ //
358
+
359
+ var nLines = 0;
360
+ var movesAll = '';
361
+
362
+ // document.body.addEventListener('keydown', function(event) {
363
+ // if (event.keyCode === 32) {
364
+ // document.getElementById('toggler').innerText = "";
365
+ // onStart();
366
+ // }
367
+ // }, true);
368
+
369
+ // document.body.addEventListener('keyup', function(event) {
370
+ // if (event.keyCode === 32) {
371
+ // document.getElementById('toggler').innerText = "Hold";
372
+ // onStop();
373
+ // }
374
+ // }, true);
375
+
376
+ document.getElementById('toggler').addEventListener("touchstart", function(event){
377
+ this.innerText = "";
378
+ onStart();
379
+ }, true);
380
+
381
+ document.getElementById('toggler').addEventListener("touchend", function(event){
382
+ this.innerText = "Hold";
383
+ onStop();
384
+ }, true)
385
+
386
+ document.getElementById('toggler').addEventListener('mousedown', function(event) {
387
+ this.innerText = "";
388
+ onStart();
389
+ }, true);
390
+
391
+ document.getElementById('toggler').addEventListener('mouseup', function(event) {
392
+ this.innerText = "Hold";
393
+ onStop();
394
+ }, true);
395
+
396
+ function onStart() {
397
+ if (!instance) return;
398
+ setStatus('Listening');
399
+
400
+ startRecording();
401
+ }
402
+
403
+ function onStop() {
404
+ setStatus('Processing');
405
+ printTextarea('js: stopping recording ...');
406
+ stopRecording();
407
+ }
408
+
409
+ function setMove(move, prob) {
410
+ if (move != null && move.length > 1) {
411
+ let gameOver = move[move.length - 1] === '#';
412
+ if (gameOver) {
413
+ move = move.substring(0, move.length - 1);
414
+ document.getElementById('toggler').disabled = true;
415
+ }
416
+ board.move(move);
417
+
418
+ movesAll += move + ', prob = ' + prob.toFixed(2) + '% <br>';
419
+ nLines++;
420
+
421
+ // if more than 10 lines, remove the first line
422
+ if (nLines > 10) {
423
+ var i = movesAll.indexOf('<br>');
424
+ if (i > 0) {
425
+ movesAll = movesAll.substring(i + 4);
426
+ nLines--;
427
  }
428
+ }
429
+ ++move_count;
430
+ setStatus(gameOver ? 'Done' : move_count % 2 ? 'Black\'s turn' : 'White\'s turn');
431
+ document.getElementById('state-moves').innerHTML = movesAll;
432
+ }
433
+ else {
434
+ setStatus('Failed. ' + (move_count % 2 ? 'Black\'s turn' : 'White\'s turn'));
435
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
+
438
+ </script>
439
+ <script type="text/javascript" src="js/chess.js"></script>
440
+ </body>
 
 
441
  </html>
js/chess.js ADDED
The diff for this file is too large to render. See raw diff
 
js/chessboard-1.0.0.js ADDED
@@ -0,0 +1,1817 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // chessboard.js v1.0.0
2
+ // https://github.com/oakmac/chessboardjs/
3
+ //
4
+ // Copyright (c) 2019, Chris Oakman
5
+ // Released under the MIT license
6
+ // https://github.com/oakmac/chessboardjs/blob/master/LICENSE.md
7
+
8
+ // start anonymous scope
9
+ ;(function () {
10
+ 'use strict'
11
+
12
+ var $ = window['jQuery']
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Constants
16
+ // ---------------------------------------------------------------------------
17
+
18
+ var COLUMNS = 'abcdefgh'.split('')
19
+ var DEFAULT_DRAG_THROTTLE_RATE = 20
20
+ var ELLIPSIS = '…'
21
+ var MINIMUM_JQUERY_VERSION = '1.8.3'
22
+ var RUN_ASSERTS = false
23
+ var START_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
24
+ var START_POSITION = fenToObj(START_FEN)
25
+
26
+ // default animation speeds
27
+ var DEFAULT_APPEAR_SPEED = 200
28
+ var DEFAULT_MOVE_SPEED = 200
29
+ var DEFAULT_SNAPBACK_SPEED = 60
30
+ var DEFAULT_SNAP_SPEED = 30
31
+ var DEFAULT_TRASH_SPEED = 100
32
+
33
+ // use unique class names to prevent clashing with anything else on the page
34
+ // and simplify selectors
35
+ // NOTE: these should never change
36
+ var CSS = {}
37
+ CSS['alpha'] = 'alpha-d2270'
38
+ CSS['black'] = 'black-3c85d'
39
+ CSS['board'] = 'board-b72b1'
40
+ CSS['chessboard'] = 'chessboard-63f37'
41
+ CSS['clearfix'] = 'clearfix-7da63'
42
+ CSS['highlight1'] = 'highlight1-32417'
43
+ CSS['highlight2'] = 'highlight2-9c5d2'
44
+ CSS['notation'] = 'notation-322f9'
45
+ CSS['numeric'] = 'numeric-fc462'
46
+ CSS['piece'] = 'piece-417db'
47
+ CSS['row'] = 'row-5277c'
48
+ CSS['sparePieces'] = 'spare-pieces-7492f'
49
+ CSS['sparePiecesBottom'] = 'spare-pieces-bottom-ae20f'
50
+ CSS['sparePiecesTop'] = 'spare-pieces-top-4028b'
51
+ CSS['square'] = 'square-55d63'
52
+ CSS['white'] = 'white-1e1d7'
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // Misc Util Functions
56
+ // ---------------------------------------------------------------------------
57
+
58
+ function throttle (f, interval, scope) {
59
+ var timeout = 0
60
+ var shouldFire = false
61
+ var args = []
62
+
63
+ var handleTimeout = function () {
64
+ timeout = 0
65
+ if (shouldFire) {
66
+ shouldFire = false
67
+ fire()
68
+ }
69
+ }
70
+
71
+ var fire = function () {
72
+ timeout = window.setTimeout(handleTimeout, interval)
73
+ f.apply(scope, args)
74
+ }
75
+
76
+ return function (_args) {
77
+ args = arguments
78
+ if (!timeout) {
79
+ fire()
80
+ } else {
81
+ shouldFire = true
82
+ }
83
+ }
84
+ }
85
+
86
+ // function debounce (f, interval, scope) {
87
+ // var timeout = 0
88
+ // return function (_args) {
89
+ // window.clearTimeout(timeout)
90
+ // var args = arguments
91
+ // timeout = window.setTimeout(function () {
92
+ // f.apply(scope, args)
93
+ // }, interval)
94
+ // }
95
+ // }
96
+
97
+ function uuid () {
98
+ return 'xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx'.replace(/x/g, function (c) {
99
+ var r = (Math.random() * 16) | 0
100
+ return r.toString(16)
101
+ })
102
+ }
103
+
104
+ function deepCopy (thing) {
105
+ return JSON.parse(JSON.stringify(thing))
106
+ }
107
+
108
+ function parseSemVer (version) {
109
+ var tmp = version.split('.')
110
+ return {
111
+ major: parseInt(tmp[0], 10),
112
+ minor: parseInt(tmp[1], 10),
113
+ patch: parseInt(tmp[2], 10)
114
+ }
115
+ }
116
+
117
+ // returns true if version is >= minimum
118
+ function validSemanticVersion (version, minimum) {
119
+ version = parseSemVer(version)
120
+ minimum = parseSemVer(minimum)
121
+
122
+ var versionNum = (version.major * 100000 * 100000) +
123
+ (version.minor * 100000) +
124
+ version.patch
125
+ var minimumNum = (minimum.major * 100000 * 100000) +
126
+ (minimum.minor * 100000) +
127
+ minimum.patch
128
+
129
+ return versionNum >= minimumNum
130
+ }
131
+
132
+ function interpolateTemplate (str, obj) {
133
+ for (var key in obj) {
134
+ if (!obj.hasOwnProperty(key)) continue
135
+ var keyTemplateStr = '{' + key + '}'
136
+ var value = obj[key]
137
+ while (str.indexOf(keyTemplateStr) !== -1) {
138
+ str = str.replace(keyTemplateStr, value)
139
+ }
140
+ }
141
+ return str
142
+ }
143
+
144
+ if (RUN_ASSERTS) {
145
+ console.assert(interpolateTemplate('abc', {a: 'x'}) === 'abc')
146
+ console.assert(interpolateTemplate('{a}bc', {}) === '{a}bc')
147
+ console.assert(interpolateTemplate('{a}bc', {p: 'q'}) === '{a}bc')
148
+ console.assert(interpolateTemplate('{a}bc', {a: 'x'}) === 'xbc')
149
+ console.assert(interpolateTemplate('{a}bc{a}bc', {a: 'x'}) === 'xbcxbc')
150
+ console.assert(interpolateTemplate('{a}{a}{b}', {a: 'x', b: 'y'}) === 'xxy')
151
+ }
152
+
153
+ // ---------------------------------------------------------------------------
154
+ // Predicates
155
+ // ---------------------------------------------------------------------------
156
+
157
+ function isString (s) {
158
+ return typeof s === 'string'
159
+ }
160
+
161
+ function isFunction (f) {
162
+ return typeof f === 'function'
163
+ }
164
+
165
+ function isInteger (n) {
166
+ return typeof n === 'number' &&
167
+ isFinite(n) &&
168
+ Math.floor(n) === n
169
+ }
170
+
171
+ function validAnimationSpeed (speed) {
172
+ if (speed === 'fast' || speed === 'slow') return true
173
+ if (!isInteger(speed)) return false
174
+ return speed >= 0
175
+ }
176
+
177
+ function validThrottleRate (rate) {
178
+ return isInteger(rate) &&
179
+ rate >= 1
180
+ }
181
+
182
+ function validMove (move) {
183
+ // move should be a string
184
+ if (!isString(move)) return false
185
+
186
+ // move should be in the form of "e2-e4", "f6-d5"
187
+ var squares = move.split('-')
188
+ if (squares.length !== 2) return false
189
+
190
+ return validSquare(squares[0]) && validSquare(squares[1])
191
+ }
192
+
193
+ function validSquare (square) {
194
+ return isString(square) && square.search(/^[a-h][1-8]$/) !== -1
195
+ }
196
+
197
+ if (RUN_ASSERTS) {
198
+ console.assert(validSquare('a1'))
199
+ console.assert(validSquare('e2'))
200
+ console.assert(!validSquare('D2'))
201
+ console.assert(!validSquare('g9'))
202
+ console.assert(!validSquare('a'))
203
+ console.assert(!validSquare(true))
204
+ console.assert(!validSquare(null))
205
+ console.assert(!validSquare({}))
206
+ }
207
+
208
+ function validPieceCode (code) {
209
+ return isString(code) && code.search(/^[bw][KQRNBP]$/) !== -1
210
+ }
211
+
212
+ if (RUN_ASSERTS) {
213
+ console.assert(validPieceCode('bP'))
214
+ console.assert(validPieceCode('bK'))
215
+ console.assert(validPieceCode('wK'))
216
+ console.assert(validPieceCode('wR'))
217
+ console.assert(!validPieceCode('WR'))
218
+ console.assert(!validPieceCode('Wr'))
219
+ console.assert(!validPieceCode('a'))
220
+ console.assert(!validPieceCode(true))
221
+ console.assert(!validPieceCode(null))
222
+ console.assert(!validPieceCode({}))
223
+ }
224
+
225
+ function validFen (fen) {
226
+ if (!isString(fen)) return false
227
+
228
+ // cut off any move, castling, etc info from the end
229
+ // we're only interested in position information
230
+ fen = fen.replace(/ .+$/, '')
231
+
232
+ // expand the empty square numbers to just 1s
233
+ fen = expandFenEmptySquares(fen)
234
+
235
+ // FEN should be 8 sections separated by slashes
236
+ var chunks = fen.split('/')
237
+ if (chunks.length !== 8) return false
238
+
239
+ // check each section
240
+ for (var i = 0; i < 8; i++) {
241
+ if (chunks[i].length !== 8 ||
242
+ chunks[i].search(/[^kqrnbpKQRNBP1]/) !== -1) {
243
+ return false
244
+ }
245
+ }
246
+
247
+ return true
248
+ }
249
+
250
+ if (RUN_ASSERTS) {
251
+ console.assert(validFen(START_FEN))
252
+ console.assert(validFen('8/8/8/8/8/8/8/8'))
253
+ console.assert(validFen('r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R'))
254
+ console.assert(validFen('3r3r/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1'))
255
+ console.assert(!validFen('3r3z/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1'))
256
+ console.assert(!validFen('anbqkbnr/8/8/8/8/8/PPPPPPPP/8'))
257
+ console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/'))
258
+ console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBN'))
259
+ console.assert(!validFen('888888/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'))
260
+ console.assert(!validFen('888888/pppppppp/74/8/8/8/PPPPPPPP/RNBQKBNR'))
261
+ console.assert(!validFen({}))
262
+ }
263
+
264
+ function validPositionObject (pos) {
265
+ if (!$.isPlainObject(pos)) return false
266
+
267
+ for (var i in pos) {
268
+ if (!pos.hasOwnProperty(i)) continue
269
+
270
+ if (!validSquare(i) || !validPieceCode(pos[i])) {
271
+ return false
272
+ }
273
+ }
274
+
275
+ return true
276
+ }
277
+
278
+ if (RUN_ASSERTS) {
279
+ console.assert(validPositionObject(START_POSITION))
280
+ console.assert(validPositionObject({}))
281
+ console.assert(validPositionObject({e2: 'wP'}))
282
+ console.assert(validPositionObject({e2: 'wP', d2: 'wP'}))
283
+ console.assert(!validPositionObject({e2: 'BP'}))
284
+ console.assert(!validPositionObject({y2: 'wP'}))
285
+ console.assert(!validPositionObject(null))
286
+ console.assert(!validPositionObject('start'))
287
+ console.assert(!validPositionObject(START_FEN))
288
+ }
289
+
290
+ function isTouchDevice () {
291
+ return 'ontouchstart' in document.documentElement
292
+ }
293
+
294
+ function validJQueryVersion () {
295
+ return typeof window.$ &&
296
+ $.fn &&
297
+ $.fn.jquery &&
298
+ validSemanticVersion($.fn.jquery, MINIMUM_JQUERY_VERSION)
299
+ }
300
+
301
+ // ---------------------------------------------------------------------------
302
+ // Chess Util Functions
303
+ // ---------------------------------------------------------------------------
304
+
305
+ // convert FEN piece code to bP, wK, etc
306
+ function fenToPieceCode (piece) {
307
+ // black piece
308
+ if (piece.toLowerCase() === piece) {
309
+ return 'b' + piece.toUpperCase()
310
+ }
311
+
312
+ // white piece
313
+ return 'w' + piece.toUpperCase()
314
+ }
315
+
316
+ // convert bP, wK, etc code to FEN structure
317
+ function pieceCodeToFen (piece) {
318
+ var pieceCodeLetters = piece.split('')
319
+
320
+ // white piece
321
+ if (pieceCodeLetters[0] === 'w') {
322
+ return pieceCodeLetters[1].toUpperCase()
323
+ }
324
+
325
+ // black piece
326
+ return pieceCodeLetters[1].toLowerCase()
327
+ }
328
+
329
+ // convert FEN string to position object
330
+ // returns false if the FEN string is invalid
331
+ function fenToObj (fen) {
332
+ if (!validFen(fen)) return false
333
+
334
+ // cut off any move, castling, etc info from the end
335
+ // we're only interested in position information
336
+ fen = fen.replace(/ .+$/, '')
337
+
338
+ var rows = fen.split('/')
339
+ var position = {}
340
+
341
+ var currentRow = 8
342
+ for (var i = 0; i < 8; i++) {
343
+ var row = rows[i].split('')
344
+ var colIdx = 0
345
+
346
+ // loop through each character in the FEN section
347
+ for (var j = 0; j < row.length; j++) {
348
+ // number / empty squares
349
+ if (row[j].search(/[1-8]/) !== -1) {
350
+ var numEmptySquares = parseInt(row[j], 10)
351
+ colIdx = colIdx + numEmptySquares
352
+ } else {
353
+ // piece
354
+ var square = COLUMNS[colIdx] + currentRow
355
+ position[square] = fenToPieceCode(row[j])
356
+ colIdx = colIdx + 1
357
+ }
358
+ }
359
+
360
+ currentRow = currentRow - 1
361
+ }
362
+
363
+ return position
364
+ }
365
+
366
+ // position object to FEN string
367
+ // returns false if the obj is not a valid position object
368
+ function objToFen (obj) {
369
+ if (!validPositionObject(obj)) return false
370
+
371
+ var fen = ''
372
+
373
+ var currentRow = 8
374
+ for (var i = 0; i < 8; i++) {
375
+ for (var j = 0; j < 8; j++) {
376
+ var square = COLUMNS[j] + currentRow
377
+
378
+ // piece exists
379
+ if (obj.hasOwnProperty(square)) {
380
+ fen = fen + pieceCodeToFen(obj[square])
381
+ } else {
382
+ // empty space
383
+ fen = fen + '1'
384
+ }
385
+ }
386
+
387
+ if (i !== 7) {
388
+ fen = fen + '/'
389
+ }
390
+
391
+ currentRow = currentRow - 1
392
+ }
393
+
394
+ // squeeze the empty numbers together
395
+ fen = squeezeFenEmptySquares(fen)
396
+
397
+ return fen
398
+ }
399
+
400
+ if (RUN_ASSERTS) {
401
+ console.assert(objToFen(START_POSITION) === START_FEN)
402
+ console.assert(objToFen({}) === '8/8/8/8/8/8/8/8')
403
+ console.assert(objToFen({a2: 'wP', 'b2': 'bP'}) === '8/8/8/8/8/8/Pp6/8')
404
+ }
405
+
406
+ function squeezeFenEmptySquares (fen) {
407
+ return fen.replace(/11111111/g, '8')
408
+ .replace(/1111111/g, '7')
409
+ .replace(/111111/g, '6')
410
+ .replace(/11111/g, '5')
411
+ .replace(/1111/g, '4')
412
+ .replace(/111/g, '3')
413
+ .replace(/11/g, '2')
414
+ }
415
+
416
+ function expandFenEmptySquares (fen) {
417
+ return fen.replace(/8/g, '11111111')
418
+ .replace(/7/g, '1111111')
419
+ .replace(/6/g, '111111')
420
+ .replace(/5/g, '11111')
421
+ .replace(/4/g, '1111')
422
+ .replace(/3/g, '111')
423
+ .replace(/2/g, '11')
424
+ }
425
+
426
+ // returns the distance between two squares
427
+ function squareDistance (squareA, squareB) {
428
+ var squareAArray = squareA.split('')
429
+ var squareAx = COLUMNS.indexOf(squareAArray[0]) + 1
430
+ var squareAy = parseInt(squareAArray[1], 10)
431
+
432
+ var squareBArray = squareB.split('')
433
+ var squareBx = COLUMNS.indexOf(squareBArray[0]) + 1
434
+ var squareBy = parseInt(squareBArray[1], 10)
435
+
436
+ var xDelta = Math.abs(squareAx - squareBx)
437
+ var yDelta = Math.abs(squareAy - squareBy)
438
+
439
+ if (xDelta >= yDelta) return xDelta
440
+ return yDelta
441
+ }
442
+
443
+ // returns the square of the closest instance of piece
444
+ // returns false if no instance of piece is found in position
445
+ function findClosestPiece (position, piece, square) {
446
+ // create array of closest squares from square
447
+ var closestSquares = createRadius(square)
448
+
449
+ // search through the position in order of distance for the piece
450
+ for (var i = 0; i < closestSquares.length; i++) {
451
+ var s = closestSquares[i]
452
+
453
+ if (position.hasOwnProperty(s) && position[s] === piece) {
454
+ return s
455
+ }
456
+ }
457
+
458
+ return false
459
+ }
460
+
461
+ // returns an array of closest squares from square
462
+ function createRadius (square) {
463
+ var squares = []
464
+
465
+ // calculate distance of all squares
466
+ for (var i = 0; i < 8; i++) {
467
+ for (var j = 0; j < 8; j++) {
468
+ var s = COLUMNS[i] + (j + 1)
469
+
470
+ // skip the square we're starting from
471
+ if (square === s) continue
472
+
473
+ squares.push({
474
+ square: s,
475
+ distance: squareDistance(square, s)
476
+ })
477
+ }
478
+ }
479
+
480
+ // sort by distance
481
+ squares.sort(function (a, b) {
482
+ return a.distance - b.distance
483
+ })
484
+
485
+ // just return the square code
486
+ var surroundingSquares = []
487
+ for (i = 0; i < squares.length; i++) {
488
+ surroundingSquares.push(squares[i].square)
489
+ }
490
+
491
+ return surroundingSquares
492
+ }
493
+
494
+ // given a position and a set of moves, return a new position
495
+ // with the moves executed
496
+ function calculatePositionFromMoves (position, moves) {
497
+ var newPosition = deepCopy(position)
498
+
499
+ for (var i in moves) {
500
+ if (!moves.hasOwnProperty(i)) continue
501
+
502
+ // skip the move if the position doesn't have a piece on the source square
503
+ if (!newPosition.hasOwnProperty(i)) continue
504
+
505
+ var piece = newPosition[i]
506
+ delete newPosition[i]
507
+ newPosition[moves[i]] = piece
508
+ }
509
+
510
+ return newPosition
511
+ }
512
+
513
+ // TODO: add some asserts here for calculatePositionFromMoves
514
+
515
+ // ---------------------------------------------------------------------------
516
+ // HTML
517
+ // ---------------------------------------------------------------------------
518
+
519
+ function buildContainerHTML (hasSparePieces) {
520
+ var html = '<div class="{chessboard}">'
521
+
522
+ if (hasSparePieces) {
523
+ html += '<div class="{sparePieces} {sparePiecesTop}"></div>'
524
+ }
525
+
526
+ html += '<div class="{board}"></div>'
527
+
528
+ if (hasSparePieces) {
529
+ html += '<div class="{sparePieces} {sparePiecesBottom}"></div>'
530
+ }
531
+
532
+ html += '</div>'
533
+
534
+ return interpolateTemplate(html, CSS)
535
+ }
536
+
537
+ // ---------------------------------------------------------------------------
538
+ // Config
539
+ // ---------------------------------------------------------------------------
540
+
541
+ function expandConfigArgumentShorthand (config) {
542
+ if (config === 'start') {
543
+ config = {position: deepCopy(START_POSITION)}
544
+ } else if (validFen(config)) {
545
+ config = {position: fenToObj(config)}
546
+ } else if (validPositionObject(config)) {
547
+ config = {position: deepCopy(config)}
548
+ }
549
+
550
+ // config must be an object
551
+ if (!$.isPlainObject(config)) config = {}
552
+
553
+ return config
554
+ }
555
+
556
+ // validate config / set default options
557
+ function expandConfig (config) {
558
+ // default for orientation is white
559
+ if (config.orientation !== 'black') config.orientation = 'white'
560
+
561
+ // default for showNotation is true
562
+ if (config.showNotation !== false) config.showNotation = true
563
+
564
+ // default for draggable is false
565
+ if (config.draggable !== true) config.draggable = false
566
+
567
+ // default for dropOffBoard is 'snapback'
568
+ if (config.dropOffBoard !== 'trash') config.dropOffBoard = 'snapback'
569
+
570
+ // default for sparePieces is false
571
+ if (config.sparePieces !== true) config.sparePieces = false
572
+
573
+ // draggable must be true if sparePieces is enabled
574
+ if (config.sparePieces) config.draggable = true
575
+
576
+ // default piece theme is wikipedia
577
+ if (!config.hasOwnProperty('pieceTheme') ||
578
+ (!isString(config.pieceTheme) && !isFunction(config.pieceTheme))) {
579
+ config.pieceTheme = 'img/chesspieces/wikipedia/{piece}.png'
580
+ }
581
+
582
+ // animation speeds
583
+ if (!validAnimationSpeed(config.appearSpeed)) config.appearSpeed = DEFAULT_APPEAR_SPEED
584
+ if (!validAnimationSpeed(config.moveSpeed)) config.moveSpeed = DEFAULT_MOVE_SPEED
585
+ if (!validAnimationSpeed(config.snapbackSpeed)) config.snapbackSpeed = DEFAULT_SNAPBACK_SPEED
586
+ if (!validAnimationSpeed(config.snapSpeed)) config.snapSpeed = DEFAULT_SNAP_SPEED
587
+ if (!validAnimationSpeed(config.trashSpeed)) config.trashSpeed = DEFAULT_TRASH_SPEED
588
+
589
+ // throttle rate
590
+ if (!validThrottleRate(config.dragThrottleRate)) config.dragThrottleRate = DEFAULT_DRAG_THROTTLE_RATE
591
+
592
+ return config
593
+ }
594
+
595
+ // ---------------------------------------------------------------------------
596
+ // Dependencies
597
+ // ---------------------------------------------------------------------------
598
+
599
+ // check for a compatible version of jQuery
600
+ function checkJQuery () {
601
+ if (!validJQueryVersion()) {
602
+ var errorMsg = 'Chessboard Error 1005: Unable to find a valid version of jQuery. ' +
603
+ 'Please include jQuery ' + MINIMUM_JQUERY_VERSION + ' or higher on the page' +
604
+ '\n\n' +
605
+ 'Exiting' + ELLIPSIS
606
+ window.alert(errorMsg)
607
+ return false
608
+ }
609
+
610
+ return true
611
+ }
612
+
613
+ // return either boolean false or the $container element
614
+ function checkContainerArg (containerElOrString) {
615
+ if (containerElOrString === '') {
616
+ var errorMsg1 = 'Chessboard Error 1001: ' +
617
+ 'The first argument to Chessboard() cannot be an empty string.' +
618
+ '\n\n' +
619
+ 'Exiting' + ELLIPSIS
620
+ window.alert(errorMsg1)
621
+ return false
622
+ }
623
+
624
+ // convert containerEl to query selector if it is a string
625
+ if (isString(containerElOrString) &&
626
+ containerElOrString.charAt(0) !== '#') {
627
+ containerElOrString = '#' + containerElOrString
628
+ }
629
+
630
+ // containerEl must be something that becomes a jQuery collection of size 1
631
+ var $container = $(containerElOrString)
632
+ if ($container.length !== 1) {
633
+ var errorMsg2 = 'Chessboard Error 1003: ' +
634
+ 'The first argument to Chessboard() must be the ID of a DOM node, ' +
635
+ 'an ID query selector, or a single DOM node.' +
636
+ '\n\n' +
637
+ 'Exiting' + ELLIPSIS
638
+ window.alert(errorMsg2)
639
+ return false
640
+ }
641
+
642
+ return $container
643
+ }
644
+
645
+ // ---------------------------------------------------------------------------
646
+ // Constructor
647
+ // ---------------------------------------------------------------------------
648
+
649
+ function constructor (containerElOrString, config) {
650
+ // first things first: check basic dependencies
651
+ if (!checkJQuery()) return null
652
+ var $container = checkContainerArg(containerElOrString)
653
+ if (!$container) return null
654
+
655
+ // ensure the config object is what we expect
656
+ config = expandConfigArgumentShorthand(config)
657
+ config = expandConfig(config)
658
+
659
+ // DOM elements
660
+ var $board = null
661
+ var $draggedPiece = null
662
+ var $sparePiecesTop = null
663
+ var $sparePiecesBottom = null
664
+
665
+ // constructor return object
666
+ var widget = {}
667
+
668
+ // -------------------------------------------------------------------------
669
+ // Stateful
670
+ // -------------------------------------------------------------------------
671
+
672
+ var boardBorderSize = 2
673
+ var currentOrientation = 'white'
674
+ var currentPosition = {}
675
+ var draggedPiece = null
676
+ var draggedPieceLocation = null
677
+ var draggedPieceSource = null
678
+ var isDragging = false
679
+ var sparePiecesElsIds = {}
680
+ var squareElsIds = {}
681
+ var squareElsOffsets = {}
682
+ var squareSize = 16
683
+
684
+ // -------------------------------------------------------------------------
685
+ // Validation / Errors
686
+ // -------------------------------------------------------------------------
687
+
688
+ function error (code, msg, obj) {
689
+ // do nothing if showErrors is not set
690
+ if (
691
+ config.hasOwnProperty('showErrors') !== true ||
692
+ config.showErrors === false
693
+ ) {
694
+ return
695
+ }
696
+
697
+ var errorText = 'Chessboard Error ' + code + ': ' + msg
698
+
699
+ // print to console
700
+ if (
701
+ config.showErrors === 'console' &&
702
+ typeof console === 'object' &&
703
+ typeof console.log === 'function'
704
+ ) {
705
+ console.log(errorText)
706
+ if (arguments.length >= 2) {
707
+ console.log(obj)
708
+ }
709
+ return
710
+ }
711
+
712
+ // alert errors
713
+ if (config.showErrors === 'alert') {
714
+ if (obj) {
715
+ errorText += '\n\n' + JSON.stringify(obj)
716
+ }
717
+ window.alert(errorText)
718
+ return
719
+ }
720
+
721
+ // custom function
722
+ if (isFunction(config.showErrors)) {
723
+ config.showErrors(code, msg, obj)
724
+ }
725
+ }
726
+
727
+ function setInitialState () {
728
+ currentOrientation = config.orientation
729
+
730
+ // make sure position is valid
731
+ if (config.hasOwnProperty('position')) {
732
+ if (config.position === 'start') {
733
+ currentPosition = deepCopy(START_POSITION)
734
+ } else if (validFen(config.position)) {
735
+ currentPosition = fenToObj(config.position)
736
+ } else if (validPositionObject(config.position)) {
737
+ currentPosition = deepCopy(config.position)
738
+ } else {
739
+ error(
740
+ 7263,
741
+ 'Invalid value passed to config.position.',
742
+ config.position
743
+ )
744
+ }
745
+ }
746
+ }
747
+
748
+ // -------------------------------------------------------------------------
749
+ // DOM Misc
750
+ // -------------------------------------------------------------------------
751
+
752
+ // calculates square size based on the width of the container
753
+ // got a little CSS black magic here, so let me explain:
754
+ // get the width of the container element (could be anything), reduce by 1 for
755
+ // fudge factor, and then keep reducing until we find an exact mod 8 for
756
+ // our square size
757
+ function calculateSquareSize () {
758
+ var containerWidth = parseInt($container.width(), 10)
759
+
760
+ // defensive, prevent infinite loop
761
+ if (!containerWidth || containerWidth <= 0) {
762
+ return 0
763
+ }
764
+
765
+ // pad one pixel
766
+ var boardWidth = containerWidth - 1
767
+
768
+ while (boardWidth % 8 !== 0 && boardWidth > 0) {
769
+ boardWidth = boardWidth - 1
770
+ }
771
+
772
+ return boardWidth / 8
773
+ }
774
+
775
+ // create random IDs for elements
776
+ function createElIds () {
777
+ // squares on the board
778
+ for (var i = 0; i < COLUMNS.length; i++) {
779
+ for (var j = 1; j <= 8; j++) {
780
+ var square = COLUMNS[i] + j
781
+ squareElsIds[square] = square + '-' + uuid()
782
+ }
783
+ }
784
+
785
+ // spare pieces
786
+ var pieces = 'KQRNBP'.split('')
787
+ for (i = 0; i < pieces.length; i++) {
788
+ var whitePiece = 'w' + pieces[i]
789
+ var blackPiece = 'b' + pieces[i]
790
+ sparePiecesElsIds[whitePiece] = whitePiece + '-' + uuid()
791
+ sparePiecesElsIds[blackPiece] = blackPiece + '-' + uuid()
792
+ }
793
+ }
794
+
795
+ // -------------------------------------------------------------------------
796
+ // Markup Building
797
+ // -------------------------------------------------------------------------
798
+
799
+ function buildBoardHTML (orientation) {
800
+ if (orientation !== 'black') {
801
+ orientation = 'white'
802
+ }
803
+
804
+ var html = ''
805
+
806
+ // algebraic notation / orientation
807
+ var alpha = deepCopy(COLUMNS)
808
+ var row = 8
809
+ if (orientation === 'black') {
810
+ alpha.reverse()
811
+ row = 1
812
+ }
813
+
814
+ var squareColor = 'white'
815
+ for (var i = 0; i < 8; i++) {
816
+ html += '<div class="{row}">'
817
+ for (var j = 0; j < 8; j++) {
818
+ var square = alpha[j] + row
819
+
820
+ html += '<div class="{square} ' + CSS[squareColor] + ' ' +
821
+ 'square-' + square + '" ' +
822
+ 'style="width:' + squareSize + 'px;height:' + squareSize + 'px;" ' +
823
+ 'id="' + squareElsIds[square] + '" ' +
824
+ 'data-square="' + square + '">'
825
+
826
+ if (config.showNotation) {
827
+ // alpha notation
828
+ if ((orientation === 'white' && row === 1) ||
829
+ (orientation === 'black' && row === 8)) {
830
+ html += '<div class="{notation} {alpha}">' + alpha[j] + '</div>'
831
+ }
832
+
833
+ // numeric notation
834
+ if (j === 0) {
835
+ html += '<div class="{notation} {numeric}">' + row + '</div>'
836
+ }
837
+ }
838
+
839
+ html += '</div>' // end .square
840
+
841
+ squareColor = (squareColor === 'white') ? 'black' : 'white'
842
+ }
843
+ html += '<div class="{clearfix}"></div></div>'
844
+
845
+ squareColor = (squareColor === 'white') ? 'black' : 'white'
846
+
847
+ if (orientation === 'white') {
848
+ row = row - 1
849
+ } else {
850
+ row = row + 1
851
+ }
852
+ }
853
+
854
+ return interpolateTemplate(html, CSS)
855
+ }
856
+
857
+ function buildPieceImgSrc (piece) {
858
+ if (isFunction(config.pieceTheme)) {
859
+ return config.pieceTheme(piece)
860
+ }
861
+
862
+ if (isString(config.pieceTheme)) {
863
+ return interpolateTemplate(config.pieceTheme, {piece: piece})
864
+ }
865
+
866
+ // NOTE: this should never happen
867
+ error(8272, 'Unable to build image source for config.pieceTheme.')
868
+ return ''
869
+ }
870
+
871
+ function buildPieceHTML (piece, hidden, id) {
872
+ var html = '<img src="' + buildPieceImgSrc(piece) + '" '
873
+ if (isString(id) && id !== '') {
874
+ html += 'id="' + id + '" '
875
+ }
876
+ html += 'alt="" ' +
877
+ 'class="{piece}" ' +
878
+ 'data-piece="' + piece + '" ' +
879
+ 'style="width:' + squareSize + 'px;' + 'height:' + squareSize + 'px;'
880
+
881
+ if (hidden) {
882
+ html += 'display:none;'
883
+ }
884
+
885
+ html += '" />'
886
+
887
+ return interpolateTemplate(html, CSS)
888
+ }
889
+
890
+ function buildSparePiecesHTML (color) {
891
+ var pieces = ['wK', 'wQ', 'wR', 'wB', 'wN', 'wP']
892
+ if (color === 'black') {
893
+ pieces = ['bK', 'bQ', 'bR', 'bB', 'bN', 'bP']
894
+ }
895
+
896
+ var html = ''
897
+ for (var i = 0; i < pieces.length; i++) {
898
+ html += buildPieceHTML(pieces[i], false, sparePiecesElsIds[pieces[i]])
899
+ }
900
+
901
+ return html
902
+ }
903
+
904
+ // -------------------------------------------------------------------------
905
+ // Animations
906
+ // -------------------------------------------------------------------------
907
+
908
+ function animateSquareToSquare (src, dest, piece, completeFn) {
909
+ // get information about the source and destination squares
910
+ var $srcSquare = $('#' + squareElsIds[src])
911
+ var srcSquarePosition = $srcSquare.offset()
912
+ var $destSquare = $('#' + squareElsIds[dest])
913
+ var destSquarePosition = $destSquare.offset()
914
+
915
+ // create the animated piece and absolutely position it
916
+ // over the source square
917
+ var animatedPieceId = uuid()
918
+ $('body').append(buildPieceHTML(piece, true, animatedPieceId))
919
+ var $animatedPiece = $('#' + animatedPieceId)
920
+ $animatedPiece.css({
921
+ display: '',
922
+ position: 'absolute',
923
+ top: srcSquarePosition.top,
924
+ left: srcSquarePosition.left
925
+ })
926
+
927
+ // remove original piece from source square
928
+ $srcSquare.find('.' + CSS.piece).remove()
929
+
930
+ function onFinishAnimation1 () {
931
+ // add the "real" piece to the destination square
932
+ $destSquare.append(buildPieceHTML(piece))
933
+
934
+ // remove the animated piece
935
+ $animatedPiece.remove()
936
+
937
+ // run complete function
938
+ if (isFunction(completeFn)) {
939
+ completeFn()
940
+ }
941
+ }
942
+
943
+ // animate the piece to the destination square
944
+ var opts = {
945
+ duration: config.moveSpeed,
946
+ complete: onFinishAnimation1
947
+ }
948
+ $animatedPiece.animate(destSquarePosition, opts)
949
+ }
950
+
951
+ function animateSparePieceToSquare (piece, dest, completeFn) {
952
+ var srcOffset = $('#' + sparePiecesElsIds[piece]).offset()
953
+ var $destSquare = $('#' + squareElsIds[dest])
954
+ var destOffset = $destSquare.offset()
955
+
956
+ // create the animate piece
957
+ var pieceId = uuid()
958
+ $('body').append(buildPieceHTML(piece, true, pieceId))
959
+ var $animatedPiece = $('#' + pieceId)
960
+ $animatedPiece.css({
961
+ display: '',
962
+ position: 'absolute',
963
+ left: srcOffset.left,
964
+ top: srcOffset.top
965
+ })
966
+
967
+ // on complete
968
+ function onFinishAnimation2 () {
969
+ // add the "real" piece to the destination square
970
+ $destSquare.find('.' + CSS.piece).remove()
971
+ $destSquare.append(buildPieceHTML(piece))
972
+
973
+ // remove the animated piece
974
+ $animatedPiece.remove()
975
+
976
+ // run complete function
977
+ if (isFunction(completeFn)) {
978
+ completeFn()
979
+ }
980
+ }
981
+
982
+ // animate the piece to the destination square
983
+ var opts = {
984
+ duration: config.moveSpeed,
985
+ complete: onFinishAnimation2
986
+ }
987
+ $animatedPiece.animate(destOffset, opts)
988
+ }
989
+
990
+ // execute an array of animations
991
+ function doAnimations (animations, oldPos, newPos) {
992
+ if (animations.length === 0) return
993
+
994
+ var numFinished = 0
995
+ function onFinishAnimation3 () {
996
+ // exit if all the animations aren't finished
997
+ numFinished = numFinished + 1
998
+ if (numFinished !== animations.length) return
999
+
1000
+ drawPositionInstant()
1001
+
1002
+ // run their onMoveEnd function
1003
+ if (isFunction(config.onMoveEnd)) {
1004
+ config.onMoveEnd(deepCopy(oldPos), deepCopy(newPos))
1005
+ }
1006
+ }
1007
+
1008
+ for (var i = 0; i < animations.length; i++) {
1009
+ var animation = animations[i]
1010
+
1011
+ // clear a piece
1012
+ if (animation.type === 'clear') {
1013
+ $('#' + squareElsIds[animation.square] + ' .' + CSS.piece)
1014
+ .fadeOut(config.trashSpeed, onFinishAnimation3)
1015
+
1016
+ // add a piece with no spare pieces - fade the piece onto the square
1017
+ } else if (animation.type === 'add' && !config.sparePieces) {
1018
+ $('#' + squareElsIds[animation.square])
1019
+ .append(buildPieceHTML(animation.piece, true))
1020
+ .find('.' + CSS.piece)
1021
+ .fadeIn(config.appearSpeed, onFinishAnimation3)
1022
+
1023
+ // add a piece with spare pieces - animate from the spares
1024
+ } else if (animation.type === 'add' && config.sparePieces) {
1025
+ animateSparePieceToSquare(animation.piece, animation.square, onFinishAnimation3)
1026
+
1027
+ // move a piece from squareA to squareB
1028
+ } else if (animation.type === 'move') {
1029
+ animateSquareToSquare(animation.source, animation.destination, animation.piece, onFinishAnimation3)
1030
+ }
1031
+ }
1032
+ }
1033
+
1034
+ // calculate an array of animations that need to happen in order to get
1035
+ // from pos1 to pos2
1036
+ function calculateAnimations (pos1, pos2) {
1037
+ // make copies of both
1038
+ pos1 = deepCopy(pos1)
1039
+ pos2 = deepCopy(pos2)
1040
+
1041
+ var animations = []
1042
+ var squaresMovedTo = {}
1043
+
1044
+ // remove pieces that are the same in both positions
1045
+ for (var i in pos2) {
1046
+ if (!pos2.hasOwnProperty(i)) continue
1047
+
1048
+ if (pos1.hasOwnProperty(i) && pos1[i] === pos2[i]) {
1049
+ delete pos1[i]
1050
+ delete pos2[i]
1051
+ }
1052
+ }
1053
+
1054
+ // find all the "move" animations
1055
+ for (i in pos2) {
1056
+ if (!pos2.hasOwnProperty(i)) continue
1057
+
1058
+ var closestPiece = findClosestPiece(pos1, pos2[i], i)
1059
+ if (closestPiece) {
1060
+ animations.push({
1061
+ type: 'move',
1062
+ source: closestPiece,
1063
+ destination: i,
1064
+ piece: pos2[i]
1065
+ })
1066
+
1067
+ delete pos1[closestPiece]
1068
+ delete pos2[i]
1069
+ squaresMovedTo[i] = true
1070
+ }
1071
+ }
1072
+
1073
+ // "add" animations
1074
+ for (i in pos2) {
1075
+ if (!pos2.hasOwnProperty(i)) continue
1076
+
1077
+ animations.push({
1078
+ type: 'add',
1079
+ square: i,
1080
+ piece: pos2[i]
1081
+ })
1082
+
1083
+ delete pos2[i]
1084
+ }
1085
+
1086
+ // "clear" animations
1087
+ for (i in pos1) {
1088
+ if (!pos1.hasOwnProperty(i)) continue
1089
+
1090
+ // do not clear a piece if it is on a square that is the result
1091
+ // of a "move", ie: a piece capture
1092
+ if (squaresMovedTo.hasOwnProperty(i)) continue
1093
+
1094
+ animations.push({
1095
+ type: 'clear',
1096
+ square: i,
1097
+ piece: pos1[i]
1098
+ })
1099
+
1100
+ delete pos1[i]
1101
+ }
1102
+
1103
+ return animations
1104
+ }
1105
+
1106
+ // -------------------------------------------------------------------------
1107
+ // Control Flow
1108
+ // -------------------------------------------------------------------------
1109
+
1110
+ function drawPositionInstant () {
1111
+ // clear the board
1112
+ $board.find('.' + CSS.piece).remove()
1113
+
1114
+ // add the pieces
1115
+ for (var i in currentPosition) {
1116
+ if (!currentPosition.hasOwnProperty(i)) continue
1117
+
1118
+ $('#' + squareElsIds[i]).append(buildPieceHTML(currentPosition[i]))
1119
+ }
1120
+ }
1121
+
1122
+ function drawBoard () {
1123
+ $board.html(buildBoardHTML(currentOrientation, squareSize, config.showNotation))
1124
+ drawPositionInstant()
1125
+
1126
+ if (config.sparePieces) {
1127
+ if (currentOrientation === 'white') {
1128
+ $sparePiecesTop.html(buildSparePiecesHTML('black'))
1129
+ $sparePiecesBottom.html(buildSparePiecesHTML('white'))
1130
+ } else {
1131
+ $sparePiecesTop.html(buildSparePiecesHTML('white'))
1132
+ $sparePiecesBottom.html(buildSparePiecesHTML('black'))
1133
+ }
1134
+ }
1135
+ }
1136
+
1137
+ function setCurrentPosition (position) {
1138
+ var oldPos = deepCopy(currentPosition)
1139
+ var newPos = deepCopy(position)
1140
+ var oldFen = objToFen(oldPos)
1141
+ var newFen = objToFen(newPos)
1142
+
1143
+ // do nothing if no change in position
1144
+ if (oldFen === newFen) return
1145
+
1146
+ // run their onChange function
1147
+ if (isFunction(config.onChange)) {
1148
+ config.onChange(oldPos, newPos)
1149
+ }
1150
+
1151
+ // update state
1152
+ currentPosition = position
1153
+ }
1154
+
1155
+ function isXYOnSquare (x, y) {
1156
+ for (var i in squareElsOffsets) {
1157
+ if (!squareElsOffsets.hasOwnProperty(i)) continue
1158
+
1159
+ var s = squareElsOffsets[i]
1160
+ if (x >= s.left &&
1161
+ x < s.left + squareSize &&
1162
+ y >= s.top &&
1163
+ y < s.top + squareSize) {
1164
+ return i
1165
+ }
1166
+ }
1167
+
1168
+ return 'offboard'
1169
+ }
1170
+
1171
+ // records the XY coords of every square into memory
1172
+ function captureSquareOffsets () {
1173
+ squareElsOffsets = {}
1174
+
1175
+ for (var i in squareElsIds) {
1176
+ if (!squareElsIds.hasOwnProperty(i)) continue
1177
+
1178
+ squareElsOffsets[i] = $('#' + squareElsIds[i]).offset()
1179
+ }
1180
+ }
1181
+
1182
+ function removeSquareHighlights () {
1183
+ $board
1184
+ .find('.' + CSS.square)
1185
+ .removeClass(CSS.highlight1 + ' ' + CSS.highlight2)
1186
+ }
1187
+
1188
+ function snapbackDraggedPiece () {
1189
+ // there is no "snapback" for spare pieces
1190
+ if (draggedPieceSource === 'spare') {
1191
+ trashDraggedPiece()
1192
+ return
1193
+ }
1194
+
1195
+ removeSquareHighlights()
1196
+
1197
+ // animation complete
1198
+ function complete () {
1199
+ drawPositionInstant()
1200
+ $draggedPiece.css('display', 'none')
1201
+
1202
+ // run their onSnapbackEnd function
1203
+ if (isFunction(config.onSnapbackEnd)) {
1204
+ config.onSnapbackEnd(
1205
+ draggedPiece,
1206
+ draggedPieceSource,
1207
+ deepCopy(currentPosition),
1208
+ currentOrientation
1209
+ )
1210
+ }
1211
+ }
1212
+
1213
+ // get source square position
1214
+ var sourceSquarePosition = $('#' + squareElsIds[draggedPieceSource]).offset()
1215
+
1216
+ // animate the piece to the target square
1217
+ var opts = {
1218
+ duration: config.snapbackSpeed,
1219
+ complete: complete
1220
+ }
1221
+ $draggedPiece.animate(sourceSquarePosition, opts)
1222
+
1223
+ // set state
1224
+ isDragging = false
1225
+ }
1226
+
1227
+ function trashDraggedPiece () {
1228
+ removeSquareHighlights()
1229
+
1230
+ // remove the source piece
1231
+ var newPosition = deepCopy(currentPosition)
1232
+ delete newPosition[draggedPieceSource]
1233
+ setCurrentPosition(newPosition)
1234
+
1235
+ // redraw the position
1236
+ drawPositionInstant()
1237
+
1238
+ // hide the dragged piece
1239
+ $draggedPiece.fadeOut(config.trashSpeed)
1240
+
1241
+ // set state
1242
+ isDragging = false
1243
+ }
1244
+
1245
+ function dropDraggedPieceOnSquare (square) {
1246
+ removeSquareHighlights()
1247
+
1248
+ // update position
1249
+ var newPosition = deepCopy(currentPosition)
1250
+ delete newPosition[draggedPieceSource]
1251
+ newPosition[square] = draggedPiece
1252
+ setCurrentPosition(newPosition)
1253
+
1254
+ // get target square information
1255
+ var targetSquarePosition = $('#' + squareElsIds[square]).offset()
1256
+
1257
+ // animation complete
1258
+ function onAnimationComplete () {
1259
+ drawPositionInstant()
1260
+ $draggedPiece.css('display', 'none')
1261
+
1262
+ // execute their onSnapEnd function
1263
+ if (isFunction(config.onSnapEnd)) {
1264
+ config.onSnapEnd(draggedPieceSource, square, draggedPiece)
1265
+ }
1266
+ }
1267
+
1268
+ // snap the piece to the target square
1269
+ var opts = {
1270
+ duration: config.snapSpeed,
1271
+ complete: onAnimationComplete
1272
+ }
1273
+ $draggedPiece.animate(targetSquarePosition, opts)
1274
+
1275
+ // set state
1276
+ isDragging = false
1277
+ }
1278
+
1279
+ function beginDraggingPiece (source, piece, x, y) {
1280
+ // run their custom onDragStart function
1281
+ // their custom onDragStart function can cancel drag start
1282
+ if (isFunction(config.onDragStart) &&
1283
+ config.onDragStart(source, piece, deepCopy(currentPosition), currentOrientation) === false) {
1284
+ return
1285
+ }
1286
+
1287
+ // set state
1288
+ isDragging = true
1289
+ draggedPiece = piece
1290
+ draggedPieceSource = source
1291
+
1292
+ // if the piece came from spare pieces, location is offboard
1293
+ if (source === 'spare') {
1294
+ draggedPieceLocation = 'offboard'
1295
+ } else {
1296
+ draggedPieceLocation = source
1297
+ }
1298
+
1299
+ // capture the x, y coords of all squares in memory
1300
+ captureSquareOffsets()
1301
+
1302
+ // create the dragged piece
1303
+ $draggedPiece.attr('src', buildPieceImgSrc(piece)).css({
1304
+ display: '',
1305
+ position: 'absolute',
1306
+ left: x - squareSize / 2,
1307
+ top: y - squareSize / 2
1308
+ })
1309
+
1310
+ if (source !== 'spare') {
1311
+ // highlight the source square and hide the piece
1312
+ $('#' + squareElsIds[source])
1313
+ .addClass(CSS.highlight1)
1314
+ .find('.' + CSS.piece)
1315
+ .css('display', 'none')
1316
+ }
1317
+ }
1318
+
1319
+ function updateDraggedPiece (x, y) {
1320
+ // put the dragged piece over the mouse cursor
1321
+ $draggedPiece.css({
1322
+ left: x - squareSize / 2,
1323
+ top: y - squareSize / 2
1324
+ })
1325
+
1326
+ // get location
1327
+ var location = isXYOnSquare(x, y)
1328
+
1329
+ // do nothing if the location has not changed
1330
+ if (location === draggedPieceLocation) return
1331
+
1332
+ // remove highlight from previous square
1333
+ if (validSquare(draggedPieceLocation)) {
1334
+ $('#' + squareElsIds[draggedPieceLocation]).removeClass(CSS.highlight2)
1335
+ }
1336
+
1337
+ // add highlight to new square
1338
+ if (validSquare(location)) {
1339
+ $('#' + squareElsIds[location]).addClass(CSS.highlight2)
1340
+ }
1341
+
1342
+ // run onDragMove
1343
+ if (isFunction(config.onDragMove)) {
1344
+ config.onDragMove(
1345
+ location,
1346
+ draggedPieceLocation,
1347
+ draggedPieceSource,
1348
+ draggedPiece,
1349
+ deepCopy(currentPosition),
1350
+ currentOrientation
1351
+ )
1352
+ }
1353
+
1354
+ // update state
1355
+ draggedPieceLocation = location
1356
+ }
1357
+
1358
+ function stopDraggedPiece (location) {
1359
+ // determine what the action should be
1360
+ var action = 'drop'
1361
+ if (location === 'offboard' && config.dropOffBoard === 'snapback') {
1362
+ action = 'snapback'
1363
+ }
1364
+ if (location === 'offboard' && config.dropOffBoard === 'trash') {
1365
+ action = 'trash'
1366
+ }
1367
+
1368
+ // run their onDrop function, which can potentially change the drop action
1369
+ if (isFunction(config.onDrop)) {
1370
+ var newPosition = deepCopy(currentPosition)
1371
+
1372
+ // source piece is a spare piece and position is off the board
1373
+ // if (draggedPieceSource === 'spare' && location === 'offboard') {...}
1374
+ // position has not changed; do nothing
1375
+
1376
+ // source piece is a spare piece and position is on the board
1377
+ if (draggedPieceSource === 'spare' && validSquare(location)) {
1378
+ // add the piece to the board
1379
+ newPosition[location] = draggedPiece
1380
+ }
1381
+
1382
+ // source piece was on the board and position is off the board
1383
+ if (validSquare(draggedPieceSource) && location === 'offboard') {
1384
+ // remove the piece from the board
1385
+ delete newPosition[draggedPieceSource]
1386
+ }
1387
+
1388
+ // source piece was on the board and position is on the board
1389
+ if (validSquare(draggedPieceSource) && validSquare(location)) {
1390
+ // move the piece
1391
+ delete newPosition[draggedPieceSource]
1392
+ newPosition[location] = draggedPiece
1393
+ }
1394
+
1395
+ var oldPosition = deepCopy(currentPosition)
1396
+
1397
+ var result = config.onDrop(
1398
+ draggedPieceSource,
1399
+ location,
1400
+ draggedPiece,
1401
+ newPosition,
1402
+ oldPosition,
1403
+ currentOrientation
1404
+ )
1405
+ if (result === 'snapback' || result === 'trash') {
1406
+ action = result
1407
+ }
1408
+ }
1409
+
1410
+ // do it!
1411
+ if (action === 'snapback') {
1412
+ snapbackDraggedPiece()
1413
+ } else if (action === 'trash') {
1414
+ trashDraggedPiece()
1415
+ } else if (action === 'drop') {
1416
+ dropDraggedPieceOnSquare(location)
1417
+ }
1418
+ }
1419
+
1420
+ // -------------------------------------------------------------------------
1421
+ // Public Methods
1422
+ // -------------------------------------------------------------------------
1423
+
1424
+ // clear the board
1425
+ widget.clear = function (useAnimation) {
1426
+ widget.position({}, useAnimation)
1427
+ }
1428
+
1429
+ // remove the widget from the page
1430
+ widget.destroy = function () {
1431
+ // remove markup
1432
+ $container.html('')
1433
+ $draggedPiece.remove()
1434
+
1435
+ // remove event handlers
1436
+ $container.unbind()
1437
+ }
1438
+
1439
+ // shorthand method to get the current FEN
1440
+ widget.fen = function () {
1441
+ return widget.position('fen')
1442
+ }
1443
+
1444
+ // flip orientation
1445
+ widget.flip = function () {
1446
+ return widget.orientation('flip')
1447
+ }
1448
+
1449
+ // move pieces
1450
+ // TODO: this method should be variadic as well as accept an array of moves
1451
+ widget.move = function () {
1452
+ // no need to throw an error here; just do nothing
1453
+ // TODO: this should return the current position
1454
+ if (arguments.length === 0) return
1455
+
1456
+ var useAnimation = true
1457
+
1458
+ // collect the moves into an object
1459
+ var moves = {}
1460
+ for (var i = 0; i < arguments.length; i++) {
1461
+ // any "false" to this function means no animations
1462
+ if (arguments[i] === false) {
1463
+ useAnimation = false
1464
+ continue
1465
+ }
1466
+
1467
+ // skip invalid arguments
1468
+ if (!validMove(arguments[i])) {
1469
+ error(2826, 'Invalid move passed to the move method.', arguments[i])
1470
+ continue
1471
+ }
1472
+
1473
+ var tmp = arguments[i].split('-')
1474
+ moves[tmp[0]] = tmp[1]
1475
+ }
1476
+
1477
+ // calculate position from moves
1478
+ var newPos = calculatePositionFromMoves(currentPosition, moves)
1479
+
1480
+ // update the board
1481
+ widget.position(newPos, useAnimation)
1482
+
1483
+ // return the new position object
1484
+ return newPos
1485
+ }
1486
+
1487
+ widget.orientation = function (arg) {
1488
+ // no arguments, return the current orientation
1489
+ if (arguments.length === 0) {
1490
+ return currentOrientation
1491
+ }
1492
+
1493
+ // set to white or black
1494
+ if (arg === 'white' || arg === 'black') {
1495
+ currentOrientation = arg
1496
+ drawBoard()
1497
+ return currentOrientation
1498
+ }
1499
+
1500
+ // flip orientation
1501
+ if (arg === 'flip') {
1502
+ currentOrientation = currentOrientation === 'white' ? 'black' : 'white'
1503
+ drawBoard()
1504
+ return currentOrientation
1505
+ }
1506
+
1507
+ error(5482, 'Invalid value passed to the orientation method.', arg)
1508
+ }
1509
+
1510
+ widget.position = function (position, useAnimation) {
1511
+ // no arguments, return the current position
1512
+ if (arguments.length === 0) {
1513
+ return deepCopy(currentPosition)
1514
+ }
1515
+
1516
+ // get position as FEN
1517
+ if (isString(position) && position.toLowerCase() === 'fen') {
1518
+ return objToFen(currentPosition)
1519
+ }
1520
+
1521
+ // start position
1522
+ if (isString(position) && position.toLowerCase() === 'start') {
1523
+ position = deepCopy(START_POSITION)
1524
+ }
1525
+
1526
+ // convert FEN to position object
1527
+ if (validFen(position)) {
1528
+ position = fenToObj(position)
1529
+ }
1530
+
1531
+ // validate position object
1532
+ if (!validPositionObject(position)) {
1533
+ error(6482, 'Invalid value passed to the position method.', position)
1534
+ return
1535
+ }
1536
+
1537
+ // default for useAnimations is true
1538
+ if (useAnimation !== false) useAnimation = true
1539
+
1540
+ if (useAnimation) {
1541
+ // start the animations
1542
+ var animations = calculateAnimations(currentPosition, position)
1543
+ doAnimations(animations, currentPosition, position)
1544
+
1545
+ // set the new position
1546
+ setCurrentPosition(position)
1547
+ } else {
1548
+ // instant update
1549
+ setCurrentPosition(position)
1550
+ drawPositionInstant()
1551
+ }
1552
+ }
1553
+
1554
+ widget.resize = function () {
1555
+ // calulate the new square size
1556
+ squareSize = calculateSquareSize()
1557
+
1558
+ // set board width
1559
+ $board.css('width', squareSize * 8 + 'px')
1560
+
1561
+ // set drag piece size
1562
+ $draggedPiece.css({
1563
+ height: squareSize,
1564
+ width: squareSize
1565
+ })
1566
+
1567
+ // spare pieces
1568
+ if (config.sparePieces) {
1569
+ $container
1570
+ .find('.' + CSS.sparePieces)
1571
+ .css('paddingLeft', squareSize + boardBorderSize + 'px')
1572
+ }
1573
+
1574
+ // redraw the board
1575
+ drawBoard()
1576
+ }
1577
+
1578
+ // set the starting position
1579
+ widget.start = function (useAnimation) {
1580
+ widget.position('start', useAnimation)
1581
+ }
1582
+
1583
+ // -------------------------------------------------------------------------
1584
+ // Browser Events
1585
+ // -------------------------------------------------------------------------
1586
+
1587
+ function stopDefault (evt) {
1588
+ evt.preventDefault()
1589
+ }
1590
+
1591
+ function mousedownSquare (evt) {
1592
+ // do nothing if we're not draggable
1593
+ if (!config.draggable) return
1594
+
1595
+ // do nothing if there is no piece on this square
1596
+ var square = $(this).attr('data-square')
1597
+ if (!validSquare(square)) return
1598
+ if (!currentPosition.hasOwnProperty(square)) return
1599
+
1600
+ beginDraggingPiece(square, currentPosition[square], evt.pageX, evt.pageY)
1601
+ }
1602
+
1603
+ function touchstartSquare (e) {
1604
+ // do nothing if we're not draggable
1605
+ if (!config.draggable) return
1606
+
1607
+ // do nothing if there is no piece on this square
1608
+ var square = $(this).attr('data-square')
1609
+ if (!validSquare(square)) return
1610
+ if (!currentPosition.hasOwnProperty(square)) return
1611
+
1612
+ e = e.originalEvent
1613
+ beginDraggingPiece(
1614
+ square,
1615
+ currentPosition[square],
1616
+ e.changedTouches[0].pageX,
1617
+ e.changedTouches[0].pageY
1618
+ )
1619
+ }
1620
+
1621
+ function mousedownSparePiece (evt) {
1622
+ // do nothing if sparePieces is not enabled
1623
+ if (!config.sparePieces) return
1624
+
1625
+ var piece = $(this).attr('data-piece')
1626
+
1627
+ beginDraggingPiece('spare', piece, evt.pageX, evt.pageY)
1628
+ }
1629
+
1630
+ function touchstartSparePiece (e) {
1631
+ // do nothing if sparePieces is not enabled
1632
+ if (!config.sparePieces) return
1633
+
1634
+ var piece = $(this).attr('data-piece')
1635
+
1636
+ e = e.originalEvent
1637
+ beginDraggingPiece(
1638
+ 'spare',
1639
+ piece,
1640
+ e.changedTouches[0].pageX,
1641
+ e.changedTouches[0].pageY
1642
+ )
1643
+ }
1644
+
1645
+ function mousemoveWindow (evt) {
1646
+ if (isDragging) {
1647
+ updateDraggedPiece(evt.pageX, evt.pageY)
1648
+ }
1649
+ }
1650
+
1651
+ var throttledMousemoveWindow = throttle(mousemoveWindow, config.dragThrottleRate)
1652
+
1653
+ function touchmoveWindow (evt) {
1654
+ // do nothing if we are not dragging a piece
1655
+ if (!isDragging) return
1656
+
1657
+ // prevent screen from scrolling
1658
+ evt.preventDefault()
1659
+
1660
+ updateDraggedPiece(evt.originalEvent.changedTouches[0].pageX,
1661
+ evt.originalEvent.changedTouches[0].pageY)
1662
+ }
1663
+
1664
+ var throttledTouchmoveWindow = throttle(touchmoveWindow, config.dragThrottleRate)
1665
+
1666
+ function mouseupWindow (evt) {
1667
+ // do nothing if we are not dragging a piece
1668
+ if (!isDragging) return
1669
+
1670
+ // get the location
1671
+ var location = isXYOnSquare(evt.pageX, evt.pageY)
1672
+
1673
+ stopDraggedPiece(location)
1674
+ }
1675
+
1676
+ function touchendWindow (evt) {
1677
+ // do nothing if we are not dragging a piece
1678
+ if (!isDragging) return
1679
+
1680
+ // get the location
1681
+ var location = isXYOnSquare(evt.originalEvent.changedTouches[0].pageX,
1682
+ evt.originalEvent.changedTouches[0].pageY)
1683
+
1684
+ stopDraggedPiece(location)
1685
+ }
1686
+
1687
+ function mouseenterSquare (evt) {
1688
+ // do not fire this event if we are dragging a piece
1689
+ // NOTE: this should never happen, but it's a safeguard
1690
+ if (isDragging) return
1691
+
1692
+ // exit if they did not provide a onMouseoverSquare function
1693
+ if (!isFunction(config.onMouseoverSquare)) return
1694
+
1695
+ // get the square
1696
+ var square = $(evt.currentTarget).attr('data-square')
1697
+
1698
+ // NOTE: this should never happen; defensive
1699
+ if (!validSquare(square)) return
1700
+
1701
+ // get the piece on this square
1702
+ var piece = false
1703
+ if (currentPosition.hasOwnProperty(square)) {
1704
+ piece = currentPosition[square]
1705
+ }
1706
+
1707
+ // execute their function
1708
+ config.onMouseoverSquare(square, piece, deepCopy(currentPosition), currentOrientation)
1709
+ }
1710
+
1711
+ function mouseleaveSquare (evt) {
1712
+ // do not fire this event if we are dragging a piece
1713
+ // NOTE: this should never happen, but it's a safeguard
1714
+ if (isDragging) return
1715
+
1716
+ // exit if they did not provide an onMouseoutSquare function
1717
+ if (!isFunction(config.onMouseoutSquare)) return
1718
+
1719
+ // get the square
1720
+ var square = $(evt.currentTarget).attr('data-square')
1721
+
1722
+ // NOTE: this should never happen; defensive
1723
+ if (!validSquare(square)) return
1724
+
1725
+ // get the piece on this square
1726
+ var piece = false
1727
+ if (currentPosition.hasOwnProperty(square)) {
1728
+ piece = currentPosition[square]
1729
+ }
1730
+
1731
+ // execute their function
1732
+ config.onMouseoutSquare(square, piece, deepCopy(currentPosition), currentOrientation)
1733
+ }
1734
+
1735
+ // -------------------------------------------------------------------------
1736
+ // Initialization
1737
+ // -------------------------------------------------------------------------
1738
+
1739
+ function addEvents () {
1740
+ // prevent "image drag"
1741
+ $('body').on('mousedown mousemove', '.' + CSS.piece, stopDefault)
1742
+
1743
+ // mouse drag pieces
1744
+ $board.on('mousedown', '.' + CSS.square, mousedownSquare)
1745
+ $container.on('mousedown', '.' + CSS.sparePieces + ' .' + CSS.piece, mousedownSparePiece)
1746
+
1747
+ // mouse enter / leave square
1748
+ $board
1749
+ .on('mouseenter', '.' + CSS.square, mouseenterSquare)
1750
+ .on('mouseleave', '.' + CSS.square, mouseleaveSquare)
1751
+
1752
+ // piece drag
1753
+ var $window = $(window)
1754
+ $window
1755
+ .on('mousemove', throttledMousemoveWindow)
1756
+ .on('mouseup', mouseupWindow)
1757
+
1758
+ // touch drag pieces
1759
+ if (isTouchDevice()) {
1760
+ $board.on('touchstart', '.' + CSS.square, touchstartSquare)
1761
+ $container.on('touchstart', '.' + CSS.sparePieces + ' .' + CSS.piece, touchstartSparePiece)
1762
+ $window
1763
+ .on('touchmove', throttledTouchmoveWindow)
1764
+ .on('touchend', touchendWindow)
1765
+ }
1766
+ }
1767
+
1768
+ function initDOM () {
1769
+ // create unique IDs for all the elements we will create
1770
+ createElIds()
1771
+
1772
+ // build board and save it in memory
1773
+ $container.html(buildContainerHTML(config.sparePieces))
1774
+ $board = $container.find('.' + CSS.board)
1775
+
1776
+ if (config.sparePieces) {
1777
+ $sparePiecesTop = $container.find('.' + CSS.sparePiecesTop)
1778
+ $sparePiecesBottom = $container.find('.' + CSS.sparePiecesBottom)
1779
+ }
1780
+
1781
+ // create the drag piece
1782
+ var draggedPieceId = uuid()
1783
+ $('body').append(buildPieceHTML('wP', true, draggedPieceId))
1784
+ $draggedPiece = $('#' + draggedPieceId)
1785
+
1786
+ // TODO: need to remove this dragged piece element if the board is no
1787
+ // longer in the DOM
1788
+
1789
+ // get the border size
1790
+ boardBorderSize = parseInt($board.css('borderLeftWidth'), 10)
1791
+
1792
+ // set the size and draw the board
1793
+ widget.resize()
1794
+ }
1795
+
1796
+ // -------------------------------------------------------------------------
1797
+ // Initialization
1798
+ // -------------------------------------------------------------------------
1799
+
1800
+ setInitialState()
1801
+ initDOM()
1802
+ addEvents()
1803
+
1804
+ // return the widget object
1805
+ return widget
1806
+ } // end constructor
1807
+
1808
+ // TODO: do module exports here
1809
+ window['Chessboard'] = constructor
1810
+
1811
+ // support legacy ChessBoard name
1812
+ window['ChessBoard'] = window['Chessboard']
1813
+
1814
+ // expose util functions
1815
+ window['Chessboard']['fenToObj'] = fenToObj
1816
+ window['Chessboard']['objToFen'] = objToFen
1817
+ })() // end anonymous wrapper
js/chessboard-1.0.0.min.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */
2
+ !function(){"use strict";var z=window.jQuery,F="abcdefgh".split(""),r=20,A="…",W="1.8.3",e="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR",G=pe(e),n=200,t=200,o=60,a=30,i=100,H={};function V(e,r,n){function t(){o=0,a&&(a=!1,s())}var o=0,a=!1,i=[],s=function(){o=window.setTimeout(t,r),e.apply(n,i)};return function(e){i=arguments,o?a=!0:s()}}function Z(){return"xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx".replace(/x/g,function(e){return(16*Math.random()|0).toString(16)})}function _(e){return JSON.parse(JSON.stringify(e))}function s(e){var r=e.split(".");return{major:parseInt(r[0],10),minor:parseInt(r[1],10),patch:parseInt(r[2],10)}}function ee(e,r){for(var n in r)if(r.hasOwnProperty(n))for(var t="{"+n+"}",o=r[n];-1!==e.indexOf(t);)e=e.replace(t,o);return e}function re(e){return"string"==typeof e}function ne(e){return"function"==typeof e}function p(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e}function c(e){return"fast"===e||"slow"===e||!!p(e)&&0<=e}function te(e){if(!re(e))return!1;var r=e.split("-");return 2===r.length&&(oe(r[0])&&oe(r[1]))}function oe(e){return re(e)&&-1!==e.search(/^[a-h][1-8]$/)}function u(e){return re(e)&&-1!==e.search(/^[bw][KQRNBP]$/)}function ae(e){if(!re(e))return!1;var r=(e=function(e){return e.replace(/8/g,"11111111").replace(/7/g,"1111111").replace(/6/g,"111111").replace(/5/g,"11111").replace(/4/g,"1111").replace(/3/g,"111").replace(/2/g,"11")}(e=e.replace(/ .+$/,""))).split("/");if(8!==r.length)return!1;for(var n=0;n<8;n++)if(8!==r[n].length||-1!==r[n].search(/[^kqrnbpKQRNBP1]/))return!1;return!0}function ie(e){if(!z.isPlainObject(e))return!1;for(var r in e)if(e.hasOwnProperty(r)&&(!oe(r)||!u(e[r])))return!1;return!0}function se(){return typeof window.$&&z.fn&&z.fn.jquery&&function(e,r){e=s(e),r=s(r);var n=1e5*e.major*1e5+1e5*e.minor+e.patch;return 1e5*r.major*1e5+1e5*r.minor+r.patch<=n}(z.fn.jquery,W)}function pe(e){if(!ae(e))return!1;for(var r,n=(e=e.replace(/ .+$/,"")).split("/"),t={},o=8,a=0;a<8;a++){for(var i=n[a].split(""),s=0,p=0;p<i.length;p++){if(-1!==i[p].search(/[1-8]/))s+=parseInt(i[p],10);else t[F[s]+o]=(r=i[p]).toLowerCase()===r?"b"+r.toUpperCase():"w"+r.toUpperCase(),s+=1}o-=1}return t}function ce(e){if(!ie(e))return!1;for(var r,n,t="",o=8,a=0;a<8;a++){for(var i=0;i<8;i++){var s=F[i]+o;e.hasOwnProperty(s)?t+=(r=e[s],n=void 0,"w"===(n=r.split(""))[0]?n[1].toUpperCase():n[1].toLowerCase()):t+="1"}7!==a&&(t+="/"),o-=1}return t=function(e){return e.replace(/11111111/g,"8").replace(/1111111/g,"7").replace(/111111/g,"6").replace(/11111/g,"5").replace(/1111/g,"4").replace(/111/g,"3").replace(/11/g,"2")}(t)}function ue(e,r,n){for(var t=function(e){for(var r=[],n=0;n<8;n++)for(var t=0;t<8;t++){var o=F[n]+(t+1);e!==o&&r.push({square:o,distance:(a=e,i=o,void 0,void 0,void 0,void 0,void 0,void 0,void 0,void 0,s=a.split(""),p=F.indexOf(s[0])+1,c=parseInt(s[1],10),u=i.split(""),f=F.indexOf(u[0])+1,d=parseInt(u[1],10),h=Math.abs(p-f),l=Math.abs(c-d),l<=h?h:l)})}var a,i,s,p,c,u,f,d,h,l;r.sort(function(e,r){return e.distance-r.distance});var v=[];for(n=0;n<r.length;n++)v.push(r[n].square);return v}(n),o=0;o<t.length;o++){var a=t[o];if(e.hasOwnProperty(a)&&e[a]===r)return a}return!1}function fe(e){return"black"!==e.orientation&&(e.orientation="white"),!1!==e.showNotation&&(e.showNotation=!0),!0!==e.draggable&&(e.draggable=!1),"trash"!==e.dropOffBoard&&(e.dropOffBoard="snapback"),!0!==e.sparePieces&&(e.sparePieces=!1),e.sparePieces&&(e.draggable=!0),e.hasOwnProperty("pieceTheme")&&(re(e.pieceTheme)||ne(e.pieceTheme))||(e.pieceTheme="img/chesspieces/wikipedia/{piece}.png"),c(e.appearSpeed)||(e.appearSpeed=n),c(e.moveSpeed)||(e.moveSpeed=t),c(e.snapbackSpeed)||(e.snapbackSpeed=o),c(e.snapSpeed)||(e.snapSpeed=a),c(e.trashSpeed)||(e.trashSpeed=i),function(e){return p(e)&&1<=e}(e.dragThrottleRate)||(e.dragThrottleRate=r),e}H.alpha="alpha-d2270",H.black="black-3c85d",H.board="board-b72b1",H.chessboard="chessboard-63f37",H.clearfix="clearfix-7da63",H.highlight1="highlight1-32417",H.highlight2="highlight2-9c5d2",H.notation="notation-322f9",H.numeric="numeric-fc462",H.piece="piece-417db",H.row="row-5277c",H.sparePieces="spare-pieces-7492f",H.sparePiecesBottom="spare-pieces-bottom-ae20f",H.sparePiecesTop="spare-pieces-top-4028b",H.square="square-55d63",H.white="white-1e1d7",window.Chessboard=function(e,f){if(!function(){if(se())return!0;var e="Chessboard Error 1005: Unable to find a valid version of jQuery. Please include jQuery "+W+" or higher on the page\n\nExiting"+A;return window.alert(e),!1}())return null;var n=function(e){if(""===e){var r="Chessboard Error 1001: The first argument to Chessboard() cannot be an empty string.\n\nExiting"+A;return window.alert(r),!1}re(e)&&"#"!==e.charAt(0)&&(e="#"+e);var n=z(e);if(1===n.length)return n;var t="Chessboard Error 1003: The first argument to Chessboard() must be the ID of a DOM node, an ID query selector, or a single DOM node.\n\nExiting"+A;return window.alert(t),!1}(e);if(!n)return null;f=fe(f=function(e){return"start"===e?e={position:_(G)}:ae(e)?e={position:pe(e)}:ie(e)&&(e={position:_(e)}),z.isPlainObject(e)||(e={}),e}(f));var r=null,a=null,t=null,o=null,i={},s=2,p="white",c={},u=null,d=null,h=null,l=!1,v={},g={},w={},b=16;function m(e,r,n){if(!0===f.hasOwnProperty("showErrors")&&!1!==f.showErrors){var t="Chessboard Error "+e+": "+r;return"console"===f.showErrors&&"object"==typeof console&&"function"==typeof console.log?(console.log(t),void(2<=arguments.length&&console.log(n))):"alert"===f.showErrors?(n&&(t+="\n\n"+JSON.stringify(n)),void window.alert(t)):void(ne(f.showErrors)&&f.showErrors(e,r,n))}}function P(e){return ne(f.pieceTheme)?f.pieceTheme(e):re(f.pieceTheme)?ee(f.pieceTheme,{piece:e}):(m(8272,"Unable to build image source for config.pieceTheme."),"")}function y(e,r,n){var t='<img src="'+P(e)+'" ';return re(n)&&""!==n&&(t+='id="'+n+'" '),t+='alt="" class="{piece}" data-piece="'+e+'" style="width:'+b+"px;height:"+b+"px;",r&&(t+="display:none;"),ee(t+='" />',H)}function x(e){var r=["wK","wQ","wR","wB","wN","wP"];"black"===e&&(r=["bK","bQ","bR","bB","bN","bP"]);for(var n="",t=0;t<r.length;t++)n+=y(r[t],!1,v[r[t]]);return n}function O(e,r,n,t){var o=z("#"+g[e]),a=o.offset(),i=z("#"+g[r]),s=i.offset(),p=Z();z("body").append(y(n,!0,p));var c=z("#"+p);c.css({display:"",position:"absolute",top:a.top,left:a.left}),o.find("."+H.piece).remove();var u={duration:f.moveSpeed,complete:function(){i.append(y(n)),c.remove(),ne(t)&&t()}};c.animate(s,u)}function S(e,r,n){var t=z("#"+v[e]).offset(),o=z("#"+g[r]),a=o.offset(),i=Z();z("body").append(y(e,!0,i));var s=z("#"+i);s.css({display:"",position:"absolute",left:t.left,top:t.top});var p={duration:f.moveSpeed,complete:function(){o.find("."+H.piece).remove(),o.append(y(e)),s.remove(),ne(n)&&n()}};s.animate(a,p)}function T(){for(var e in r.find("."+H.piece).remove(),c)c.hasOwnProperty(e)&&z("#"+g[e]).append(y(c[e]))}function q(){r.html(function(e){"black"!==e&&(e="white");var r="",n=_(F),t=8;"black"===e&&(n.reverse(),t=1);for(var o="white",a=0;a<8;a++){r+='<div class="{row}">';for(var i=0;i<8;i++){var s=n[i]+t;r+='<div class="{square} '+H[o]+" square-"+s+'" style="width:'+b+"px;height:"+b+'px;" id="'+g[s]+'" data-square="'+s+'">',f.showNotation&&(("white"===e&&1===t||"black"===e&&8===t)&&(r+='<div class="{notation} {alpha}">'+n[i]+"</div>"),0===i&&(r+='<div class="{notation} {numeric}">'+t+"</div>")),r+="</div>",o="white"===o?"black":"white"}r+='<div class="{clearfix}"></div></div>',o="white"===o?"black":"white","white"===e?t-=1:t+=1}return ee(r,H)}(p,f.showNotation)),T(),f.sparePieces&&("white"===p?(t.html(x("black")),o.html(x("white"))):(t.html(x("white")),o.html(x("black"))))}function k(e){var r=_(c),n=_(e);ce(r)!==ce(n)&&(ne(f.onChange)&&f.onChange(r,n),c=e)}function E(e,r){for(var n in w)if(w.hasOwnProperty(n)){var t=w[n];if(e>=t.left&&e<t.left+b&&r>=t.top&&r<t.top+b)return n}return"offboard"}function C(){r.find("."+H.square).removeClass(H.highlight1+" "+H.highlight2)}function B(){C();var e=_(c);delete e[h],k(e),T(),a.fadeOut(f.trashSpeed),l=!1}function I(e,r,n,t){ne(f.onDragStart)&&!1===f.onDragStart(e,r,_(c),p)||(l=!0,u=r,d="spare"===(h=e)?"offboard":e,function(){for(var e in w={},g)g.hasOwnProperty(e)&&(w[e]=z("#"+g[e]).offset())}(),a.attr("src",P(r)).css({display:"",position:"absolute",left:n-b/2,top:t-b/2}),"spare"!==e&&z("#"+g[e]).addClass(H.highlight1).find("."+H.piece).css("display","none"))}function M(e,r){a.css({left:e-b/2,top:r-b/2});var n=E(e,r);n!==d&&(oe(d)&&z("#"+g[d]).removeClass(H.highlight2),oe(n)&&z("#"+g[n]).addClass(H.highlight2),ne(f.onDragMove)&&f.onDragMove(n,d,h,u,_(c),p),d=n)}function N(e){var r="drop";if("offboard"===e&&"snapback"===f.dropOffBoard&&(r="snapback"),"offboard"===e&&"trash"===f.dropOffBoard&&(r="trash"),ne(f.onDrop)){var n=_(c);"spare"===h&&oe(e)&&(n[e]=u),oe(h)&&"offboard"===e&&delete n[h],oe(h)&&oe(e)&&(delete n[h],n[e]=u);var t=_(c),o=f.onDrop(h,e,u,n,t,p);"snapback"!==o&&"trash"!==o||(r=o)}"snapback"===r?function(){if("spare"!==h){C();var e=z("#"+g[h]).offset(),r={duration:f.snapbackSpeed,complete:function(){T(),a.css("display","none"),ne(f.onSnapbackEnd)&&f.onSnapbackEnd(u,h,_(c),p)}};a.animate(e,r),l=!1}else B()}():"trash"===r?B():"drop"===r&&function(e){C();var r=_(c);delete r[h],r[e]=u,k(r);var n=z("#"+g[e]).offset(),t={duration:f.snapSpeed,complete:function(){T(),a.css("display","none"),ne(f.onSnapEnd)&&f.onSnapEnd(h,e,u)}};a.animate(n,t),l=!1}(e)}function j(e){e.preventDefault()}function D(e){if(f.draggable){var r=z(this).attr("data-square");oe(r)&&c.hasOwnProperty(r)&&I(r,c[r],e.pageX,e.pageY)}}function R(e){if(f.draggable){var r=z(this).attr("data-square");oe(r)&&c.hasOwnProperty(r)&&(e=e.originalEvent,I(r,c[r],e.changedTouches[0].pageX,e.changedTouches[0].pageY))}}function Q(e){f.sparePieces&&I("spare",z(this).attr("data-piece"),e.pageX,e.pageY)}function X(e){f.sparePieces&&I("spare",z(this).attr("data-piece"),(e=e.originalEvent).changedTouches[0].pageX,e.changedTouches[0].pageY)}i.clear=function(e){i.position({},e)},i.destroy=function(){n.html(""),a.remove(),n.unbind()},i.fen=function(){return i.position("fen")},i.flip=function(){return i.orientation("flip")},i.move=function(){if(0!==arguments.length){for(var e=!0,r={},n=0;n<arguments.length;n++)if(!1!==arguments[n])if(te(arguments[n])){var t=arguments[n].split("-");r[t[0]]=t[1]}else m(2826,"Invalid move passed to the move method.",arguments[n]);else e=!1;var o=function(e,r){var n=_(e);for(var t in r)if(r.hasOwnProperty(t)&&n.hasOwnProperty(t)){var o=n[t];delete n[t],n[r[t]]=o}return n}(c,r);return i.position(o,e),o}},i.orientation=function(e){return 0===arguments.length?p:"white"===e||"black"===e?(p=e,q(),p):"flip"===e?(p="white"===p?"black":"white",q(),p):void m(5482,"Invalid value passed to the orientation method.",e)},i.position=function(e,r){if(0===arguments.length)return _(c);if(re(e)&&"fen"===e.toLowerCase())return ce(c);(re(e)&&"start"===e.toLowerCase()&&(e=_(G)),ae(e)&&(e=pe(e)),ie(e))?(!1!==r&&(r=!0),r?(function(e,r,n){if(0!==e.length)for(var t=0,o=0;o<e.length;o++){var a=e[o];"clear"===a.type?z("#"+g[a.square]+" ."+H.piece).fadeOut(f.trashSpeed,i):"add"!==a.type||f.sparePieces?"add"===a.type&&f.sparePieces?S(a.piece,a.square,i):"move"===a.type&&O(a.source,a.destination,a.piece,i):z("#"+g[a.square]).append(y(a.piece,!0)).find("."+H.piece).fadeIn(f.appearSpeed,i)}function i(){(t+=1)===e.length&&(T(),ne(f.onMoveEnd)&&f.onMoveEnd(_(r),_(n)))}}(function(e,r){e=_(e),r=_(r);var n=[],t={};for(var o in r)r.hasOwnProperty(o)&&e.hasOwnProperty(o)&&e[o]===r[o]&&(delete e[o],delete r[o]);for(o in r)if(r.hasOwnProperty(o)){var a=ue(e,r[o],o);a&&(n.push({type:"move",source:a,destination:o,piece:r[o]}),delete e[a],delete r[o],t[o]=!0)}for(o in r)r.hasOwnProperty(o)&&(n.push({type:"add",square:o,piece:r[o]}),delete r[o]);for(o in e)e.hasOwnProperty(o)&&(t.hasOwnProperty(o)||(n.push({type:"clear",square:o,piece:e[o]}),delete e[o]));return n}(c,e),c,e),k(e)):(k(e),T())):m(6482,"Invalid value passed to the position method.",e)},i.resize=function(){b=function(){var e=parseInt(n.width(),10);if(!e||e<=0)return 0;for(var r=e-1;r%8!=0&&0<r;)r-=1;return r/8}(),r.css("width",8*b+"px"),a.css({height:b,width:b}),f.sparePieces&&n.find("."+H.sparePieces).css("paddingLeft",b+s+"px"),q()},i.start=function(e){i.position("start",e)};var Y=V(function(e){l&&M(e.pageX,e.pageY)},f.dragThrottleRate),K=V(function(e){l&&(e.preventDefault(),M(e.originalEvent.changedTouches[0].pageX,e.originalEvent.changedTouches[0].pageY))},f.dragThrottleRate);function L(e){l&&N(E(e.pageX,e.pageY))}function U(e){l&&N(E(e.originalEvent.changedTouches[0].pageX,e.originalEvent.changedTouches[0].pageY))}function $(e){if(!l&&ne(f.onMouseoverSquare)){var r=z(e.currentTarget).attr("data-square");if(oe(r)){var n=!1;c.hasOwnProperty(r)&&(n=c[r]),f.onMouseoverSquare(r,n,_(c),p)}}}function J(e){if(!l&&ne(f.onMouseoutSquare)){var r=z(e.currentTarget).attr("data-square");if(oe(r)){var n=!1;c.hasOwnProperty(r)&&(n=c[r]),f.onMouseoutSquare(r,n,_(c),p)}}}return p=f.orientation,f.hasOwnProperty("position")&&("start"===f.position?c=_(G):ae(f.position)?c=pe(f.position):ie(f.position)?c=_(f.position):m(7263,"Invalid value passed to config.position.",f.position)),function(){!function(){for(var e=0;e<F.length;e++)for(var r=1;r<=8;r++){var n=F[e]+r;g[n]=n+"-"+Z()}var t="KQRNBP".split("");for(e=0;e<t.length;e++){var o="w"+t[e],a="b"+t[e];v[o]=o+"-"+Z(),v[a]=a+"-"+Z()}}(),n.html(function(e){var r='<div class="{chessboard}">';return e&&(r+='<div class="{sparePieces} {sparePiecesTop}"></div>'),r+='<div class="{board}"></div>',e&&(r+='<div class="{sparePieces} {sparePiecesBottom}"></div>'),ee(r+="</div>",H)}(f.sparePieces)),r=n.find("."+H.board),f.sparePieces&&(t=n.find("."+H.sparePiecesTop),o=n.find("."+H.sparePiecesBottom));var e=Z();z("body").append(y("wP",!0,e)),a=z("#"+e),s=parseInt(r.css("borderLeftWidth"),10),i.resize()}(),function(){z("body").on("mousedown mousemove","."+H.piece,j),r.on("mousedown","."+H.square,D),n.on("mousedown","."+H.sparePieces+" ."+H.piece,Q),r.on("mouseenter","."+H.square,$).on("mouseleave","."+H.square,J);var e=z(window);e.on("mousemove",Y).on("mouseup",L),"ontouchstart"in document.documentElement&&(r.on("touchstart","."+H.square,R),n.on("touchstart","."+H.sparePieces+" ."+H.piece,X),e.on("touchmove",K).on("touchend",U))}(),i},window.ChessBoard=window.Chessboard,window.Chessboard.fenToObj=pe,window.Chessboard.objToFen=ce}();
helpers.js → js/helpers.js RENAMED
@@ -8,7 +8,7 @@ function convertTypedArray(src, type) {
8
 
9
  var printTextarea = (function() {
10
  var element = document.getElementById('output');
11
- if (element) element.alue = ''; // clear browser cache
12
  return function(text) {
13
  if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
14
  console.log(text);
@@ -22,6 +22,7 @@ var printTextarea = (function() {
22
  async function clearCache() {
23
  if (confirm('Are you sure you want to clear the cache?\nAll the models will be downloaded again.')) {
24
  indexedDB.deleteDatabase(dbName);
 
25
  }
26
  }
27
 
@@ -88,11 +89,15 @@ async function fetchRemote(url, cbProgress, cbPrint) {
88
  // - check if the data is already in the IndexedDB
89
  // - if not, fetch it from the remote URL and store it in the IndexedDB
90
  function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
91
- // query the storage quota and print it
92
- navigator.storage.estimate().then(function (estimate) {
93
- cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes');
94
- cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes');
95
- });
 
 
 
 
96
 
97
  // check if the data is already in the IndexedDB
98
  var rq = indexedDB.open(dbName, dbVersion);
@@ -141,7 +146,15 @@ function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
141
  var db = event.target.result;
142
  var tx = db.transaction(['models'], 'readwrite');
143
  var os = tx.objectStore('models');
144
- var rq = os.put(data, url);
 
 
 
 
 
 
 
 
145
 
146
  rq.onsuccess = function (event) {
147
  cbPrint('loadRemote: "' + url + '" stored in the IndexedDB');
@@ -176,7 +189,6 @@ function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
176
 
177
  rq.onabort = function (event) {
178
  cbPrint('loadRemote: failed to open IndexedDB: abort');
179
-
180
  };
181
  }
182
-
 
8
 
9
  var printTextarea = (function() {
10
  var element = document.getElementById('output');
11
+ if (element) element.value = ''; // clear browser cache
12
  return function(text) {
13
  if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
14
  console.log(text);
 
22
  async function clearCache() {
23
  if (confirm('Are you sure you want to clear the cache?\nAll the models will be downloaded again.')) {
24
  indexedDB.deleteDatabase(dbName);
25
+ location.reload();
26
  }
27
  }
28
 
 
89
  // - check if the data is already in the IndexedDB
90
  // - if not, fetch it from the remote URL and store it in the IndexedDB
91
  function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
92
+ if (!navigator.storage || !navigator.storage.estimate) {
93
+ cbPrint('loadRemote: navigator.storage.estimate() is not supported');
94
+ } else {
95
+ // query the storage quota and print it
96
+ navigator.storage.estimate().then(function (estimate) {
97
+ cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes');
98
+ cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes');
99
+ });
100
+ }
101
 
102
  // check if the data is already in the IndexedDB
103
  var rq = indexedDB.open(dbName, dbVersion);
 
146
  var db = event.target.result;
147
  var tx = db.transaction(['models'], 'readwrite');
148
  var os = tx.objectStore('models');
149
+
150
+ var rq = null;
151
+ try {
152
+ var rq = os.put(data, url);
153
+ } catch (e) {
154
+ cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB: \n' + e);
155
+ cbCancel();
156
+ return;
157
+ }
158
 
159
  rq.onsuccess = function (event) {
160
  cbPrint('loadRemote: "' + url + '" stored in the IndexedDB');
 
189
 
190
  rq.onabort = function (event) {
191
  cbPrint('loadRemote: failed to open IndexedDB: abort');
192
+ cbCancel();
193
  };
194
  }
 
js/jquery-3.7.1.min.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */
2
+ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}function fe(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}ce.fn=ce.prototype={jquery:t,constructor:ce,length:0,toArray:function(){return ae.call(this)},get:function(e){return null==e?ae.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=ce.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return ce.each(this,e)},map:function(n){return this.pushStack(ce.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(ae.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(ce.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(ce.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:oe.sort,splice:oe.splice},ce.extend=ce.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||v(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(ce.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||ce.isPlainObject(n)?n:{},i=!1,a[t]=ce.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},ce.extend({expando:"jQuery"+(t+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==i.call(e))&&(!(t=r(e))||"function"==typeof(n=ue.call(t,"constructor")&&t.constructor)&&o.call(n)===a)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){m(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(c(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},text:function(e){var t,n="",r=0,i=e.nodeType;if(!i)while(t=e[r++])n+=ce.text(t);return 1===i||11===i?e.textContent:9===i?e.documentElement.textContent:3===i||4===i?e.nodeValue:n},makeArray:function(e,t){var n=t||[];return null!=e&&(c(Object(e))?ce.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:se.call(t,e,n)},isXMLDoc:function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!l.test(t||n&&n.nodeName||"HTML")},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(c(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:le}),"function"==typeof Symbol&&(ce.fn[Symbol.iterator]=oe[Symbol.iterator]),ce.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var pe=oe.pop,de=oe.sort,he=oe.splice,ge="[\\x20\\t\\r\\n\\f]",ve=new RegExp("^"+ge+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ge+"+$","g");ce.contains=function(e,t){var n=t&&t.parentNode;return e===n||!(!n||1!==n.nodeType||!(e.contains?e.contains(n):e.compareDocumentPosition&&16&e.compareDocumentPosition(n)))};var f=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;function p(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e}ce.escapeSelector=function(e){return(e+"").replace(f,p)};var ye=C,me=s;!function(){var e,b,w,o,a,T,r,C,d,i,k=me,S=ce.expando,E=0,n=0,s=W(),c=W(),u=W(),h=W(),l=function(e,t){return e===t&&(a=!0),0},f="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",t="(?:\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",p="\\["+ge+"*("+t+")(?:"+ge+"*([*^$|!~]?=)"+ge+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+t+"))|)"+ge+"*\\]",g=":("+t+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+p+")*)|.*)\\)|)",v=new RegExp(ge+"+","g"),y=new RegExp("^"+ge+"*,"+ge+"*"),m=new RegExp("^"+ge+"*([>+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="<a id='"+S+"' href='' disabled='disabled'></a><select id='"+S+"-\r\\' disabled='disabled'><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0<I(t,T,null,[e]).length},I.contains=function(e,t){return(e.ownerDocument||e)!=T&&V(e),ce.contains(e,t)},I.attr=function(e,t){(e.ownerDocument||e)!=T&&V(e);var n=b.attrHandle[t.toLowerCase()],r=n&&ue.call(b.attrHandle,t.toLowerCase())?n(e,t,!C):void 0;return void 0!==r?r:e.getAttribute(t)},I.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},ce.uniqueSort=function(e){var t,n=[],r=0,i=0;if(a=!le.sortStable,o=!le.sortStable&&ae.call(e,0),de.call(e,l),a){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)he.call(e,n[r],1)}return o=null,e},ce.fn.uniqueSort=function(){return this.pushStack(ce.uniqueSort(ae.apply(this)))},(b=ce.expr={cacheLength:50,createPseudo:F,match:D,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(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===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]||I.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]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(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(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(v," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(d,e,t,h,g){var v="nth"!==d.slice(0,3),y="last"!==d.slice(-4),m="of-type"===e;return 1===h&&0===g?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u=v!==y?"nextSibling":"previousSibling",l=e.parentNode,c=m&&e.nodeName.toLowerCase(),f=!n&&!m,p=!1;if(l){if(v){while(u){o=e;while(o=o[u])if(m?fe(o,c):1===o.nodeType)return!1;s=u="only"===d&&!s&&"nextSibling"}return!0}if(s=[y?l.firstChild:l.lastChild],y&&f){p=(a=(r=(i=l[S]||(l[S]={}))[d]||[])[0]===E&&r[1])&&r[2],o=a&&l.childNodes[a];while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if(1===o.nodeType&&++p&&o===e){i[d]=[E,a,p];break}}else if(f&&(p=a=(r=(i=e[S]||(e[S]={}))[d]||[])[0]===E&&r[1]),!1===p)while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if((m?fe(o,c):1===o.nodeType)&&++p&&(f&&((i=o[S]||(o[S]={}))[d]=[E,p]),o===e))break;return(p-=g)===h||p%h==0&&0<=p/h}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||I.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?F(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=se.call(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:F(function(e){var r=[],i=[],s=ne(e.replace(ve,"$1"));return s[S]?F(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:F(function(t){return function(e){return 0<I(t,e).length}}),contains:F(function(t){return t=t.replace(O,P),function(e){return-1<(e.textContent||ce.text(e)).indexOf(t)}}),lang:F(function(n){return A.test(n||"")||I.error("unsupported lang: "+n),n=n.replace(O,P).toLowerCase(),function(e){var t;do{if(t=C?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=ie.location&&ie.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===r},focus:function(e){return e===function(){try{return T.activeElement}catch(e){}}()&&T.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:z(!1),disabled:z(!0),checked:function(e){return fe(e,"input")&&!!e.checked||fe(e,"option")&&!!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!b.pseudos.empty(e)},header:function(e){return q.test(e.nodeName)},input:function(e){return N.test(e.nodeName)},button:function(e){return fe(e,"input")&&"button"===e.type||fe(e,"button")},text:function(e){var t;return fe(e,"input")&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:X(function(){return[0]}),last:X(function(e,t){return[t-1]}),eq:X(function(e,t,n){return[n<0?n+t:n]}),even:X(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:X(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:X(function(e,t,n){var r;for(r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:X(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=B(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=_(e);function G(){}function Y(e,t){var n,r,i,o,a,s,u,l=c[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=y.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=m.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(ve," ")}),a=a.slice(n.length)),b.filter)!(r=D[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?I.error(e):c(e,s).slice(0)}function Q(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function J(a,e,t){var s=e.dir,u=e.next,l=u||s,c=t&&"parentNode"===l,f=n++;return e.first?function(e,t,n){while(e=e[s])if(1===e.nodeType||c)return a(e,t,n);return!1}:function(e,t,n){var r,i,o=[E,f];if(n){while(e=e[s])if((1===e.nodeType||c)&&a(e,t,n))return!0}else while(e=e[s])if(1===e.nodeType||c)if(i=e[S]||(e[S]={}),u&&fe(e,u))e=e[s]||e;else{if((r=i[l])&&r[0]===E&&r[1]===f)return o[2]=r[2];if((i[l]=o)[2]=a(e,t,n))return!0}return!1}}function K(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Z(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function ee(d,h,g,v,y,e){return v&&!v[S]&&(v=ee(v)),y&&!y[S]&&(y=ee(y,e)),F(function(e,t,n,r){var i,o,a,s,u=[],l=[],c=t.length,f=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)I(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),p=!d||!e&&h?f:Z(f,u,d,n,r);if(g?g(p,s=y||(e?d:c||v)?[]:t,n,r):s=p,v){i=Z(s,l),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(s[l[o]]=!(p[l[o]]=a))}if(e){if(y||d){if(y){i=[],o=s.length;while(o--)(a=s[o])&&i.push(p[o]=a);y(null,s=[],i,r)}o=s.length;while(o--)(a=s[o])&&-1<(i=y?se.call(e,a):u[o])&&(e[i]=!(t[i]=a))}}else s=Z(s===t?s.splice(c,s.length):s),y?y(null,t,s,r):k.apply(t,s)})}function te(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=J(function(e){return e===i},a,!0),l=J(function(e){return-1<se.call(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!=w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[J(K(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return ee(1<s&&K(c),1<s&&Q(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(ve,"$1"),t,s<n&&te(e.slice(s,n)),n<r&&te(e=e.slice(n)),n<r&&Q(e))}c.push(t)}return K(c)}function ne(e,t){var n,v,y,m,x,r,i=[],o=[],a=u[e+" "];if(!a){t||(t=Y(e)),n=t.length;while(n--)(a=te(t[n]))[S]?i.push(a):o.push(a);(a=u(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=E+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==T||(V(o),n=!C);while(s=v[a++])if(s(o,t||T,n)){k.call(r,o);break}i&&(E=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=pe.call(r));f=Z(f)}k.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&ce.uniqueSort(r)}return i&&(E=h,w=p),c},m?F(r):r))).selector=e}return a}function re(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&Y(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&C&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(O,P),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=D.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(O,P),H.test(o[0].type)&&U(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&Q(o)))return k.apply(n,r),n;break}}}return(l||ne(e,c))(r,t,!C,n,!t||H.test(e)&&U(t.parentNode)||t),n}G.prototype=b.filters=b.pseudos,b.setFilters=new G,le.sortStable=S.split("").sort(l).join("")===S,V(),le.sortDetached=$(function(e){return 1&e.compareDocumentPosition(T.createElement("fieldset"))}),ce.find=I,ce.expr[":"]=ce.expr.pseudos,ce.unique=ce.uniqueSort,I.compile=ne,I.select=re,I.setDocument=V,I.tokenize=Y,I.escape=ce.escapeSelector,I.getText=ce.text,I.isXML=ce.isXMLDoc,I.selectors=ce.expr,I.support=ce.support,I.uniqueSort=ce.uniqueSort}();var d=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&ce(e).is(n))break;r.push(e)}return r},h=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},b=ce.expr.match.needsContext,w=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1<se.call(n,e)!==r}):ce.filter(n,e,r)}ce.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?ce.find.matchesSelector(r,e)?[r]:[]:ce.find.matches(e,ce.grep(t,function(e){return 1===e.nodeType}))},ce.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(ce(e).filter(function(){for(t=0;t<r;t++)if(ce.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)ce.find(e,i[t],n);return 1<r?ce.uniqueSort(n):n},filter:function(e){return this.pushStack(T(this,e||[],!1))},not:function(e){return this.pushStack(T(this,e||[],!0))},is:function(e){return!!T(this,"string"==typeof e&&b.test(e)?ce(e):e||[],!1).length}});var k,S=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.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 ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(ce.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&ce(e);if(!b.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&ce.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?ce.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?se.call(ce(e),this[0]):se.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ce.uniqueSort(ce.merge(this.get(),ce(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ce.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return d(e,"parentNode")},parentsUntil:function(e,t,n){return d(e,"parentNode",n)},next:function(e){return A(e,"nextSibling")},prev:function(e){return A(e,"previousSibling")},nextAll:function(e){return d(e,"nextSibling")},prevAll:function(e){return d(e,"previousSibling")},nextUntil:function(e,t,n){return d(e,"nextSibling",n)},prevUntil:function(e,t,n){return d(e,"previousSibling",n)},siblings:function(e){return h((e.parentNode||{}).firstChild,e)},children:function(e){return h(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(fe(e,"template")&&(e=e.content||e),ce.merge([],e.childNodes))}},function(r,i){ce.fn[r]=function(e,t){var n=ce.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=ce.filter(t,n)),1<this.length&&(j[r]||ce.uniqueSort(n),E.test(r)&&n.reverse()),this.pushStack(n)}});var D=/[^\x20\t\r\n\f]+/g;function N(e){return e}function q(e){throw e}function L(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}ce.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},ce.each(e.match(D)||[],function(e,t){n[t]=!0}),n):ce.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){ce.each(e,function(e,t){v(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==x(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return ce.each(arguments,function(e,t){var n;while(-1<(n=ce.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<ce.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},ce.extend({Deferred:function(e){var o=[["notify","progress",ce.Callbacks("memory"),ce.Callbacks("memory"),2],["resolve","done",ce.Callbacks("once memory"),ce.Callbacks("once memory"),0,"resolved"],["reject","fail",ce.Callbacks("once memory"),ce.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return ce.Deferred(function(r){ce.each(o,function(e,t){var n=v(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&v(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,v(t)?s?t.call(e,l(u,o,N,s),l(u,o,q,s)):(u++,t.call(e,l(u,o,N,s),l(u,o,q,s),l(u,o,N,o.notifyWith))):(a!==N&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){ce.Deferred.exceptionHook&&ce.Deferred.exceptionHook(e,t.error),u<=i+1&&(a!==q&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(ce.Deferred.getErrorHook?t.error=ce.Deferred.getErrorHook():ce.Deferred.getStackHook&&(t.error=ce.Deferred.getStackHook()),ie.setTimeout(t))}}return ce.Deferred(function(e){o[0][3].add(l(0,e,v(r)?r:N,e.notifyWith)),o[1][3].add(l(0,e,v(t)?t:N)),o[2][3].add(l(0,e,v(n)?n:q))}).promise()},promise:function(e){return null!=e?ce.extend(e,a):a}},s={};return ce.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=ae.call(arguments),o=ce.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?ae.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(L(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||v(i[t]&&i[t].then)))return o.then();while(t--)L(i[t],a(t),o.reject);return o.promise()}});var H=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;ce.Deferred.exceptionHook=function(e,t){ie.console&&ie.console.warn&&e&&H.test(e.name)&&ie.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},ce.readyException=function(e){ie.setTimeout(function(){throw e})};var O=ce.Deferred();function P(){C.removeEventListener("DOMContentLoaded",P),ie.removeEventListener("load",P),ce.ready()}ce.fn.ready=function(e){return O.then(e)["catch"](function(e){ce.readyException(e)}),this},ce.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--ce.readyWait:ce.isReady)||(ce.isReady=!0)!==e&&0<--ce.readyWait||O.resolveWith(C,[ce])}}),ce.ready.then=O.then,"complete"===C.readyState||"loading"!==C.readyState&&!C.documentElement.doScroll?ie.setTimeout(ce.ready):(C.addEventListener("DOMContentLoaded",P),ie.addEventListener("load",P));var M=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n))for(s in i=!0,n)M(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,v(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(ce(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},R=/^-ms-/,I=/-([a-z])/g;function W(e,t){return t.toUpperCase()}function F(e){return e.replace(R,"ms-").replace(I,W)}var $=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function B(){this.expando=ce.expando+B.uid++}B.uid=1,B.prototype={cache:function(e){var t=e[this.expando];return t||(t={},$(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[F(t)]=n;else for(r in t)i[F(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][F(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(F):(t=F(t))in r?[t]:t.match(D)||[]).length;while(n--)delete r[t[n]]}(void 0===t||ce.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!ce.isEmptyObject(t)}};var _=new B,z=new B,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,U=/[A-Z]/g;function V(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(U,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:X.test(i)?JSON.parse(i):i)}catch(e){}z.set(e,t,n)}else n=void 0;return n}ce.extend({hasData:function(e){return z.hasData(e)||_.hasData(e)},data:function(e,t,n){return z.access(e,t,n)},removeData:function(e,t){z.remove(e,t)},_data:function(e,t,n){return _.access(e,t,n)},_removeData:function(e,t){_.remove(e,t)}}),ce.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=z.get(o),1===o.nodeType&&!_.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=F(r.slice(5)),V(o,r,i[r]));_.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){z.set(this,n)}):M(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=z.get(o,n))?t:void 0!==(t=V(o,n))?t:void 0;this.each(function(){z.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){z.remove(this,e)})}}),ce.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=_.get(e,t),n&&(!r||Array.isArray(n)?r=_.access(e,t,ce.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=ce.queue(e,t),r=n.length,i=n.shift(),o=ce._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){ce.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return _.get(e,n)||_.access(e,n,{empty:ce.Callbacks("once memory").add(function(){_.remove(e,[t+"queue",n])})})}}),ce.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?ce.queue(this[0],t):void 0===n?this:this.each(function(){var e=ce.queue(this,t,n);ce._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&ce.dequeue(this,t)})},dequeue:function(e){return this.each(function(){ce.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=ce.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=_.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var G=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,Y=new RegExp("^(?:([+-])=|)("+G+")([a-z%]*)$","i"),Q=["Top","Right","Bottom","Left"],J=C.documentElement,K=function(e){return ce.contains(e.ownerDocument,e)},Z={composed:!0};J.getRootNode&&(K=function(e){return ce.contains(e.ownerDocument,e)||e.getRootNode(Z)===e.ownerDocument});var ee=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&K(e)&&"none"===ce.css(e,"display")};function te(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return ce.css(e,t,"")},u=s(),l=n&&n[3]||(ce.cssNumber[t]?"":"px"),c=e.nodeType&&(ce.cssNumber[t]||"px"!==l&&+u)&&Y.exec(ce.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)ce.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,ce.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ne={};function re(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=_.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ee(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ne[s])||(o=a.body.appendChild(a.createElement(s)),u=ce.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ne[s]=u)))):"none"!==n&&(l[c]="none",_.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}ce.fn.extend({show:function(){return re(this,!0)},hide:function(){return re(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ee(this)?ce(this).show():ce(this).hide()})}});var xe,be,we=/^(?:checkbox|radio)$/i,Te=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="<textarea>x</textarea>",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="<option></option>",le.option=!!xe.lastChild;var ke={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n<r;n++)_.set(e[n],"globalEval",!t||_.get(t[n],"globalEval"))}ke.tbody=ke.tfoot=ke.colgroup=ke.caption=ke.thead,ke.th=ke.td,le.option||(ke.optgroup=ke.option=[1,"<select multiple='multiple'>","</select>"]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===x(o))ce.merge(p,o.nodeType?[o]:o);else if(je.test(o)){a=a||f.appendChild(t.createElement("div")),s=(Te.exec(o)||["",""])[1].toLowerCase(),u=ke[s]||ke._default,a.innerHTML=u[1]+ce.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;ce.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<ce.inArray(o,r))i&&i.push(o);else if(l=K(o),a=Se(f.appendChild(o),"script"),l&&Ee(a),n){c=0;while(o=a[c++])Ce.test(o.type||"")&&n.push(o)}return f}var De=/^([^.]*)(?:\.(.+)|)/;function Ne(){return!0}function qe(){return!1}function Le(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Le(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=qe;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return ce().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=ce.guid++)),e.each(function(){ce.event.add(this,t,i,r,n)})}function He(e,r,t){t?(_.set(e,r,!1),ce.event.add(e,r,{namespace:!1,handler:function(e){var t,n=_.get(this,r);if(1&e.isTrigger&&this[r]){if(n)(ce.event.special[r]||{}).delegateType&&e.stopPropagation();else if(n=ae.call(arguments),_.set(this,r,n),this[r](),t=_.get(this,r),_.set(this,r,!1),n!==t)return e.stopImmediatePropagation(),e.preventDefault(),t}else n&&(_.set(this,r,ce.event.trigger(n[0],n.slice(1),this)),e.stopPropagation(),e.isImmediatePropagationStopped=Ne)}})):void 0===_.get(e,r)&&ce.event.add(e,r,Ne)}ce.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.get(t);if($(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&ce.find.matchesSelector(J,i),n.guid||(n.guid=ce.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof ce&&ce.event.triggered!==e.type?ce.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(D)||[""]).length;while(l--)d=g=(s=De.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=ce.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=ce.event.special[d]||{},c=ce.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&ce.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),ce.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.hasData(e)&&_.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(D)||[""]).length;while(l--)if(d=g=(s=De.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=ce.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||ce.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)ce.event.remove(e,d+t[l],n,r,!0);ce.isEmptyObject(u)&&_.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=ce.event.fix(e),l=(_.get(this,"events")||Object.create(null))[u.type]||[],c=ce.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=ce.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((ce.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<ce(i,this).index(l):ce.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(ce.Event.prototype,t,{enumerable:!0,configurable:!0,get:v(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[ce.expando]?e:new ce.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click",!0),!1},trigger:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click"),!0},_default:function(e){var t=e.target;return we.test(t.type)&&t.click&&fe(t,"input")&&_.get(t,"click")||fe(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},ce.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},ce.Event=function(e,t){if(!(this instanceof ce.Event))return new ce.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ne:qe,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&ce.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[ce.expando]=!0},ce.Event.prototype={constructor:ce.Event,isDefaultPrevented:qe,isPropagationStopped:qe,isImmediatePropagationStopped:qe,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ne,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ne,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ne,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},ce.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},ce.event.addProp),ce.each({focus:"focusin",blur:"focusout"},function(r,i){function o(e){if(C.documentMode){var t=_.get(this,"handle"),n=ce.event.fix(e);n.type="focusin"===e.type?"focus":"blur",n.isSimulated=!0,t(e),n.target===n.currentTarget&&t(n)}else ce.event.simulate(i,e.target,ce.event.fix(e))}ce.event.special[r]={setup:function(){var e;if(He(this,r,!0),!C.documentMode)return!1;(e=_.get(this,i))||this.addEventListener(i,o),_.set(this,i,(e||0)+1)},trigger:function(){return He(this,r),!0},teardown:function(){var e;if(!C.documentMode)return!1;(e=_.get(this,i)-1)?_.set(this,i,e):(this.removeEventListener(i,o),_.remove(this,i))},_default:function(e){return _.get(e.target,r)},delegateType:i},ce.event.special[i]={setup:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i);n||(C.documentMode?this.addEventListener(i,o):e.addEventListener(r,o,!0)),_.set(t,i,(n||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i)-1;n?_.set(t,i,n):(C.documentMode?this.removeEventListener(i,o):e.removeEventListener(r,o,!0),_.remove(t,i))}}}),ce.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){ce.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||ce.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),ce.fn.extend({on:function(e,t,n,r){return Le(this,e,t,n,r)},one:function(e,t,n,r){return Le(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,ce(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=qe),this.each(function(){ce.event.remove(this,e,n,t)})}});var Oe=/<script|<style|<link/i,Pe=/checked\s*(?:[^=]|=\s*.checked.)/i,Me=/^\s*<!\[CDATA\[|\]\]>\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)ce.event.add(t,i,s[i][n]);z.hasData(e)&&(o=z.access(e),a=ce.extend({},o),z.set(t,a))}}function $e(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=v(d);if(h||1<f&&"string"==typeof d&&!le.checkClone&&Pe.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),$e(t,r,i,o)});if(f&&(t=(e=Ae(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=ce.map(Se(e,"script"),Ie)).length;c<f;c++)u=e,c!==p&&(u=ce.clone(u,!0,!0),s&&ce.merge(a,Se(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,ce.map(a,We),c=0;c<s;c++)u=a[c],Ce.test(u.type||"")&&!_.access(u,"globalEval")&&ce.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?ce._evalUrl&&!u.noModule&&ce._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):m(u.textContent.replace(Me,""),u,l))}return n}function Be(e,t,n){for(var r,i=t?ce.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||ce.cleanData(Se(r)),r.parentNode&&(n&&K(r)&&Ee(Se(r,"script")),r.parentNode.removeChild(r));return e}ce.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=K(e);if(!(le.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ce.isXMLDoc(e)))for(a=Se(c),r=0,i=(o=Se(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&we.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||Se(e),a=a||Se(c),r=0,i=o.length;r<i;r++)Fe(o[r],a[r]);else Fe(e,c);return 0<(a=Se(c,"script")).length&&Ee(a,!f&&Se(e,"script")),c},cleanData:function(e){for(var t,n,r,i=ce.event.special,o=0;void 0!==(n=e[o]);o++)if($(n)){if(t=n[_.expando]){if(t.events)for(r in t.events)i[r]?ce.event.remove(n,r):ce.removeEvent(n,r,t.handle);n[_.expando]=void 0}n[z.expando]&&(n[z.expando]=void 0)}}}),ce.fn.extend({detach:function(e){return Be(this,e,!0)},remove:function(e){return Be(this,e)},text:function(e){return M(this,function(e){return void 0===e?ce.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 $e(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Re(this,e).appendChild(e)})},prepend:function(){return $e(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Re(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return $e(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&&(ce.cleanData(Se(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ce.clone(this,e,t)})},html:function(e){return M(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&&!Oe.test(e)&&!ke[(Te.exec(e)||["",""])[1].toLowerCase()]){e=ce.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(ce.cleanData(Se(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return $e(this,arguments,function(e){var t=this.parentNode;ce.inArray(this,n)<0&&(ce.cleanData(Se(this)),t&&t.replaceChild(e,this))},n)}}),ce.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){ce.fn[e]=function(e){for(var t,n=[],r=ce(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),ce(r[o])[a](t),s.apply(n,t.get());return this.pushStack(n)}});var _e=new RegExp("^("+G+")(?!px)[a-z%]+$","i"),ze=/^--/,Xe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=ie),t.getComputedStyle(e)},Ue=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ve=new RegExp(Q.join("|"),"i");function Ge(e,t,n){var r,i,o,a,s=ze.test(t),u=e.style;return(n=n||Xe(e))&&(a=n.getPropertyValue(t)||n[t],s&&a&&(a=a.replace(ve,"$1")||void 0),""!==a||K(e)||(a=ce.style(e,t)),!le.pixelBoxStyles()&&_e.test(a)&&Ve.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=n.width,u.width=r,u.minWidth=i,u.maxWidth=o)),void 0!==a?a+"":a}function Ye(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",J.appendChild(u).appendChild(l);var e=ie.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),J.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=C.createElement("div"),l=C.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",le.clearCloneStyle="content-box"===l.style.backgroundClip,ce.extend(le,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=C.createElement("table"),t=C.createElement("tr"),n=C.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="box-sizing:content-box;border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",J.appendChild(e).appendChild(t).appendChild(n),r=ie.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,J.removeChild(e)),a}}))}();var Qe=["Webkit","Moz","ms"],Je=C.createElement("div").style,Ke={};function Ze(e){var t=ce.cssProps[e]||Ke[e];return t||(e in Je?e:Ke[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Qe.length;while(n--)if((e=Qe[n]+t)in Je)return e}(e)||e)}var et=/^(none|table(?!-c[ea]).+)/,tt={position:"absolute",visibility:"hidden",display:"block"},nt={letterSpacing:"0",fontWeight:"400"};function rt(e,t,n){var r=Y.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function it(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0,l=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(l+=ce.css(e,n+Q[a],!0,i)),r?("content"===n&&(u-=ce.css(e,"padding"+Q[a],!0,i)),"margin"!==n&&(u-=ce.css(e,"border"+Q[a]+"Width",!0,i))):(u+=ce.css(e,"padding"+Q[a],!0,i),"padding"!==n?u+=ce.css(e,"border"+Q[a]+"Width",!0,i):s+=ce.css(e,"border"+Q[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u+l}function ot(e,t,n){var r=Xe(e),i=(!le.boxSizingReliable()||n)&&"border-box"===ce.css(e,"boxSizing",!1,r),o=i,a=Ge(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(_e.test(a)){if(!n)return a;a="auto"}return(!le.boxSizingReliable()&&i||!le.reliableTrDimensions()&&fe(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===ce.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===ce.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+it(e,t,n||(i?"border":"content"),o,r,a)+"px"}function at(e,t,n,r,i){return new at.prototype.init(e,t,n,r,i)}ce.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ge(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=F(t),u=ze.test(t),l=e.style;if(u||(t=Ze(s)),a=ce.cssHooks[t]||ce.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=Y.exec(n))&&i[1]&&(n=te(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(ce.cssNumber[s]?"":"px")),le.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=F(t);return ze.test(t)||(t=Ze(s)),(a=ce.cssHooks[t]||ce.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ge(e,t,r)),"normal"===i&&t in nt&&(i=nt[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),ce.each(["height","width"],function(e,u){ce.cssHooks[u]={get:function(e,t,n){if(t)return!et.test(ce.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?ot(e,u,n):Ue(e,tt,function(){return ot(e,u,n)})},set:function(e,t,n){var r,i=Xe(e),o=!le.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===ce.css(e,"boxSizing",!1,i),s=n?it(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-it(e,u,"border",!1,i)-.5)),s&&(r=Y.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=ce.css(e,u)),rt(0,t,s)}}}),ce.cssHooks.marginLeft=Ye(le.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ge(e,"marginLeft"))||e.getBoundingClientRect().left-Ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),ce.each({margin:"",padding:"",border:"Width"},function(i,o){ce.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+Q[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(ce.cssHooks[i+o].set=rt)}),ce.fn.extend({css:function(e,t){return M(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Xe(e),i=t.length;a<i;a++)o[t[a]]=ce.css(e,t[a],!1,r);return o}return void 0!==n?ce.style(e,t,n):ce.css(e,t)},e,t,1<arguments.length)}}),((ce.Tween=at).prototype={constructor:at,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||ce.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ce.cssNumber[n]?"":"px")},cur:function(){var e=at.propHooks[this.prop];return e&&e.get?e.get(this):at.propHooks._default.get(this)},run:function(e){var t,n=at.propHooks[this.prop];return this.options.duration?this.pos=t=ce.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):at.propHooks._default.set(this),this}}).init.prototype=at.prototype,(at.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=ce.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){ce.fx.step[e.prop]?ce.fx.step[e.prop](e):1!==e.elem.nodeType||!ce.cssHooks[e.prop]&&null==e.elem.style[Ze(e.prop)]?e.elem[e.prop]=e.now:ce.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=at.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ce.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},ce.fx=at.prototype.init,ce.fx.step={};var st,ut,lt,ct,ft=/^(?:toggle|show|hide)$/,pt=/queueHooks$/;function dt(){ut&&(!1===C.hidden&&ie.requestAnimationFrame?ie.requestAnimationFrame(dt):ie.setTimeout(dt,ce.fx.interval),ce.fx.tick())}function ht(){return ie.setTimeout(function(){st=void 0}),st=Date.now()}function gt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=Q[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function vt(e,t,n){for(var r,i=(yt.tweeners[t]||[]).concat(yt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function yt(o,e,t){var n,a,r=0,i=yt.prefilters.length,s=ce.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=st||ht(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:ce.extend({},e),opts:ce.extend(!0,{specialEasing:{},easing:ce.easing._default},t),originalProperties:e,originalOptions:t,startTime:st||ht(),duration:t.duration,tweens:[],createTween:function(e,t){var n=ce.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=F(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=ce.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=yt.prefilters[r].call(l,o,c,l.opts))return v(n.stop)&&(ce._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return ce.map(c,vt,l),v(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),ce.fx.timer(ce.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}ce.Animation=ce.extend(yt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return te(n.elem,e,Y.exec(t),n),n}]},tweener:function(e,t){v(e)?(t=e,e=["*"]):e=e.match(D);for(var n,r=0,i=e.length;r<i;r++)n=e[r],yt.tweeners[n]=yt.tweeners[n]||[],yt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ee(e),v=_.get(e,"fxshow");for(r in n.queue||(null==(a=ce._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,ce.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ft.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||ce.style(e,r)}if((u=!ce.isEmptyObject(t))||!ce.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=_.get(e,"display")),"none"===(c=ce.css(e,"display"))&&(l?c=l:(re([e],!0),l=e.style.display||l,c=ce.css(e,"display"),re([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===ce.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=_.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&re([e],!0),p.done(function(){for(r in g||re([e]),_.remove(e,"fxshow"),d)ce.style(e,r,d[r])})),u=vt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?yt.prefilters.unshift(e):yt.prefilters.push(e)}}),ce.speed=function(e,t,n){var r=e&&"object"==typeof e?ce.extend({},e):{complete:n||!n&&t||v(e)&&e,duration:e,easing:n&&t||t&&!v(t)&&t};return ce.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in ce.fx.speeds?r.duration=ce.fx.speeds[r.duration]:r.duration=ce.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){v(r.old)&&r.old.call(this),r.queue&&ce.dequeue(this,r.queue)},r},ce.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ee).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=ce.isEmptyObject(t),o=ce.speed(e,n,r),a=function(){var e=yt(this,ce.extend({},t),o);(i||_.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=ce.timers,r=_.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&pt.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||ce.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=_.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=ce.timers,o=n?n.length:0;for(t.finish=!0,ce.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),ce.each(["toggle","show","hide"],function(e,r){var i=ce.fn[r];ce.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(gt(r,!0),e,t,n)}}),ce.each({slideDown:gt("show"),slideUp:gt("hide"),slideToggle:gt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){ce.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),ce.timers=[],ce.fx.tick=function(){var e,t=0,n=ce.timers;for(st=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||ce.fx.stop(),st=void 0},ce.fx.timer=function(e){ce.timers.push(e),ce.fx.start()},ce.fx.interval=13,ce.fx.start=function(){ut||(ut=!0,dt())},ce.fx.stop=function(){ut=null},ce.fx.speeds={slow:600,fast:200,_default:400},ce.fn.delay=function(r,e){return r=ce.fx&&ce.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=ie.setTimeout(e,r);t.stop=function(){ie.clearTimeout(n)}})},lt=C.createElement("input"),ct=C.createElement("select").appendChild(C.createElement("option")),lt.type="checkbox",le.checkOn=""!==lt.value,le.optSelected=ct.selected,(lt=C.createElement("input")).value="t",lt.type="radio",le.radioValue="t"===lt.value;var mt,xt=ce.expr.attrHandle;ce.fn.extend({attr:function(e,t){return M(this,ce.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){ce.removeAttr(this,e)})}}),ce.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?ce.prop(e,t,n):(1===o&&ce.isXMLDoc(e)||(i=ce.attrHooks[t.toLowerCase()]||(ce.expr.match.bool.test(t)?mt:void 0)),void 0!==n?null===n?void ce.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:null==(r=ce.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!le.radioValue&&"radio"===t&&fe(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(D);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),mt={set:function(e,t,n){return!1===t?ce.removeAttr(e,n):e.setAttribute(n,n),n}},ce.each(ce.expr.match.bool.source.match(/\w+/g),function(e,t){var a=xt[t]||ce.find.attr;xt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=xt[o],xt[o]=r,r=null!=a(e,t,n)?o:null,xt[o]=i),r}});var bt=/^(?:input|select|textarea|button)$/i,wt=/^(?:a|area)$/i;function Tt(e){return(e.match(D)||[]).join(" ")}function Ct(e){return e.getAttribute&&e.getAttribute("class")||""}function kt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(D)||[]}ce.fn.extend({prop:function(e,t){return M(this,ce.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[ce.propFix[e]||e]})}}),ce.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&ce.isXMLDoc(e)||(t=ce.propFix[t]||t,i=ce.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=ce.find.attr(e,"tabindex");return t?parseInt(t,10):bt.test(e.nodeName)||wt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),le.optSelected||(ce.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)}}),ce.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ce.propFix[this.toLowerCase()]=this}),ce.fn.extend({addClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).addClass(t.call(this,e,Ct(this)))}):(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++)i=e[o],n.indexOf(" "+i+" ")<0&&(n+=i+" ");a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this},removeClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).removeClass(t.call(this,e,Ct(this)))}):arguments.length?(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++){i=e[o];while(-1<n.indexOf(" "+i+" "))n=n.replace(" "+i+" "," ")}a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this:this.attr("class","")},toggleClass:function(t,n){var e,r,i,o,a=typeof t,s="string"===a||Array.isArray(t);return v(t)?this.each(function(e){ce(this).toggleClass(t.call(this,e,Ct(this),n),n)}):"boolean"==typeof n&&s?n?this.addClass(t):this.removeClass(t):(e=kt(t),this.each(function(){if(s)for(o=ce(this),i=0;i<e.length;i++)r=e[i],o.hasClass(r)?o.removeClass(r):o.addClass(r);else void 0!==t&&"boolean"!==a||((r=Ct(this))&&_.set(this,"__className__",r),this.setAttribute&&this.setAttribute("class",r||!1===t?"":_.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+Tt(Ct(n))+" ").indexOf(t))return!0;return!1}});var St=/\r/g;ce.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=v(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,ce(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=ce.map(t,function(e){return null==e?"":e+""})),(r=ce.valHooks[this.type]||ce.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=ce.valHooks[t.type]||ce.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(St,""):null==e?"":e:void 0}}),ce.extend({valHooks:{option:{get:function(e){var t=ce.find.attr(e,"value");return null!=t?t:Tt(ce.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!fe(n.parentNode,"optgroup"))){if(t=ce(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=ce.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<ce.inArray(ce.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),ce.each(["radio","checkbox"],function(){ce.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<ce.inArray(ce(e).val(),t)}},le.checkOn||(ce.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Et=ie.location,jt={guid:Date.now()},At=/\?/;ce.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new ie.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||ce.error("Invalid XML: "+(n?ce.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Dt=/^(?:focusinfocus|focusoutblur)$/,Nt=function(e){e.stopPropagation()};ce.extend(ce.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||C],d=ue.call(e,"type")?e.type:e,h=ue.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||C,3!==n.nodeType&&8!==n.nodeType&&!Dt.test(d+ce.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[ce.expando]?e:new ce.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:ce.makeArray(t,[e]),c=ce.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!y(n)){for(s=c.delegateType||d,Dt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||C)&&p.push(a.defaultView||a.parentWindow||ie)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(_.get(o,"events")||Object.create(null))[e.type]&&_.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&$(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!$(n)||u&&v(n[d])&&!y(n)&&((a=n[u])&&(n[u]=null),ce.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Nt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Nt),ce.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=ce.extend(new ce.Event,n,{type:e,isSimulated:!0});ce.event.trigger(r,null,t)}}),ce.fn.extend({trigger:function(e,t){return this.each(function(){ce.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ce.event.trigger(e,t,n,!0)}});var qt=/\[\]$/,Lt=/\r?\n/g,Ht=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;function Pt(n,e,r,i){var t;if(Array.isArray(e))ce.each(e,function(e,t){r||qt.test(n)?i(n,t):Pt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==x(e))i(n,e);else for(t in e)Pt(n+"["+t+"]",e[t],r,i)}ce.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!ce.isPlainObject(e))ce.each(e,function(){i(this.name,this.value)});else for(n in e)Pt(n,e[n],t,i);return r.join("&")},ce.fn.extend({serialize:function(){return ce.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ce.prop(this,"elements");return e?ce.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ce(this).is(":disabled")&&Ot.test(this.nodeName)&&!Ht.test(e)&&(this.checked||!we.test(e))}).map(function(e,t){var n=ce(this).val();return null==n?null:Array.isArray(n)?ce.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 Mt=/%20/g,Rt=/#.*$/,It=/([?&])_=[^&]*/,Wt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ft=/^(?:GET|HEAD)$/,$t=/^\/\//,Bt={},_t={},zt="*/".concat("*"),Xt=C.createElement("a");function Ut(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(D)||[];if(v(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Vt(t,i,o,a){var s={},u=t===_t;function l(e){var r;return s[e]=!0,ce.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Gt(e,t){var n,r,i=ce.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&ce.extend(!0,e,r),e}Xt.href=Et.href,ce.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":zt,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":ce.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Gt(Gt(e,ce.ajaxSettings),t):Gt(ce.ajaxSettings,e)},ajaxPrefilter:Ut(Bt),ajaxTransport:Ut(_t),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=ce.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?ce(y):ce.event,x=ce.Deferred(),b=ce.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Wt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace($t,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(D)||[""],null==v.crossDomain){r=C.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Xt.protocol+"//"+Xt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=ce.param(v.data,v.traditional)),Vt(Bt,v,t,T),h)return T;for(i in(g=ce.event&&v.global)&&0==ce.active++&&ce.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ft.test(v.type),f=v.url.replace(Rt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Mt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(At.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(It,"$1"),o=(At.test(f)?"&":"?")+"_="+jt.guid+++o),v.url=f+o),v.ifModified&&(ce.lastModified[f]&&T.setRequestHeader("If-Modified-Since",ce.lastModified[f]),ce.etag[f]&&T.setRequestHeader("If-None-Match",ce.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+zt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Vt(_t,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=ie.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&ie.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<ce.inArray("script",v.dataTypes)&&ce.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(ce.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(ce.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--ce.active||ce.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return ce.get(e,t,n,"json")},getScript:function(e,t){return ce.get(e,void 0,t,"script")}}),ce.each(["get","post"],function(e,i){ce[i]=function(e,t,n,r){return v(t)&&(r=r||n,n=t,t=void 0),ce.ajax(ce.extend({url:e,type:i,dataType:r,data:t,success:n},ce.isPlainObject(e)&&e))}}),ce.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),ce._evalUrl=function(e,t,n){return ce.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){ce.globalEval(e,t,n)}})},ce.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=ce(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return v(n)?this.each(function(e){ce(this).wrapInner(n.call(this,e))}):this.each(function(){var e=ce(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=v(t);return this.each(function(e){ce(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){ce(this).replaceWith(this.childNodes)}),this}}),ce.expr.pseudos.hidden=function(e){return!ce.expr.pseudos.visible(e)},ce.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},ce.ajaxSettings.xhr=function(){try{return new ie.XMLHttpRequest}catch(e){}};var Yt={0:200,1223:204},Qt=ce.ajaxSettings.xhr();le.cors=!!Qt&&"withCredentials"in Qt,le.ajax=Qt=!!Qt,ce.ajaxTransport(function(i){var o,a;if(le.cors||Qt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Yt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&ie.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),ce.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),ce.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 ce.globalEval(e),e}}}),ce.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),ce.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=ce("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=Tt(e.slice(s)),e=e.slice(0,s)),v(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&ce.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?ce("<div>").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.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,n){ce.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var en=/^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;ce.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),v(e))return r=ae.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(ae.call(arguments)))}).guid=e.guid=e.guid||ce.guid++,i},ce.holdReady=function(e){e?ce.readyWait++:ce.ready(!0)},ce.isArray=Array.isArray,ce.parseJSON=JSON.parse,ce.nodeName=fe,ce.isFunction=v,ce.isWindow=y,ce.camelCase=F,ce.type=x,ce.now=Date.now,ce.isNumeric=function(e){var t=ce.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},ce.trim=function(e){return null==e?"":(e+"").replace(en,"$1")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return ce});var tn=ie.jQuery,nn=ie.$;return ce.noConflict=function(e){return ie.$===ce&&(ie.$=nn),e&&ie.jQuery===ce&&(ie.jQuery=tn),ce},"undefined"==typeof e&&(ie.jQuery=ie.$=ce),ce});
js/wchess.wasm.js ADDED
The diff for this file is too large to render. See raw diff
 
js/wchess.wasm.worker.js ADDED
@@ -0,0 +1 @@
 
 
1
+ "use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason||e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err(`worker.js received unknown command ${e.data.cmd}`);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
libmain.worker.js DELETED
@@ -1 +0,0 @@
1
- "use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f)},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}var initializedJS=false;var pendingNotifiedProxyingQueues=[];function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=function(){postMessage({cmd:"callHandler",handler:handler,args:[...arguments]})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();pendingNotifiedProxyingQueues.forEach(queue=>{Module["executeNotifiedProxyingQueue"](queue)});pendingNotifiedProxyingQueues=[];initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processProxyingQueue"){if(initializedJS){Module["executeNotifiedProxyingQueue"](e.data.queue)}else{pendingNotifiedProxyingQueues.push(e.data.queue)}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
 
 
libwhisper.worker.js DELETED
@@ -1 +0,0 @@
1
- "use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f)},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}var initializedJS=false;var pendingNotifiedProxyingQueues=[];function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=function(){postMessage({cmd:"callHandler",handler:handler,args:[...arguments]})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}whisper_factory(Module)}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();pendingNotifiedProxyingQueues.forEach(queue=>{Module["executeNotifiedProxyingQueue"](queue)});pendingNotifiedProxyingQueues=[];initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processProxyingQueue"){if(initializedJS){Module["executeNotifiedProxyingQueue"](e.data.queue)}else{pendingNotifiedProxyingQueues.push(e.data.queue)}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
 
 
models/.gitattributes DELETED
@@ -1,51 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ftz filter=lfs diff=lfs merge=lfs -text
6
- *.gz filter=lfs diff=lfs merge=lfs -text
7
- *.h5 filter=lfs diff=lfs merge=lfs -text
8
- *.joblib filter=lfs diff=lfs merge=lfs -text
9
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
10
- *.lz4 filter=lfs diff=lfs merge=lfs -text
11
- *.model filter=lfs diff=lfs merge=lfs -text
12
- *.msgpack filter=lfs diff=lfs merge=lfs -text
13
- *.npy filter=lfs diff=lfs merge=lfs -text
14
- *.npz filter=lfs diff=lfs merge=lfs -text
15
- *.onnx filter=lfs diff=lfs merge=lfs -text
16
- *.ot filter=lfs diff=lfs merge=lfs -text
17
- *.parquet filter=lfs diff=lfs merge=lfs -text
18
- *.pb filter=lfs diff=lfs merge=lfs -text
19
- *.pickle filter=lfs diff=lfs merge=lfs -text
20
- *.pkl filter=lfs diff=lfs merge=lfs -text
21
- *.pt filter=lfs diff=lfs merge=lfs -text
22
- *.pth filter=lfs diff=lfs merge=lfs -text
23
- *.rar filter=lfs diff=lfs merge=lfs -text
24
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
25
- *.tar.* filter=lfs diff=lfs merge=lfs -text
26
- *.tflite filter=lfs diff=lfs merge=lfs -text
27
- *.tgz filter=lfs diff=lfs merge=lfs -text
28
- *.wasm filter=lfs diff=lfs merge=lfs -text
29
- *.xz filter=lfs diff=lfs merge=lfs -text
30
- *.zip filter=lfs diff=lfs merge=lfs -text
31
- *.zst filter=lfs diff=lfs merge=lfs -text
32
- *tfevents* filter=lfs diff=lfs merge=lfs -text
33
- # Audio files - uncompressed
34
- *.pcm filter=lfs diff=lfs merge=lfs -text
35
- *.sam filter=lfs diff=lfs merge=lfs -text
36
- *.raw filter=lfs diff=lfs merge=lfs -text
37
- # Audio files - compressed
38
- *.aac filter=lfs diff=lfs merge=lfs -text
39
- *.flac filter=lfs diff=lfs merge=lfs -text
40
- *.mp3 filter=lfs diff=lfs merge=lfs -text
41
- *.ogg filter=lfs diff=lfs merge=lfs -text
42
- *.wav filter=lfs diff=lfs merge=lfs -text
43
- # Image files - uncompressed
44
- *.bmp filter=lfs diff=lfs merge=lfs -text
45
- *.gif filter=lfs diff=lfs merge=lfs -text
46
- *.png filter=lfs diff=lfs merge=lfs -text
47
- *.tiff filter=lfs diff=lfs merge=lfs -text
48
- # Image files - compressed
49
- *.jpg filter=lfs diff=lfs merge=lfs -text
50
- *.jpeg filter=lfs diff=lfs merge=lfs -text
51
- *.webp filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models/README.md DELETED
@@ -1,24 +0,0 @@
1
- ---
2
- license: mit
3
- ---
4
-
5
- # OpenAI's Whisper models converted to ggml format
6
-
7
- [Available models](https://huggingface.co/datasets/ggerganov/whisper.cpp/tree/main)
8
-
9
- | Model | Disk | Mem | SHA |
10
- | --- | --- | --- | --- |
11
- | tiny | 75 MB | ~390 MB | `bd577a113a864445d4c299885e0cb97d4ba92b5f` |
12
- | tiny.en | 75 MB | ~390 MB | `c78c86eb1a8faa21b369bcd33207cc90d64ae9df` |
13
- | base | 142 MB | ~500 MB | `465707469ff3a37a2b9b8d8f89f2f99de7299dac` |
14
- | base.en | 142 MB | ~500 MB | `137c40403d78fd54d454da0f9bd998f78703390c` |
15
- | small | 466 MB | ~1.0 GB | `55356645c2b361a969dfd0ef2c5a50d530afd8d5` |
16
- | small.en | 466 MB | ~1.0 GB | `db8a495a91d927739e50b3fc1cc4c6b8f6c2d022` |
17
- | medium | 1.5 GB | ~2.6 GB | `fd9727b6e1217c2f614f9b698455c4ffd82463b4` |
18
- | medium.en | 1.5 GB | ~2.6 GB | `8c30f0e44ce9560643ebd10bbe50cd20eafd3723` |
19
- | large-v1 | 2.9 GB | ~4.7 GB | `b1caaf735c4cc1429223d5a74f0f4d0b9b59a299` |
20
- | large | 2.9 GB | ~4.7 GB | `0f4c8e34f21cf1a914c59d8b3ce882345ad349d6` |
21
-
22
- For more information, visit:
23
-
24
- https://github.com/ggerganov/whisper.cpp/tree/master/models
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models/ggml-base.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:60ed5bc3dd14eea856493d334349b405782ddcaf0028d4b5df4088345fba2efe
3
- size 147951465
 
 
 
 
models/ggml-base.en.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:a03779c86df3323075f5e796cb2ce5029f00ec8869eee3fdfb897afe36c6d002
3
- size 147964211
 
 
 
 
models/ggml-tiny.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:be07e048e1e599ad46341c8d2a135645097a538221678b7acdd1b1919c6e1b21
3
- size 77691713
 
 
 
 
models/ggml-tiny.en.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:921e4cf8686fdd993dcd081a5da5b6c365bfde1162e72b08d75ac75289920b1f
3
- size 77704715