##// END OF EJS Templates
Merged with default branch
neko259 -
r1501:c4d18abb merge decentral
parent child Browse files
Show More
@@ -0,0 +1,27 b''
1 from boards.abstracts.settingsmanager import SessionSettingsManager
2 from boards.models import PostImage
3
4 class AttachmentAlias:
5 def get_image(alias):
6 pass
7
8
9 class SessionAttachmentAlias(AttachmentAlias):
10 def __init__(self, session):
11 self.session = session
12
13 def get_image(self, alias):
14 settings_manager = SessionSettingsManager(self.session)
15 return settings_manager.get_image_by_alias(alias)
16
17
18 class ModelAttachmentAlias(AttachmentAlias):
19 def get_image(self, alias):
20 return PostImage.objects.filter(alias=alias).first()
21
22
23 def get_image_by_alias(alias, session):
24 image = SessionAttachmentAlias(session).get_image(alias) or ModelAttachmentAlias().get_image(alias)
25
26 if image is not None:
27 return image
@@ -0,0 +1,24 b''
1 # -*- coding: utf-8 -*-
2 from __future__ import unicode_literals
3
4 from django.db import migrations, models
5
6
7 class Migration(migrations.Migration):
8
9 dependencies = [
10 ('boards', '0040_thread_monochrome'),
11 ]
12
13 operations = [
14 migrations.AddField(
15 model_name='attachment',
16 name='original_filename',
17 field=models.TextField(null=True),
18 ),
19 migrations.AddField(
20 model_name='postimage',
21 name='original_filename',
22 field=models.TextField(null=True),
23 ),
24 ]
@@ -0,0 +1,28 b''
1 # -*- coding: utf-8 -*-
2 # Generated by Django 1.9.5 on 2016-04-22 07:53
3 from __future__ import unicode_literals
4
5 from django.db import migrations, models
6
7
8 class Migration(migrations.Migration):
9
10 dependencies = [
11 ('boards', '0041_auto_20160124_2341'),
12 ]
13
14 operations = [
15 migrations.RemoveField(
16 model_name='attachment',
17 name='original_filename',
18 ),
19 migrations.RemoveField(
20 model_name='postimage',
21 name='original_filename',
22 ),
23 migrations.AddField(
24 model_name='postimage',
25 name='alias',
26 field=models.TextField(blank=True, null=True, unique=True),
27 ),
28 ]
This diff has been collapsed as it changes many lines, (620 lines changed) Show them Hide them
@@ -0,0 +1,620 b''
1 /*!
2 * jQuery blockUI plugin
3 * Version 2.70.0-2014.11.23
4 * Requires jQuery v1.7 or later
5 *
6 * Examples at: http://malsup.com/jquery/block/
7 * Copyright (c) 2007-2013 M. Alsup
8 * Dual licensed under the MIT and GPL licenses:
9 * http://www.opensource.org/licenses/mit-license.php
10 * http://www.gnu.org/licenses/gpl.html
11 *
12 * Thanks to Amir-Hossein Sobhi for some excellent contributions!
13 */
14
15 ;(function() {
16 /*jshint eqeqeq:false curly:false latedef:false */
17 "use strict";
18
19 function setup($) {
20 $.fn._fadeIn = $.fn.fadeIn;
21
22 var noOp = $.noop || function() {};
23
24 // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
25 // confusing userAgent strings on Vista)
26 var msie = /MSIE/.test(navigator.userAgent);
27 var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
28 var mode = document.documentMode || 0;
29 var setExpr = $.isFunction( document.createElement('div').style.setExpression );
30
31 // global $ methods for blocking/unblocking the entire page
32 $.blockUI = function(opts) { install(window, opts); };
33 $.unblockUI = function(opts) { remove(window, opts); };
34
35 // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
36 $.growlUI = function(title, message, timeout, onClose) {
37 var $m = $('<div class="growlUI"></div>');
38 if (title) $m.append('<h1>'+title+'</h1>');
39 if (message) $m.append('<h2>'+message+'</h2>');
40 if (timeout === undefined) timeout = 3000;
41
42 // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
43 var callBlock = function(opts) {
44 opts = opts || {};
45
46 $.blockUI({
47 message: $m,
48 fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
49 fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
50 timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
51 centerY: false,
52 showOverlay: false,
53 onUnblock: onClose,
54 css: $.blockUI.defaults.growlCSS
55 });
56 };
57
58 callBlock();
59 var nonmousedOpacity = $m.css('opacity');
60 $m.mouseover(function() {
61 callBlock({
62 fadeIn: 0,
63 timeout: 30000
64 });
65
66 var displayBlock = $('.blockMsg');
67 displayBlock.stop(); // cancel fadeout if it has started
68 displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
69 }).mouseout(function() {
70 $('.blockMsg').fadeOut(1000);
71 });
72 // End konapun additions
73 };
74
75 // plugin method for blocking element content
76 $.fn.block = function(opts) {
77 if ( this[0] === window ) {
78 $.blockUI( opts );
79 return this;
80 }
81 var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
82 this.each(function() {
83 var $el = $(this);
84 if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
85 return;
86 $el.unblock({ fadeOut: 0 });
87 });
88
89 return this.each(function() {
90 if ($.css(this,'position') == 'static') {
91 this.style.position = 'relative';
92 $(this).data('blockUI.static', true);
93 }
94 this.style.zoom = 1; // force 'hasLayout' in ie
95 install(this, opts);
96 });
97 };
98
99 // plugin method for unblocking element content
100 $.fn.unblock = function(opts) {
101 if ( this[0] === window ) {
102 $.unblockUI( opts );
103 return this;
104 }
105 return this.each(function() {
106 remove(this, opts);
107 });
108 };
109
110 $.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
111
112 // override these in your code to change the default behavior and style
113 $.blockUI.defaults = {
114 // message displayed when blocking (use null for no message)
115 message: '<h1>Please wait...</h1>',
116
117 title: null, // title string; only used when theme == true
118 draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
119
120 theme: false, // set to true to use with jQuery UI themes
121
122 // styles for the message when blocking; if you wish to disable
123 // these and use an external stylesheet then do this in your code:
124 // $.blockUI.defaults.css = {};
125 css: {
126 padding: 0,
127 margin: 0,
128 width: '30%',
129 top: '40%',
130 left: '35%',
131 textAlign: 'center',
132 color: '#000',
133 border: '3px solid #aaa',
134 backgroundColor:'#fff',
135 cursor: 'wait'
136 },
137
138 // minimal style set used when themes are used
139 themedCSS: {
140 width: '30%',
141 top: '40%',
142 left: '35%'
143 },
144
145 // styles for the overlay
146 overlayCSS: {
147 backgroundColor: '#000',
148 opacity: 0.6,
149 cursor: 'wait'
150 },
151
152 // style to replace wait cursor before unblocking to correct issue
153 // of lingering wait cursor
154 cursorReset: 'default',
155
156 // styles applied when using $.growlUI
157 growlCSS: {
158 width: '350px',
159 top: '10px',
160 left: '',
161 right: '10px',
162 border: 'none',
163 padding: '5px',
164 opacity: 0.6,
165 cursor: 'default',
166 color: '#fff',
167 backgroundColor: '#000',
168 '-webkit-border-radius':'10px',
169 '-moz-border-radius': '10px',
170 'border-radius': '10px'
171 },
172
173 // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
174 // (hat tip to Jorge H. N. de Vasconcelos)
175 /*jshint scripturl:true */
176 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
177
178 // force usage of iframe in non-IE browsers (handy for blocking applets)
179 forceIframe: false,
180
181 // z-index for the blocking overlay
182 baseZ: 1000,
183
184 // set these to true to have the message automatically centered
185 centerX: true, // <-- only effects element blocking (page block controlled via css above)
186 centerY: true,
187
188 // allow body element to be stetched in ie6; this makes blocking look better
189 // on "short" pages. disable if you wish to prevent changes to the body height
190 allowBodyStretch: true,
191
192 // enable if you want key and mouse events to be disabled for content that is blocked
193 bindEvents: true,
194
195 // be default blockUI will supress tab navigation from leaving blocking content
196 // (if bindEvents is true)
197 constrainTabKey: true,
198
199 // fadeIn time in millis; set to 0 to disable fadeIn on block
200 fadeIn: 200,
201
202 // fadeOut time in millis; set to 0 to disable fadeOut on unblock
203 fadeOut: 400,
204
205 // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
206 timeout: 0,
207
208 // disable if you don't want to show the overlay
209 showOverlay: true,
210
211 // if true, focus will be placed in the first available input field when
212 // page blocking
213 focusInput: true,
214
215 // elements that can receive focus
216 focusableElements: ':input:enabled:visible',
217
218 // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
219 // no longer needed in 2012
220 // applyPlatformOpacityRules: true,
221
222 // callback method invoked when fadeIn has completed and blocking message is visible
223 onBlock: null,
224
225 // callback method invoked when unblocking has completed; the callback is
226 // passed the element that has been unblocked (which is the window object for page
227 // blocks) and the options that were passed to the unblock call:
228 // onUnblock(element, options)
229 onUnblock: null,
230
231 // callback method invoked when the overlay area is clicked.
232 // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
233 onOverlayClick: null,
234
235 // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
236 quirksmodeOffsetHack: 4,
237
238 // class name of the message block
239 blockMsgClass: 'blockMsg',
240
241 // if it is already blocked, then ignore it (don't unblock and reblock)
242 ignoreIfBlocked: false
243 };
244
245 // private data and functions follow...
246
247 var pageBlock = null;
248 var pageBlockEls = [];
249
250 function install(el, opts) {
251 var css, themedCSS;
252 var full = (el == window);
253 var msg = (opts && opts.message !== undefined ? opts.message : undefined);
254 opts = $.extend({}, $.blockUI.defaults, opts || {});
255
256 if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
257 return;
258
259 opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
260 css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
261 if (opts.onOverlayClick)
262 opts.overlayCSS.cursor = 'pointer';
263
264 themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
265 msg = msg === undefined ? opts.message : msg;
266
267 // remove the current block (if there is one)
268 if (full && pageBlock)
269 remove(window, {fadeOut:0});
270
271 // if an existing element is being used as the blocking content then we capture
272 // its current place in the DOM (and current display style) so we can restore
273 // it when we unblock
274 if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
275 var node = msg.jquery ? msg[0] : msg;
276 var data = {};
277 $(el).data('blockUI.history', data);
278 data.el = node;
279 data.parent = node.parentNode;
280 data.display = node.style.display;
281 data.position = node.style.position;
282 if (data.parent)
283 data.parent.removeChild(node);
284 }
285
286 $(el).data('blockUI.onUnblock', opts.onUnblock);
287 var z = opts.baseZ;
288
289 // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
290 // layer1 is the iframe layer which is used to supress bleed through of underlying content
291 // layer2 is the overlay layer which has opacity and a wait cursor (by default)
292 // layer3 is the message content that is displayed while blocking
293 var lyr1, lyr2, lyr3, s;
294 if (msie || opts.forceIframe)
295 lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
296 else
297 lyr1 = $('<div class="blockUI" style="display:none"></div>');
298
299 if (opts.theme)
300 lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
301 else
302 lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
303
304 if (opts.theme && full) {
305 s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
306 if ( opts.title ) {
307 s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
308 }
309 s += '<div class="ui-widget-content ui-dialog-content"></div>';
310 s += '</div>';
311 }
312 else if (opts.theme) {
313 s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
314 if ( opts.title ) {
315 s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
316 }
317 s += '<div class="ui-widget-content ui-dialog-content"></div>';
318 s += '</div>';
319 }
320 else if (full) {
321 s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
322 }
323 else {
324 s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
325 }
326 lyr3 = $(s);
327
328 // if we have a message, style it
329 if (msg) {
330 if (opts.theme) {
331 lyr3.css(themedCSS);
332 lyr3.addClass('ui-widget-content');
333 }
334 else
335 lyr3.css(css);
336 }
337
338 // style the overlay
339 if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
340 lyr2.css(opts.overlayCSS);
341 lyr2.css('position', full ? 'fixed' : 'absolute');
342
343 // make iframe layer transparent in IE
344 if (msie || opts.forceIframe)
345 lyr1.css('opacity',0.0);
346
347 //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
348 var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
349 $.each(layers, function() {
350 this.appendTo($par);
351 });
352
353 if (opts.theme && opts.draggable && $.fn.draggable) {
354 lyr3.draggable({
355 handle: '.ui-dialog-titlebar',
356 cancel: 'li'
357 });
358 }
359
360 // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
361 var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
362 if (ie6 || expr) {
363 // give body 100% height
364 if (full && opts.allowBodyStretch && $.support.boxModel)
365 $('html,body').css('height','100%');
366
367 // fix ie6 issue when blocked element has a border width
368 if ((ie6 || !$.support.boxModel) && !full) {
369 var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
370 var fixT = t ? '(0 - '+t+')' : 0;
371 var fixL = l ? '(0 - '+l+')' : 0;
372 }
373
374 // simulate fixed position
375 $.each(layers, function(i,o) {
376 var s = o[0].style;
377 s.position = 'absolute';
378 if (i < 2) {
379 if (full)
380 s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
381 else
382 s.setExpression('height','this.parentNode.offsetHeight + "px"');
383 if (full)
384 s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
385 else
386 s.setExpression('width','this.parentNode.offsetWidth + "px"');
387 if (fixL) s.setExpression('left', fixL);
388 if (fixT) s.setExpression('top', fixT);
389 }
390 else if (opts.centerY) {
391 if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
392 s.marginTop = 0;
393 }
394 else if (!opts.centerY && full) {
395 var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
396 var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
397 s.setExpression('top',expression);
398 }
399 });
400 }
401
402 // show the message
403 if (msg) {
404 if (opts.theme)
405 lyr3.find('.ui-widget-content').append(msg);
406 else
407 lyr3.append(msg);
408 if (msg.jquery || msg.nodeType)
409 $(msg).show();
410 }
411
412 if ((msie || opts.forceIframe) && opts.showOverlay)
413 lyr1.show(); // opacity is zero
414 if (opts.fadeIn) {
415 var cb = opts.onBlock ? opts.onBlock : noOp;
416 var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
417 var cb2 = msg ? cb : noOp;
418 if (opts.showOverlay)
419 lyr2._fadeIn(opts.fadeIn, cb1);
420 if (msg)
421 lyr3._fadeIn(opts.fadeIn, cb2);
422 }
423 else {
424 if (opts.showOverlay)
425 lyr2.show();
426 if (msg)
427 lyr3.show();
428 if (opts.onBlock)
429 opts.onBlock.bind(lyr3)();
430 }
431
432 // bind key and mouse events
433 bind(1, el, opts);
434
435 if (full) {
436 pageBlock = lyr3[0];
437 pageBlockEls = $(opts.focusableElements,pageBlock);
438 if (opts.focusInput)
439 setTimeout(focus, 20);
440 }
441 else
442 center(lyr3[0], opts.centerX, opts.centerY);
443
444 if (opts.timeout) {
445 // auto-unblock
446 var to = setTimeout(function() {
447 if (full)
448 $.unblockUI(opts);
449 else
450 $(el).unblock(opts);
451 }, opts.timeout);
452 $(el).data('blockUI.timeout', to);
453 }
454 }
455
456 // remove the block
457 function remove(el, opts) {
458 var count;
459 var full = (el == window);
460 var $el = $(el);
461 var data = $el.data('blockUI.history');
462 var to = $el.data('blockUI.timeout');
463 if (to) {
464 clearTimeout(to);
465 $el.removeData('blockUI.timeout');
466 }
467 opts = $.extend({}, $.blockUI.defaults, opts || {});
468 bind(0, el, opts); // unbind events
469
470 if (opts.onUnblock === null) {
471 opts.onUnblock = $el.data('blockUI.onUnblock');
472 $el.removeData('blockUI.onUnblock');
473 }
474
475 var els;
476 if (full) // crazy selector to handle odd field errors in ie6/7
477 els = $('body').children().filter('.blockUI').add('body > .blockUI');
478 else
479 els = $el.find('>.blockUI');
480
481 // fix cursor issue
482 if ( opts.cursorReset ) {
483 if ( els.length > 1 )
484 els[1].style.cursor = opts.cursorReset;
485 if ( els.length > 2 )
486 els[2].style.cursor = opts.cursorReset;
487 }
488
489 if (full)
490 pageBlock = pageBlockEls = null;
491
492 if (opts.fadeOut) {
493 count = els.length;
494 els.stop().fadeOut(opts.fadeOut, function() {
495 if ( --count === 0)
496 reset(els,data,opts,el);
497 });
498 }
499 else
500 reset(els, data, opts, el);
501 }
502
503 // move blocking element back into the DOM where it started
504 function reset(els,data,opts,el) {
505 var $el = $(el);
506 if ( $el.data('blockUI.isBlocked') )
507 return;
508
509 els.each(function(i,o) {
510 // remove via DOM calls so we don't lose event handlers
511 if (this.parentNode)
512 this.parentNode.removeChild(this);
513 });
514
515 if (data && data.el) {
516 data.el.style.display = data.display;
517 data.el.style.position = data.position;
518 data.el.style.cursor = 'default'; // #59
519 if (data.parent)
520 data.parent.appendChild(data.el);
521 $el.removeData('blockUI.history');
522 }
523
524 if ($el.data('blockUI.static')) {
525 $el.css('position', 'static'); // #22
526 }
527
528 if (typeof opts.onUnblock == 'function')
529 opts.onUnblock(el,opts);
530
531 // fix issue in Safari 6 where block artifacts remain until reflow
532 var body = $(document.body), w = body.width(), cssW = body[0].style.width;
533 body.width(w-1).width(w);
534 body[0].style.width = cssW;
535 }
536
537 // bind/unbind the handler
538 function bind(b, el, opts) {
539 var full = el == window, $el = $(el);
540
541 // don't bother unbinding if there is nothing to unbind
542 if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
543 return;
544
545 $el.data('blockUI.isBlocked', b);
546
547 // don't bind events when overlay is not in use or if bindEvents is false
548 if (!full || !opts.bindEvents || (b && !opts.showOverlay))
549 return;
550
551 // bind anchors and inputs for mouse and key events
552 var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
553 if (b)
554 $(document).bind(events, opts, handler);
555 else
556 $(document).unbind(events, handler);
557
558 // former impl...
559 // var $e = $('a,:input');
560 // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
561 }
562
563 // event handler to suppress keyboard/mouse events when blocking
564 function handler(e) {
565 // allow tab navigation (conditionally)
566 if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
567 if (pageBlock && e.data.constrainTabKey) {
568 var els = pageBlockEls;
569 var fwd = !e.shiftKey && e.target === els[els.length-1];
570 var back = e.shiftKey && e.target === els[0];
571 if (fwd || back) {
572 setTimeout(function(){focus(back);},10);
573 return false;
574 }
575 }
576 }
577 var opts = e.data;
578 var target = $(e.target);
579 if (target.hasClass('blockOverlay') && opts.onOverlayClick)
580 opts.onOverlayClick(e);
581
582 // allow events within the message content
583 if (target.parents('div.' + opts.blockMsgClass).length > 0)
584 return true;
585
586 // allow events for content that is not being blocked
587 return target.parents().children().filter('div.blockUI').length === 0;
588 }
589
590 function focus(back) {
591 if (!pageBlockEls)
592 return;
593 var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
594 if (e)
595 e.focus();
596 }
597
598 function center(el, x, y) {
599 var p = el.parentNode, s = el.style;
600 var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
601 var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
602 if (x) s.left = l > 0 ? (l+'px') : '0';
603 if (y) s.top = t > 0 ? (t+'px') : '0';
604 }
605
606 function sz(el, p) {
607 return parseInt($.css(el,p),10)||0;
608 }
609
610 }
611
612
613 /*global define:true */
614 if (typeof define === 'function' && define.amd && define.amd.jQuery) {
615 define(['jquery'], setup);
616 } else {
617 setup(jQuery);
618 }
619
620 })();
@@ -0,0 +1,4 b''
1 /*! jQuery v2.2.0 | (c) jQuery Foundation | jquery.org/license */
2 !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!k.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=R.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q," ")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c}catch(e){}O.set(a,b,c);
3 }else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=N.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function W(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&T.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var X=/^(?:checkbox|radio)$/i,Y=/<([\w:-]+)/,Z=/^$|\/(?:java|ecma)script/i,$={option:[1,"<select multiple='multiple'>","</select>"],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,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return this;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,e,f,g=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||d,e=c.documentElement,f=c.body,a.pageX=b.clientX+(e&&e.scrollLeft||f&&f.scrollLeft||0)-(e&&e.clientLeft||f&&f.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||f&&f.scrollTop||0)-(e&&e.clientTop||f&&f.clientTop||0)),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ea.test(f)?this.mouseHooks:da.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=d),3===a.target.nodeType&&(a.target=a.target.parentNode),h.filter?h.filter(a,g):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==ia()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===ia()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ga:ha):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:ha,isPropagationStopped:ha,isImmediatePropagationStopped:ha,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ga,a&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ga,a&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ga,a&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),n.fn.extend({on:function(a,b,c,d){return ja(this,a,b,c,d)},one:function(a,b,c,d){return ja(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=ha),this.each(function(){n.event.remove(this,a,c,b)})}});var ka=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,la=/<script|<style|<link/i,ma=/checked\s*(?:[^=]|=\s*.checked.)/i,na=/^true\/(.*)/,oa=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=wa[0].contentDocument,b.write(),b.close(),c=ya(a,b),wa.detach()),xa[a]=c),c}var Aa=/^margin/,Ba=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ca=function(b){var c=b.ownerDocument.defaultView;return c.opener||(c=a),c.getComputedStyle(b)},Da=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Ea=d.documentElement;!function(){var b,c,e,f,g=d.createElement("div"),h=d.createElement("div");if(h.style){h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,g.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",g.appendChild(h);function i(){h.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",h.innerHTML="",Ea.appendChild(g);var d=a.getComputedStyle(h);b="1%"!==d.top,f="2px"===d.marginLeft,c="4px"===d.width,h.style.marginRight="50%",e="4px"===d.marginRight,Ea.removeChild(g)}n.extend(l,{pixelPosition:function(){return i(),b},boxSizingReliable:function(){return null==c&&i(),c},pixelMarginRight:function(){return null==c&&i(),e},reliableMarginLeft:function(){return null==c&&i(),f},reliableMarginRight:function(){var b,c=h.appendChild(d.createElement("div"));return c.style.cssText=h.style.cssText="-webkit-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",h.style.width="1px",Ea.appendChild(g),b=!parseFloat(a.getComputedStyle(c).marginRight),Ea.removeChild(g),h.removeChild(c),b}})}}();function Fa(a,b,c){var d,e,f,g,h=a.style;return c=c||Ca(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),!l.pixelMarginRight()&&Ba.test(g)&&Aa.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Ga(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Ha=/^(none|table(?!-c[ea]).+)/,Ia={position:"absolute",visibility:"hidden",display:"block"},Ja={letterSpacing:"0",fontWeight:"400"},Ka=["Webkit","O","Moz","ms"],La=d.createElement("div").style;function Ma(a){if(a in La)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ka.length;while(c--)if(a=Ka[c]+b,a in La)return a}function Na(a,b,c){var d=T.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Oa(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Pa(b,c,e){var f=!0,g="width"===c?b.offsetWidth:b.offsetHeight,h=Ca(b),i="border-box"===n.css(b,"boxSizing",!1,h);if(d.msFullscreenElement&&a.top!==a&&b.getClientRects().length&&(g=Math.round(100*b.getBoundingClientRect()[c])),0>=g||null==g){if(g=Fa(b,c,h),(0>g||null==g)&&(g=b.style[c]),Ba.test(g))return g;f=i&&(l.boxSizingReliable()||g===b.style[c]),g=parseFloat(g)||0}return g+Oa(b,c,e||(i?"border":"content"),f,h)+"px"}function Qa(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=N.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=N.access(d,"olddisplay",za(d.nodeName)))):(e=V(d),"none"===c&&e||N.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Fa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Ma(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=T.exec(c))&&e[1]&&(c=W(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(n.cssNumber[h]?"":"px")),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Ma(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Fa(a,b,d)),"normal"===e&&b in Ja&&(e=Ja[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Ha.test(n.css(a,"display"))&&0===a.offsetWidth?Da(a,Ia,function(){return Pa(a,b,d)}):Pa(a,b,d):void 0},set:function(a,c,d){var e,f=d&&Ca(a),g=d&&Oa(a,b,d,"border-box"===n.css(a,"boxSizing",!1,f),f);return g&&(e=T.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=n.css(a,b)),Na(a,c,g)}}}),n.cssHooks.marginLeft=Ga(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Fa(a,"marginLeft"))||a.getBoundingClientRect().left-Da(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px":void 0}),n.cssHooks.marginRight=Ga(l.reliableMarginRight,function(a,b){return b?Da(a,{display:"inline-block"},Fa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Aa.test(a)||(n.cssHooks[a+b].set=Na)}),n.fn.extend({css:function(a,b){return K(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ca(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Qa(this,!0)},hide:function(){return Qa(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function Ra(a,b,c,d,e){return new Ra.prototype.init(a,b,c,d,e)}n.Tween=Ra,Ra.prototype={constructor:Ra,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ra.propHooks[this.prop];return a&&a.get?a.get(this):Ra.propHooks._default.get(this)},run:function(a){var b,c=Ra.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ra.propHooks._default.set(this),this}},Ra.prototype.init.prototype=Ra.prototype,Ra.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},Ra.propHooks.scrollTop=Ra.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=Ra.prototype.init,n.fx.step={};var Sa,Ta,Ua=/^(?:toggle|show|hide)$/,Va=/queueHooks$/;function Wa(){return a.setTimeout(function(){Sa=void 0}),Sa=n.now()}function Xa(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=U[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ya(a,b,c){for(var d,e=(_a.tweeners[b]||[]).concat(_a.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Za(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&V(a),q=N.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?N.get(a,"olddisplay")||za(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Ua.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?za(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=N.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;N.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ya(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function $a(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function _a(a,b,c){var d,e,f=0,g=_a.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Sa||Wa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:Sa||Wa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for($a(k,j.opts.specialEasing);g>f;f++)if(d=_a.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,Ya,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(_a,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return W(c.elem,a,T.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],_a.tweeners[c]=_a.tweeners[c]||[],_a.tweeners[c].unshift(b)},prefilters:[Za],prefilter:function(a,b){b?_a.prefilters.unshift(a):_a.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=_a(this,n.extend({},a),f);(e||N.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=N.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Va.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=N.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Xa(b,!0),a,d,e)}}),n.each({slideDown:Xa("show"),slideUp:Xa("hide"),slideToggle:Xa("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Sa=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Sa=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ta||(Ta=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(Ta),Ta=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=d.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var ab,bb=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return K(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ab:void 0)),void 0!==c?null===c?void n.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)}}),ab={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=bb[b]||n.find.attr;bb[b]=function(a,b,d){var e,f;return d||(f=bb[b],bb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,bb[b]=f),e}});var cb=/^(?:input|select|textarea|button)$/i,db=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return K(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b];
4 },propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):cb.test(a.nodeName)||db.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var eb=/[\t\r\n\f]/g;function fb(a){return a.getAttribute&&a.getAttribute("class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,fb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,fb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,fb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(void 0===a||"boolean"===c)&&(b=fb(this),b&&N.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":N.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+fb(c)+" ").replace(eb," ").indexOf(b)>-1)return!0;return!1}});var gb=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(gb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){return n.trim(a.value)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(n.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var hb=/^(?:focusinfocus|focusoutblur)$/;n.extend(n.event,{trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!hb.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),l=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},f||!o.trigger||o.trigger.apply(e,c)!==!1)){if(!f&&!o.noBubble&&!n.isWindow(e)){for(j=o.delegateType||q,hb.test(j+q)||(h=h.parentNode);h;h=h.parentNode)p.push(h),i=h;i===(e.ownerDocument||d)&&p.push(i.defaultView||i.parentWindow||a)}g=0;while((h=p[g++])&&!b.isPropagationStopped())b.type=g>1?j:o.bindType||q,m=(N.get(h,"events")||{})[b.type]&&N.get(h,"handle"),m&&m.apply(h,c),m=l&&h[l],m&&m.apply&&L(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=q,f||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!L(e)||l&&n.isFunction(e[q])&&!n.isWindow(e)&&(i=e[l],i&&(e[l]=null),n.event.triggered=q,e[q](),n.event.triggered=void 0,i&&(e[l]=i)),b.result}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}}),n.fn.extend({trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),l.focusin="onfocusin"in a,l.focusin||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=N.access(d,b);e||d.addEventListener(a,c,!0),N.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=N.access(d,b)-1;e?N.access(d,b,e):(d.removeEventListener(a,c,!0),N.remove(d,b))}}});var ib=a.location,jb=n.now(),kb=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return(!c||c.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+b),c};var lb=/#.*$/,mb=/([?&])_=[^&]*/,nb=/^(.*?):[ \t]*([^\r\n]*)$/gm,ob=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,pb=/^(?:GET|HEAD)$/,qb=/^\/\//,rb={},sb={},tb="*/".concat("*"),ub=d.createElement("a");ub.href=ib.href;function vb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function wb(a,b,c,d){var e={},f=a===sb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function xb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function yb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function zb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ib.href,type:"GET",isLocal:ob.test(ib.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":tb,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":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?xb(xb(a,n.ajaxSettings),b):xb(n.ajaxSettings,a)},ajaxPrefilter:vb(rb),ajaxTransport:vb(sb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m=n.ajaxSetup({},c),o=m.context||m,p=m.context&&(o.nodeType||o.jquery)?n(o):n.event,q=n.Deferred(),r=n.Callbacks("once memory"),s=m.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,getResponseHeader:function(a){var b;if(2===v){if(!h){h={};while(b=nb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===v?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return v||(a=u[c]=u[c]||a,t[a]=b),this},overrideMimeType:function(a){return v||(m.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>v)for(b in a)s[b]=[s[b],a[b]];else x.always(a[x.status]);return this},abort:function(a){var b=a||w;return e&&e.abort(b),z(0,b),this}};if(q.promise(x).complete=r.add,x.success=x.done,x.error=x.fail,m.url=((b||m.url||ib.href)+"").replace(lb,"").replace(qb,ib.protocol+"//"),m.type=c.method||c.type||m.method||m.type,m.dataTypes=n.trim(m.dataType||"*").toLowerCase().match(G)||[""],null==m.crossDomain){j=d.createElement("a");try{j.href=m.url,j.href=j.href,m.crossDomain=ub.protocol+"//"+ub.host!=j.protocol+"//"+j.host}catch(y){m.crossDomain=!0}}if(m.data&&m.processData&&"string"!=typeof m.data&&(m.data=n.param(m.data,m.traditional)),wb(rb,m,c,x),2===v)return x;k=n.event&&m.global,k&&0===n.active++&&n.event.trigger("ajaxStart"),m.type=m.type.toUpperCase(),m.hasContent=!pb.test(m.type),f=m.url,m.hasContent||(m.data&&(f=m.url+=(kb.test(f)?"&":"?")+m.data,delete m.data),m.cache===!1&&(m.url=mb.test(f)?f.replace(mb,"$1_="+jb++):f+(kb.test(f)?"&":"?")+"_="+jb++)),m.ifModified&&(n.lastModified[f]&&x.setRequestHeader("If-Modified-Since",n.lastModified[f]),n.etag[f]&&x.setRequestHeader("If-None-Match",n.etag[f])),(m.data&&m.hasContent&&m.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",m.contentType),x.setRequestHeader("Accept",m.dataTypes[0]&&m.accepts[m.dataTypes[0]]?m.accepts[m.dataTypes[0]]+("*"!==m.dataTypes[0]?", "+tb+"; q=0.01":""):m.accepts["*"]);for(l in m.headers)x.setRequestHeader(l,m.headers[l]);if(m.beforeSend&&(m.beforeSend.call(o,x,m)===!1||2===v))return x.abort();w="abort";for(l in{success:1,error:1,complete:1})x[l](m[l]);if(e=wb(sb,m,c,x)){if(x.readyState=1,k&&p.trigger("ajaxSend",[x,m]),2===v)return x;m.async&&m.timeout>0&&(i=a.setTimeout(function(){x.abort("timeout")},m.timeout));try{v=1,e.send(t,z)}catch(y){if(!(2>v))throw y;z(-1,y)}}else z(-1,"No Transport");function z(b,c,d,h){var j,l,t,u,w,y=c;2!==v&&(v=2,i&&a.clearTimeout(i),e=void 0,g=h||"",x.readyState=b>0?4:0,j=b>=200&&300>b||304===b,d&&(u=yb(m,x,d)),u=zb(m,u,x,j),j?(m.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(n.lastModified[f]=w),w=x.getResponseHeader("etag"),w&&(n.etag[f]=w)),204===b||"HEAD"===m.type?y="nocontent":304===b?y="notmodified":(y=u.state,l=u.data,t=u.error,j=!t)):(t=y,(b||!y)&&(y="error",0>b&&(b=0))),x.status=b,x.statusText=(c||y)+"",j?q.resolveWith(o,[l,y,x]):q.rejectWith(o,[x,y,t]),x.statusCode(s),s=void 0,k&&p.trigger(j?"ajaxSuccess":"ajaxError",[x,m,j?l:t]),r.fireWith(o,[x,y]),k&&(p.trigger("ajaxComplete",[x,m]),--n.active||n.event.trigger("ajaxStop")))}return x},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return!n.expr.filters.visible(a)},n.expr.filters.visible=function(a){return a.offsetWidth>0||a.offsetHeight>0||a.getClientRects().length>0};var Ab=/%20/g,Bb=/\[\]$/,Cb=/\r?\n/g,Db=/^(?:submit|button|image|reset|file)$/i,Eb=/^(?:input|select|textarea|keygen)/i;function Fb(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Bb.test(a)?d(a,e):Fb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Fb(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Fb(c,a[c],b,e);return d.join("&").replace(Ab,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Eb.test(this.nodeName)&&!Db.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Cb,"\r\n")}}):{name:b.name,value:c.replace(Cb,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Gb={0:200,1223:204},Hb=n.ajaxSettings.xhr();l.cors=!!Hb&&"withCredentials"in Hb,l.ajax=Hb=!!Hb,n.ajaxTransport(function(b){var c,d;return l.cors||Hb&&!b.crossDomain?{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Gb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=n("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Ib=[],Jb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Ib.pop()||n.expando+"_"+jb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Jb.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Jb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Jb,"$1"+e):b.jsonp!==!1&&(b.url+=(kb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Ib.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),l.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||(l.createHTMLDocument?d.implementation.createHTMLDocument(""):d);var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ca([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var Kb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Kb)return Kb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(g,f||[a.responseText,b,a])})}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function Lb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(e=d.getBoundingClientRect(),c=Lb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0)-a.scrollTop(),d.left+=n.css(a[0],"borderLeftWidth",!0)-a.scrollLeft()),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ea})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;n.fn[a]=function(d){return K(this,function(a,d,e){var f=Lb(a);return void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Ga(l.pixelPosition,function(a,c){return c?(c=Fa(a,b),Ba.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return K(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)},size:function(){return this.length}}),n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Mb=a.jQuery,Nb=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Nb),b&&a.jQuery===n&&(a.jQuery=Mb),n},b||(a.jQuery=a.$=n),n});
@@ -0,0 +1,53 b''
1 var UPDATE_INTERVAL = 10000;
2
3 var ports = [];
4 var includePostBody = false;
5
6 function updateFavPosts() {
7 var url = '/api/new_posts/';
8 if (includePostBody) {
9 url += '?include_posts';
10 }
11
12 var xhr = new XMLHttpRequest();
13
14 xhr.onreadystatechange = function() {
15 if (xhr.readyState == XMLHttpRequest.DONE) {
16 if (xhr.status == 200 || xhr.status == 304) {
17 var data = xhr.responseText;
18 for (var i = 0; i < ports.length; i++) {
19 port = ports[i];
20 try {
21 port.postMessage(data);
22 } catch (error) {
23 // Assume the port was closed with the tab
24 var index = ports.indexOf(port);
25 ports.splice(index, 1);
26 }
27 }
28 }
29 }
30 }
31
32 xhr.open('GET', url);
33 xhr.send(null);
34 }
35
36 onconnect = function(e) {
37 var port = e.ports[0];
38 port.start();
39
40 port.onmessage = function(e) {
41 // FIXME For now we include body even if a panel was opened once
42 if (e.data.includePostBody) {
43 includePostBody = true;
44 }
45 updateFavPosts();
46 }
47
48 ports.push(port);
49 }
50
51 setInterval(function() {
52 updateFavPosts();
53 }, UPDATE_INTERVAL);
@@ -37,3 +37,4 b' c48ffdc671566069ed0f33644da1229277f3cd18'
37 d66dc192d4e089ba85325afeef5229b73cb0fde4 2.10.0
37 d66dc192d4e089ba85325afeef5229b73cb0fde4 2.10.0
38 1c22a38cca9ae3bee13d6f263792c0629d0061f6 2.10.1
38 1c22a38cca9ae3bee13d6f263792c0629d0061f6 2.10.1
39 3076e0d03339f3b41dcc71fb6af2b4169920846c 2.11.0
39 3076e0d03339f3b41dcc71fb6af2b4169920846c 2.11.0
40 9cffa58fae74952b8ffe70328af88a5df17059c1 2.12.0
@@ -19,6 +19,7 b" SETTING_USERNAME = 'username'"
19 SETTING_LAST_NOTIFICATION_ID = 'last_notification'
19 SETTING_LAST_NOTIFICATION_ID = 'last_notification'
20 SETTING_IMAGE_VIEWER = 'image_viewer'
20 SETTING_IMAGE_VIEWER = 'image_viewer'
21 SETTING_TRIPCODE = 'tripcode'
21 SETTING_TRIPCODE = 'tripcode'
22 SETTING_IMAGES = 'images_aliases'
22
23
23 DEFAULT_THEME = 'md'
24 DEFAULT_THEME = 'md'
24
25
@@ -144,11 +145,25 b' class SettingsManager:'
144 return str(opening_post.id) in self.get_fav_threads()
145 return str(opening_post.id) in self.get_fav_threads()
145
146
146 def get_notification_usernames(self):
147 def get_notification_usernames(self):
148 names = set()
147 name_list = self.get_setting(SETTING_USERNAME)
149 name_list = self.get_setting(SETTING_USERNAME)
148 if name_list is not None and len(name_list) > 0:
150 if name_list is not None:
149 return name_list.lower().split(',')
151 name_list = name_list.strip()
150 else:
152 if len(name_list) > 0:
151 return list()
153 names = name_list.lower().split(',')
154 names = set(name.strip() for name in names)
155 return names
156
157 def get_image_by_alias(self, alias):
158 images = self.get_setting(SETTING_IMAGES)
159 if images is not None and len(images) > 0:
160 return images.get(alias)
161
162 def add_image_alias(self, alias, image):
163 images = self.get_setting(SETTING_IMAGES)
164 if images is None:
165 images = dict()
166 images.put(alias, image)
152
167
153
168
154 class SessionSettingsManager(SettingsManager):
169 class SessionSettingsManager(SettingsManager):
@@ -1,16 +1,17 b''
1 from django.contrib import admin
1 from django.contrib import admin
2 from boards.models import Post, Tag, Ban, Thread, KeyPair, Banner
3 from django.utils.translation import ugettext_lazy as _
2 from django.utils.translation import ugettext_lazy as _
3 from django.core.urlresolvers import reverse
4 from boards.models import Post, Tag, Ban, Thread, Banner, PostImage
4
5
5
6
6 @admin.register(Post)
7 @admin.register(Post)
7 class PostAdmin(admin.ModelAdmin):
8 class PostAdmin(admin.ModelAdmin):
8
9
9 list_display = ('id', 'title', 'text', 'poster_ip')
10 list_display = ('id', 'title', 'text', 'poster_ip', 'linked_images')
10 list_filter = ('pub_time',)
11 list_filter = ('pub_time',)
11 search_fields = ('id', 'title', 'text', 'poster_ip')
12 search_fields = ('id', 'title', 'text', 'poster_ip')
12 exclude = ('referenced_posts', 'refmap')
13 exclude = ('referenced_posts', 'refmap')
13 readonly_fields = ('poster_ip', 'threads', 'thread', 'images',
14 readonly_fields = ('poster_ip', 'threads', 'thread', 'linked_images',
14 'attachments', 'uid', 'url', 'pub_time', 'opening')
15 'attachments', 'uid', 'url', 'pub_time', 'opening')
15
16
16 def ban_poster(self, request, queryset):
17 def ban_poster(self, request, queryset):
@@ -22,7 +23,27 b' class PostAdmin(admin.ModelAdmin):'
22 bans += 1
23 bans += 1
23 self.message_user(request, _('{} posters were banned').format(bans))
24 self.message_user(request, _('{} posters were banned').format(bans))
24
25
25 actions = ['ban_poster']
26 def ban_with_hiding(self, request, queryset):
27 bans = 0
28 hidden = 0
29 for post in queryset:
30 poster_ip = post.poster_ip
31 ban, created = Ban.objects.get_or_create(ip=poster_ip)
32 if created:
33 bans += 1
34 posts = Post.objects.filter(poster_ip=poster_ip, id__gte=post.id)
35 hidden += posts.count()
36 posts.update(hidden=True)
37 self.message_user(request, _('{} posters were banned, {} messages were hidden').format(bans, hidden))
38
39 def linked_images(self, obj: Post):
40 images = obj.images.all()
41 image_urls = ['<a href="{}">{}</a>'.format(reverse('admin:%s_%s_change' %(image._meta.app_label, image._meta.model_name), args=[image.id]), image.hash) for image in images]
42 return ', '.join(image_urls)
43 linked_images.allow_tags = True
44
45
46 actions = ['ban_poster', 'ban_with_hiding']
26
47
27
48
28 @admin.register(Tag)
49 @admin.register(Tag)
@@ -34,6 +55,10 b' class TagAdmin(admin.ModelAdmin):'
34 def display_children(self, obj: Tag):
55 def display_children(self, obj: Tag):
35 return ', '.join([str(child) for child in obj.get_children().all()])
56 return ', '.join([str(child) for child in obj.get_children().all()])
36
57
58 def save_model(self, request, obj, form, change):
59 super().save_model(request, obj, form, change)
60 for thread in obj.get_threads().all():
61 thread.refresh_tags()
37 list_display = ('name', 'thread_count', 'display_children')
62 list_display = ('name', 'thread_count', 'display_children')
38 search_fields = ('name',)
63 search_fields = ('name',)
39
64
@@ -56,6 +81,10 b' class ThreadAdmin(admin.ModelAdmin):'
56 def op(self, obj: Thread):
81 def op(self, obj: Thread):
57 return obj.get_opening_post_id()
82 return obj.get_opening_post_id()
58
83
84 # Save parent tags when editing tags
85 def save_related(self, request, form, formsets, change):
86 super().save_related(request, form, formsets, change)
87 form.instance.refresh_tags()
59 list_display = ('id', 'op', 'title', 'reply_count', 'status', 'ip',
88 list_display = ('id', 'op', 'title', 'reply_count', 'status', 'ip',
60 'display_tags')
89 'display_tags')
61 list_filter = ('bump_time', 'status')
90 list_filter = ('bump_time', 'status')
@@ -1,5 +1,5 b''
1 [Version]
1 [Version]
2 Version = 2.11.0 Yuko
2 Version = 2.12.0 Lyekka
3 SiteName = Neboard DEV
3 SiteName = Neboard DEV
4
4
5 [Cache]
5 [Cache]
@@ -4,8 +4,9 b' from boards.models.user import Notificat'
4
4
5 __author__ = 'neko259'
5 __author__ = 'neko259'
6
6
7 import neboard
7 from boards import settings
8 from boards import settings
8 from boards.models import Post, Tag
9 from boards.models import Post, Tag, Thread
9
10
10 CONTEXT_SITE_NAME = 'site_name'
11 CONTEXT_SITE_NAME = 'site_name'
11 CONTEXT_VERSION = 'version'
12 CONTEXT_VERSION = 'version'
@@ -20,6 +21,8 b" CONTEXT_TAGS_STR = 'tags_str'"
20 CONTEXT_IMAGE_VIEWER = 'image_viewer'
21 CONTEXT_IMAGE_VIEWER = 'image_viewer'
21 CONTEXT_HAS_FAV_THREADS = 'has_fav_threads'
22 CONTEXT_HAS_FAV_THREADS = 'has_fav_threads'
22 CONTEXT_POW_DIFFICULTY = 'pow_difficulty'
23 CONTEXT_POW_DIFFICULTY = 'pow_difficulty'
24 CONTEXT_NEW_POST_COUNT = 'new_post_count'
25 CONTEXT_SEARCH_ENABLED = 'search_enabled'
23
26
24
27
25 def get_notifications(context, request):
28 def get_notifications(context, request):
@@ -31,11 +34,23 b' def get_notifications(context, request):'
31 SETTING_LAST_NOTIFICATION_ID)
34 SETTING_LAST_NOTIFICATION_ID)
32
35
33 new_notifications_count = Notification.objects.get_notification_posts(
36 new_notifications_count = Notification.objects.get_notification_posts(
34 usernames=usernames, last=last_notification_id).count()
37 usernames=usernames, last=last_notification_id).only('id').count()
35 context[CONTEXT_NEW_NOTIFICATIONS_COUNT] = new_notifications_count
38 context[CONTEXT_NEW_NOTIFICATIONS_COUNT] = new_notifications_count
36 context[CONTEXT_USERNAMES] = usernames
39 context[CONTEXT_USERNAMES] = usernames
37
40
38
41
42 def get_new_post_count(context, request):
43 settings_manager = get_settings_manager(request)
44 fav_threads = settings_manager.get_fav_threads()
45 fav_thread_ops = Post.objects.filter(id__in=fav_threads.keys()) \
46 .order_by('-pub_time').only('thread_id', 'pub_time')
47
48 ops = [{'op': op, 'last_id': fav_threads[str(op.id)]} for op in fav_thread_ops]
49 count = Thread.objects.get_new_post_count(ops)
50 if count > 0:
51 context[CONTEXT_NEW_POST_COUNT] = '(+{})'.format(count)
52
53
39 def user_and_ui_processor(request):
54 def user_and_ui_processor(request):
40 context = dict()
55 context = dict()
41
56
@@ -53,7 +68,7 b' def user_and_ui_processor(request):'
53 context[CONTEXT_VERSION] = settings.get('Version', 'Version')
68 context[CONTEXT_VERSION] = settings.get('Version', 'Version')
54 context[CONTEXT_SITE_NAME] = settings.get('Version', 'SiteName')
69 context[CONTEXT_SITE_NAME] = settings.get('Version', 'SiteName')
55
70
56 if settings.get_bool('Forms', 'LimitPostingSpeed'):
71 if settings.get_bool('Forms', 'LimitPostingSpeed') and not settings_manager.get_setting('confirmed_user'):
57 context[CONTEXT_POW_DIFFICULTY] = settings.get_int('Forms', 'PowDifficulty')
72 context[CONTEXT_POW_DIFFICULTY] = settings.get_int('Forms', 'PowDifficulty')
58
73
59 context[CONTEXT_IMAGE_VIEWER] = settings_manager.get_setting(
74 context[CONTEXT_IMAGE_VIEWER] = settings_manager.get_setting(
@@ -63,6 +78,9 b' def user_and_ui_processor(request):'
63 context[CONTEXT_HAS_FAV_THREADS] =\
78 context[CONTEXT_HAS_FAV_THREADS] =\
64 len(settings_manager.get_fav_threads()) > 0
79 len(settings_manager.get_fav_threads()) > 0
65
80
81 context[CONTEXT_SEARCH_ENABLED] = 'haystack' in neboard.settings.INSTALLED_APPS
82
66 get_notifications(context, request)
83 get_notifications(context, request)
84 get_new_post_count(context, request)
67
85
68 return context
86 return context
@@ -8,10 +8,12 b' import pytz'
8 from django import forms
8 from django import forms
9 from django.core.files.uploadedfile import SimpleUploadedFile
9 from django.core.files.uploadedfile import SimpleUploadedFile
10 from django.core.exceptions import ObjectDoesNotExist
10 from django.core.exceptions import ObjectDoesNotExist
11 from django.forms.util import ErrorList
11 from django.forms.utils import ErrorList
12 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
12 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
13 from django.utils import timezone
13 from django.utils import timezone
14
14
15 from boards.abstracts.settingsmanager import get_settings_manager
16 from boards.abstracts.attachment_alias import get_image_by_alias
15 from boards.mdx_neboard import formatters
17 from boards.mdx_neboard import formatters
16 from boards.models.attachment.downloaders import Downloader
18 from boards.models.attachment.downloaders import Downloader
17 from boards.models.post import TITLE_MAX_LENGTH
19 from boards.models.post import TITLE_MAX_LENGTH
@@ -23,7 +25,7 b' import boards.settings as board_settings'
23 import neboard
25 import neboard
24
26
25 POW_HASH_LENGTH = 16
27 POW_HASH_LENGTH = 16
26 POW_LIFE_MINUTES = 1
28 POW_LIFE_MINUTES = 5
27
29
28 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
30 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
29 REGEX_USERNAMES = re.compile(r'^[\w\s\d,]+$', re.UNICODE)
31 REGEX_USERNAMES = re.compile(r'^[\w\s\d,]+$', re.UNICODE)
@@ -62,6 +64,8 b' MIMETYPE_EXTENSIONS = {'
62 'x-diff': 'diff',
64 'x-diff': 'diff',
63 'image/svg+xml': 'svg',
65 'image/svg+xml': 'svg',
64 'application/x-shockwave-flash': 'swf',
66 'application/x-shockwave-flash': 'swf',
67 'image/x-ms-bmp': 'bmp',
68 'image/bmp': 'bmp',
65 }
69 }
66
70
67
71
@@ -180,6 +184,7 b' class PostForm(NeboardForm):'
180
184
181 session = None
185 session = None
182 need_to_ban = False
186 need_to_ban = False
187 image = None
183
188
184 def _update_file_extension(self, file):
189 def _update_file_extension(self, file):
185 if file:
190 if file:
@@ -226,13 +231,20 b' class PostForm(NeboardForm):'
226 url = self.cleaned_data['file_url']
231 url = self.cleaned_data['file_url']
227
232
228 file = None
233 file = None
234
229 if url:
235 if url:
230 file = self._get_file_from_url(url)
236 file = get_image_by_alias(url, self.session)
237 self.image = file
231
238
232 if not file:
239 if file is not None:
233 raise forms.ValidationError(_('Invalid URL'))
240 return
234 else:
241
235 validate_file_size(file.size)
242 if file is None:
243 file = self._get_file_from_url(url)
244 if not file:
245 raise forms.ValidationError(_('Invalid URL'))
246 else:
247 validate_file_size(file.size)
236 self._update_file_extension(file)
248 self._update_file_extension(file)
237
249
238 return file
250 return file
@@ -267,12 +279,21 b' class PostForm(NeboardForm):'
267 self._clean_text_file()
279 self._clean_text_file()
268
280
269 limit_speed = board_settings.get_bool('Forms', 'LimitPostingSpeed')
281 limit_speed = board_settings.get_bool('Forms', 'LimitPostingSpeed')
270 if not self.errors and limit_speed:
282
283 settings_manager = get_settings_manager(self)
284 if not self.errors and limit_speed and not settings_manager.get_setting('confirmed_user'):
271 pow_difficulty = board_settings.get_int('Forms', 'PowDifficulty')
285 pow_difficulty = board_settings.get_int('Forms', 'PowDifficulty')
272 if pow_difficulty > 0 and cleaned_data['timestamp'] and cleaned_data['iteration'] and cleaned_data['guess']:
286 if pow_difficulty > 0:
273 self._validate_hash(cleaned_data['timestamp'], cleaned_data['iteration'], cleaned_data['guess'], cleaned_data['text'])
287 # Limit only first post
288 if cleaned_data['timestamp'] \
289 and cleaned_data['iteration'] and cleaned_data['guess'] \
290 and not settings_manager.get_setting('confirmed_user'):
291 self._validate_hash(cleaned_data['timestamp'], cleaned_data['iteration'], cleaned_data['guess'], cleaned_data['text'])
274 else:
292 else:
293 # Limit every post
275 self._validate_posting_speed()
294 self._validate_posting_speed()
295 settings_manager.set_setting('confirmed_user', True)
296
276
297
277 return cleaned_data
298 return cleaned_data
278
299
@@ -300,11 +321,18 b' class PostForm(NeboardForm):'
300 else:
321 else:
301 return title
322 return title
302
323
324 def get_images(self):
325 if self.image:
326 return [self.image]
327 else:
328 return []
329
303 def _clean_text_file(self):
330 def _clean_text_file(self):
304 text = self.cleaned_data.get('text')
331 text = self.cleaned_data.get('text')
305 file = self.get_file()
332 file = self.get_file()
333 images = self.get_images()
306
334
307 if (not text) and (not file):
335 if (not text) and (not file) and len(images) == 0:
308 error_message = _('Either text or file must be entered.')
336 error_message = _('Either text or file must be entered.')
309 self._errors['text'] = self.error_class([error_message])
337 self._errors['text'] = self.error_class([error_message])
310
338
@@ -361,9 +389,6 b' class PostForm(NeboardForm):'
361 def _validate_hash(self, timestamp: str, iteration: str, guess: str, message: str):
389 def _validate_hash(self, timestamp: str, iteration: str, guess: str, message: str):
362 post_time = timezone.datetime.fromtimestamp(
390 post_time = timezone.datetime.fromtimestamp(
363 int(timestamp[:-3]), tz=timezone.get_current_timezone())
391 int(timestamp[:-3]), tz=timezone.get_current_timezone())
364 timedelta = (timezone.now() - post_time).seconds / 60
365 if timedelta > POW_LIFE_MINUTES:
366 self._errors['text'] = self.error_class([_('Stale PoW.')])
367
392
368 payload = timestamp + message.replace('\r\n', '\n')
393 payload = timestamp + message.replace('\r\n', '\n')
369 difficulty = board_settings.get_int('Forms', 'PowDifficulty')
394 difficulty = board_settings.get_int('Forms', 'PowDifficulty')
@@ -378,6 +403,7 b' class PostForm(NeboardForm):'
378 [_('Invalid PoW.')])
403 [_('Invalid PoW.')])
379
404
380
405
406
381 class ThreadForm(PostForm):
407 class ThreadForm(PostForm):
382
408
383 tags = forms.CharField(
409 tags = forms.CharField(
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -529,4 +529,16 b' msgid "Remove from favorites"'
529 msgstr "Убрать из избранного"
529 msgstr "Убрать из избранного"
530
530
531 msgid "Monochrome"
531 msgid "Monochrome"
532 msgstr "Монохромный" No newline at end of file
532 msgstr "Монохромный"
533
534 msgid "Subsections: "
535 msgstr "Подразделы: "
536
537 msgid "Change file source"
538 msgstr "Изменить источник файла"
539
540 msgid "interesting"
541 msgstr "интересное"
542
543 msgid "images"
544 msgstr "изображения"
@@ -1,6 +1,7 b''
1 # coding=utf-8
1 # coding=utf-8
2
2
3 import re
3 import re
4 import random
4 import bbcode
5 import bbcode
5
6
6 from urllib.parse import unquote
7 from urllib.parse import unquote
@@ -19,6 +20,9 b" MULTI_NEWLINES_PATTERN = re.compile(r'(\\"
19 ONE_NEWLINE = '\n'
20 ONE_NEWLINE = '\n'
20 REGEX_URL = re.compile(r'https?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?')
21 REGEX_URL = re.compile(r'https?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?')
21 LINE_BREAK_HTML = '<div class="br"></div>'
22 LINE_BREAK_HTML = '<div class="br"></div>'
23 SPOILER_SPACE = '&nbsp;'
24
25 MAX_SPOILER_MULTIPLIER = 2
22
26
23
27
24 class TextFormatter():
28 class TextFormatter():
@@ -67,13 +71,6 b' class SpoilerPattern(TextFormatter):'
67 format_left = '[spoiler]'
71 format_left = '[spoiler]'
68 format_right = '[/spoiler]'
72 format_right = '[/spoiler]'
69
73
70 def handleMatch(self, m):
71 quote_element = etree.Element('span')
72 quote_element.set('class', 'spoiler')
73 quote_element.text = m.group(2)
74
75 return quote_element
76
77
74
78 class CommentPattern(TextFormatter):
75 class CommentPattern(TextFormatter):
79 name = ''
76 name = ''
@@ -173,6 +170,17 b' def render_tag(tag_name, value, options,'
173 return url
170 return url
174
171
175
172
173 def render_spoiler(tag_name, value, options, parent, context):
174 text_len = len(value)
175 space_count = random.randint(0, text_len * MAX_SPOILER_MULTIPLIER)
176 side_spaces = SPOILER_SPACE * (space_count // 2)
177 return '<span class="spoiler">{}{}{}</span>'.format(side_spaces, value,
178 side_spaces)
179
180 return quote_element
181
182
183
176 formatters = [
184 formatters = [
177 QuotePattern,
185 QuotePattern,
178 SpoilerPattern,
186 SpoilerPattern,
@@ -202,11 +210,10 b' class Parser:'
202 self.parser.add_formatter('quote', render_quote, strip=True)
210 self.parser.add_formatter('quote', render_quote, strip=True)
203 self.parser.add_formatter('user', render_notification, strip=True)
211 self.parser.add_formatter('user', render_notification, strip=True)
204 self.parser.add_formatter('tag', render_tag, strip=True)
212 self.parser.add_formatter('tag', render_tag, strip=True)
213 self.parser.add_formatter('spoiler', render_spoiler, strip=True)
205 self.parser.add_simple_formatter(
214 self.parser.add_simple_formatter(
206 'comment', '<span class="comment">//%(value)s</span>')
215 'comment', '<span class="comment">//%(value)s</span>')
207 self.parser.add_simple_formatter(
216 self.parser.add_simple_formatter(
208 'spoiler', '<span class="spoiler">%(value)s</span>')
209 self.parser.add_simple_formatter(
210 's', '<span class="strikethrough">%(value)s</span>')
217 's', '<span class="strikethrough">%(value)s</span>')
211 # TODO Why not use built-in tag?
218 # TODO Why not use built-in tag?
212 self.parser.add_simple_formatter('code',
219 self.parser.add_simple_formatter('code',
@@ -230,3 +237,8 b' class Parser:'
230
237
231 def parse(self, text):
238 def parse(self, text):
232 return self.parser.format(text)
239 return self.parser.format(text)
240
241
242 parser = Parser()
243 def get_parser():
244 return parser
@@ -17,7 +17,7 b" HEADER_CONTENT_TYPE = 'content-type'"
17
17
18 FILE_DOWNLOAD_CHUNK_BYTES = 200000
18 FILE_DOWNLOAD_CHUNK_BYTES = 200000
19
19
20 YOUTUBE_URL = re.compile(r'https?://(www\.youtube\.com/watch\?v=|youtu.be/)\w+')
20 YOUTUBE_URL = re.compile(r'https?://((www\.)?youtube\.com/watch\?v=|youtu.be/)\w+')
21
21
22
22
23 class Downloader:
23 class Downloader:
@@ -67,3 +67,4 b' class YouTubeDownloader(Downloader):'
67 @staticmethod
67 @staticmethod
68 def handles(url: str) -> bool:
68 def handles(url: str) -> bool:
69 return YOUTUBE_URL.match(url)
69 return YOUTUBE_URL.match(url)
70
@@ -7,6 +7,7 b' FILE_TYPES_VIDEO = ('
7 'webm',
7 'webm',
8 'mp4',
8 'mp4',
9 'mpeg',
9 'mpeg',
10 'ogv',
10 )
11 )
11 FILE_TYPE_SVG = 'svg'
12 FILE_TYPE_SVG = 'svg'
12 FILE_TYPES_AUDIO = (
13 FILE_TYPES_AUDIO = (
@@ -56,6 +56,7 b' class PostImage(models.Model, Viewable):'
56 preview_width_field='pre_width',
56 preview_width_field='pre_width',
57 preview_height_field='pre_height')
57 preview_height_field='pre_height')
58 hash = models.CharField(max_length=HASH_LENGTH)
58 hash = models.CharField(max_length=HASH_LENGTH)
59 alias = models.TextField(unique=True, null=True, blank=True)
59
60
60 def save(self, *args, **kwargs):
61 def save(self, *args, **kwargs):
61 """
62 """
@@ -12,7 +12,7 b' from django.utils import timezone'
12
12
13 from boards import settings
13 from boards import settings
14 from boards.abstracts.tripcode import Tripcode
14 from boards.abstracts.tripcode import Tripcode
15 from boards.mdx_neboard import Parser
15 from boards.mdx_neboard import get_parser
16 from boards.models import PostImage, Attachment, KeyPair, GlobalId
16 from boards.models import PostImage, Attachment, KeyPair, GlobalId
17 from boards.models.base import Viewable
17 from boards.models.base import Viewable
18 from boards.models.post.export import get_exporter, DIFF_TYPE_JSON
18 from boards.models.post.export import get_exporter, DIFF_TYPE_JSON
@@ -60,6 +60,7 b' POST_VIEW_PARAMS = ('
60 'truncated',
60 'truncated',
61 'mode_tree',
61 'mode_tree',
62 'perms',
62 'perms',
63 'tree_depth',
63 )
64 )
64
65
65
66
@@ -169,6 +170,8 b' class Post(models.Model, Viewable):'
169 def get_thread(self):
170 def get_thread(self):
170 return self.thread
171 return self.thread
171
172
173 def get_thread_id(self):
174 return self.thread_id
172 def get_threads(self) -> QuerySet:
175 def get_threads(self) -> QuerySet:
173 """
176 """
174 Gets post's thread.
177 Gets post's thread.
@@ -337,8 +340,6 b' class Post(models.Model, Viewable):'
337 update_fields=None):
340 update_fields=None):
338 new_post = self.id is None
341 new_post = self.id is None
339
342
340 self._text_rendered = Parser().parse(self.get_raw_text())
341
342 self.uid = str(uuid.uuid4())
343 self.uid = str(uuid.uuid4())
343 if update_fields is not None and 'uid' not in update_fields:
344 if update_fields is not None and 'uid' not in update_fields:
344 update_fields += ['uid']
345 update_fields += ['uid']
@@ -354,9 +355,6 b' class Post(models.Model, Viewable):'
354 if self.url is None:
355 if self.url is None:
355 self.build_url()
356 self.build_url()
356
357
357 self._connect_replies()
358 self._connect_notifications()
359
360 def get_text(self) -> str:
358 def get_text(self) -> str:
361 return self._text_rendered
359 return self._text_rendered
362
360
@@ -391,28 +389,6 b' class Post(models.Model, Viewable):'
391 else:
389 else:
392 return str(self.id)
390 return str(self.id)
393
391
394 def _connect_notifications(self):
395 for reply_number in re.finditer(REGEX_NOTIFICATION, self.get_raw_text()):
396 user_name = reply_number.group(1).lower()
397 Notification.objects.get_or_create(name=user_name, post=self)
398
399 def _connect_replies(self):
400 """
401 Connects replies to a post to show them as a reflink map
402 """
403
404 for reply_number in re.finditer(REGEX_REPLY, self.get_raw_text()):
405 post_id = reply_number.group(1)
406
407 try:
408 referenced_post = Post.objects.get(id=post_id)
409
410 referenced_post.referenced_posts.add(self)
411 referenced_post.last_edit_time = self.pub_time
412 referenced_post.build_refmap()
413 referenced_post.save(update_fields=['refmap', 'last_edit_time'])
414 except ObjectDoesNotExist:
415 pass
416
392
417 def connect_threads(self, opening_posts):
393 def connect_threads(self, opening_posts):
418 for opening_post in opening_posts:
394 for opening_post in opening_posts:
@@ -445,3 +421,32 b' class Post(models.Model, Viewable):'
445
421
446 def set_hidden(self, hidden):
422 def set_hidden(self, hidden):
447 self.hidden = hidden
423 self.hidden = hidden
424
425
426 # SIGNALS (Maybe move to other module?)
427 @receiver(post_save, sender=Post)
428 def connect_replies(instance, **kwargs):
429 for reply_number in re.finditer(REGEX_REPLY, instance.get_raw_text()):
430 post_id = reply_number.group(1)
431
432 try:
433 referenced_post = Post.objects.get(id=post_id)
434
435 referenced_post.referenced_posts.add(instance)
436 referenced_post.last_edit_time = instance.pub_time
437 referenced_post.build_refmap()
438 referenced_post.save(update_fields=['refmap', 'last_edit_time'])
439 except ObjectDoesNotExist:
440 pass
441
442
443 @receiver(post_save, sender=Post)
444 def connect_notifications(instance, **kwargs):
445 for reply_number in re.finditer(REGEX_NOTIFICATION, instance.get_raw_text()):
446 user_name = reply_number.group(1).lower()
447 Notification.objects.get_or_create(name=user_name, post=instance)
448
449
450 @receiver(pre_save, sender=Post)
451 def preparse_text(instance, **kwargs):
452 instance._text_rendered = get_parser().parse(instance.get_raw_text())
@@ -31,11 +31,14 b' class PostManager(models.Manager):'
31 @transaction.atomic
31 @transaction.atomic
32 def create_post(self, title: str, text: str, file=None, thread=None,
32 def create_post(self, title: str, text: str, file=None, thread=None,
33 ip=NO_IP, tags: list=None, opening_posts: list=None,
33 ip=NO_IP, tags: list=None, opening_posts: list=None,
34 tripcode='', monochrome=False):
34 tripcode='', monochrome=False, images=[]):
35 """
35 """
36 Creates new post
36 Creates new post
37 """
37 """
38
38
39 if thread is not None and thread.is_archived():
40 raise Exception('Cannot post into an archived thread')
41
39 if not utils.is_anonymous_mode():
42 if not utils.is_anonymous_mode():
40 is_banned = Ban.objects.filter(ip=ip).exists()
43 is_banned = Ban.objects.filter(ip=ip).exists()
41 else:
44 else:
@@ -84,6 +87,8 b' class PostManager(models.Manager):'
84 post.images.add(PostImage.objects.create_with_hash(file))
87 post.images.add(PostImage.objects.create_with_hash(file))
85 else:
88 else:
86 post.attachments.add(Attachment.objects.create_with_hash(file))
89 post.attachments.add(Attachment.objects.create_with_hash(file))
90 for image in images:
91 post.images.add(image)
87
92
88 post.connect_threads(opening_posts)
93 post.connect_threads(opening_posts)
89 post.set_global_id()
94 post.set_global_id()
@@ -3,7 +3,7 b' from adjacent import Client'
3
3
4 from django.db.models import Count, Sum, QuerySet, Q
4 from django.db.models import Count, Sum, QuerySet, Q
5 from django.utils import timezone
5 from django.utils import timezone
6 from django.db import models
6 from django.db import models, transaction
7
7
8 from boards.models import STATUS_BUMPLIMIT, STATUS_ACTIVE, STATUS_ARCHIVE
8 from boards.models import STATUS_BUMPLIMIT, STATUS_ACTIVE, STATUS_ARCHIVE
9
9
@@ -68,7 +68,7 b' class ThreadManager(models.Manager):'
68 # TODO Use classes instead of dicts
68 # TODO Use classes instead of dicts
69 for data in datas:
69 for data in datas:
70 if data['last_id'] != FAV_THREAD_NO_UPDATES:
70 if data['last_id'] != FAV_THREAD_NO_UPDATES:
71 q = (Q(id=data['op'].get_thread().id)
71 q = (Q(id=data['op'].get_thread_id())
72 & Q(multi_replies__id__gt=data['last_id']))
72 & Q(multi_replies__id__gt=data['last_id']))
73 if query is None:
73 if query is None:
74 query = q
74 query = q
@@ -270,3 +270,53 b' class Thread(models.Model):'
270
270
271 def is_monochrome(self):
271 def is_monochrome(self):
272 return self.monochrome
272 return self.monochrome
273
274 # If tags have parent, add them to the tag list
275 @transaction.atomic
276 def refresh_tags(self):
277 for tag in self.get_tags().all():
278 parents = tag.get_all_parents()
279 if len(parents) > 0:
280 self.tags.add(*parents)
281
282 def get_reply_tree(self):
283 replies = self.get_replies().prefetch_related('refposts')
284 tree = []
285 for reply in replies:
286 parents = reply.refposts.all()
287
288 found_parent = False
289 searching_for_index = False
290
291 if len(parents) > 0:
292 index = 0
293 parent_depth = 0
294
295 indexes_to_insert = []
296
297 for depth, element in tree:
298 index += 1
299
300 # If this element is next after parent on the same level,
301 # insert child before it
302 if searching_for_index and depth <= parent_depth:
303 indexes_to_insert.append((index - 1, parent_depth))
304 searching_for_index = False
305
306 if element in parents:
307 found_parent = True
308 searching_for_index = True
309 parent_depth = depth
310
311 if not found_parent:
312 tree.append((0, reply))
313 else:
314 if searching_for_index:
315 tree.append((parent_depth + 1, reply))
316
317 offset = 0
318 for last_index, parent_depth in indexes_to_insert:
319 tree.insert(last_index + offset, (parent_depth + 1, reply))
320 offset += 1
321
322 return tree
@@ -141,10 +141,6 b' textarea, input {'
141 margin: 1ex;
141 margin: 1ex;
142 }
142 }
143
143
144 #new-fav-post-count {
145 display: none;
146 }
147
148 .hidden_post {
144 .hidden_post {
149 opacity: 0.2;
145 opacity: 0.2;
150 }
146 }
@@ -157,3 +153,4 b' textarea, input {'
157 filter: grayscale(100%);
153 filter: grayscale(100%);
158 -webkit-filter: grayscale(100%);
154 -webkit-filter: grayscale(100%);
159 }
155 }
156
@@ -121,6 +121,7 b' body {'
121
121
122 .tag_info > .tag-text-data {
122 .tag_info > .tag-text-data {
123 text-align: left;
123 text-align: left;
124 max-width: 30em;
124 }
125 }
125
126
126 .header {
127 .header {
@@ -280,7 +281,6 b' blockquote {'
280 .spoiler {
281 .spoiler {
281 background: black;
282 background: black;
282 color: black;
283 color: black;
283 padding: 0 1ex 0 1ex;
284 }
284 }
285
285
286 .spoiler:hover {
286 .spoiler:hover {
@@ -1,3 +1,5 b''
1 var ITEM_FILE_SOURCE = 'fileSource';
2
1 $('input[name=image]').wrap($('<div class="file_wrap"></div>'));
3 $('input[name=image]').wrap($('<div class="file_wrap"></div>'));
2
4
3 $('body').on('change', 'input[name=image]', function(event) {
5 $('body').on('change', 'input[name=image]', function(event) {
@@ -60,36 +62,75 b' function addHiddenInput(form, name, valu'
60 form.find('input[name=' + name + ']').val(value);
62 form.find('input[name=' + name + ']').val(value);
61 }
63 }
62
64
65 function selectFileChoice() {
66 var file_input = $('#id_file');
67 var url_input = $('#id_file_url');
68
69 var file_input_row = file_input.parent().parent();
70 var url_input_row = url_input.parent().parent();
71
72 file_input_row.toggle();
73 url_input_row.toggle();
74 url_input.val('');
75 file_input.val('');
76
77 var source;
78 if (file_input_row.is(':visible')) {
79 source = 'file';
80 } else {
81 source = 'url';
82 }
83 localStorage.setItem(ITEM_FILE_SOURCE, source);
84 }
85
63 $(document).ready(function() {
86 $(document).ready(function() {
64 var powDifficulty = parseInt($('body').attr('data-pow-difficulty'));
87 var powDifficulty = parseInt($('body').attr('data-pow-difficulty'));
65 if (powDifficulty > 0) {
88 if (powDifficulty > 0 && typeof SharedWorker != 'undefined') {
66 var worker = new Worker($('#powScript').attr('src'));
89 var worker = new SharedWorker($('.post-form').attr('data-pow-script'));
67 worker.onmessage = function(e) {
90 worker.port.onmessage = function(e) {
68 var form = $('#form');
91 var form = $('#form');
69 addHiddenInput(form, 'timestamp', e.data.timestamp);
92 addHiddenInput(form, 'timestamp', e.data.timestamp);
70 addHiddenInput(form, 'iteration', e.data.iteration);
93 addHiddenInput(form, 'iteration', e.data.iteration);
71 addHiddenInput(form, 'guess', e.data.guess);
94 addHiddenInput(form, 'guess', e.data.guess);
72
95
73 form.submit();
96 form.submit();
74 form.find('input[type=submit]').toggle();
97 $('.post-form-w').unblock();
75 };
98 };
99 worker.onerror = function(event){
100 throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
101 };
102 worker.port.start();
76
103
77 var form = $('#form');
104 var form = $('#form');
78 var submitButton = form.find('input[type=submit]');
105 var submitButton = form.find('input[type=submit]');
79 submitButton.click(function() {
106 submitButton.click(function() {
80 showAsErrors(form, gettext('Computing PoW...'));
107 showAsErrors(form, gettext('Computing PoW...'));
81 submitButton.toggle();
108 $('.post-form-w').block({ message: gettext('Computing PoW...') })
82
109
83 var msg = $('textarea').val().trim();
110 var msg = $('textarea').val().trim();
84
111
85 var data = {
112 var data = {
86 msg: msg,
113 msg: msg,
87 difficulty: parseInt($('body').attr('data-pow-difficulty')),
114 difficulty: parseInt($('body').attr('data-pow-difficulty')),
88 hasher: $('#sha256Script').attr('src')
115 hasher: $('.post-form').attr('data-hasher')
89 };
116 };
90 worker.postMessage(data);
117 worker.port.postMessage(data);
91
118
92 return false;
119 return false;
93 });
120 });
94 }
121 }
122
123 var source = localStorage.getItem(ITEM_FILE_SOURCE);
124 if (source == null) {
125 source = 'file';
126 }
127 if (source == 'file') {
128 $('#id_file_url').parent().parent().hide();
129 } else {
130 $('#id_file').parent().parent().hide();
131 }
132
133 $('#file-source-button').click(function() {
134 selectFileChoice();
135 });
95 });
136 });
@@ -147,39 +147,42 b' PopupImageViewer.prototype.view = functi'
147 'width': img_w,
147 'width': img_w,
148 'height': img_h,
148 'height': img_h,
149 'left': (win_w - img_w) / 2,
149 'left': (win_w - img_w) / 2,
150 'top': ((win_h - img_h) / 2)
150 'top': ((win_h - img_h) / 2),
151 'position': 'fixed' // Chrome fix because it adds a 'relative' value to the image somehow
151 })
152 })
152 .appendTo(postNode)
153 //scaling preview
153 //scaling preview
154 .mousewheel(function(event, delta) {
154 .mousewheel(function(event, delta) {
155 var cx = event.originalEvent.clientX;
155 var cx = event.originalEvent.clientX;
156 var cy = event.originalEvent.clientY;
156 var cy = event.originalEvent.clientY;
157
157
158 var scale = newImage.attr(ATTR_SCALE) / (delta > 0 ? 1.25 : 0.8);
158 var scale = newImage.attr(ATTR_SCALE) / (delta > 0 ? 1.25 : 0.8);
159
159
160 var oldWidth = newImage.width();
160 var oldWidth = newImage.width();
161 var oldHeight = newImage.height();
161 var oldHeight = newImage.height();
162
162
163 var newIW = full_img_w / scale;
163 var newIW = full_img_w / scale;
164 var newIH = full_img_h / scale;
164 var newIH = full_img_h / scale;
165
165
166 newImage.width(newIW);
166 newImage.width(newIW);
167 newImage.height(newIH);
167 newImage.height(newIH);
168 newImage.attr(ATTR_SCALE, scale);
168 newImage.attr(ATTR_SCALE, scale);
169
169
170 // Set position
170 // Set position
171 var oldPosition = newImage.position();
171 var oldPosition = newImage.position();
172 newImage.css({
172 newImage.css({
173 left: parseInt(cx - (newIW/oldWidth) * (cx - parseInt(oldPosition.left, 10)), 10),
173 left: parseInt(cx - (newIW/oldWidth) * (cx - parseInt(oldPosition.left, 10)), 10),
174 top: parseInt(cy - (newIH/oldHeight) * (cy - parseInt(oldPosition.top, 10)), 10)
174 top: parseInt(cy - (newIH/oldHeight) * (cy - parseInt(oldPosition.top, 10)), 10)
175 });
175 });
176
176
177 return false;
177 return false;
178 }
178 })
179 )
180 .draggable({
179 .draggable({
181 addClasses: false,
180 addClasses: false,
182 stack: '.img-full'
181 stack: '.img-full'
182 })
183 .appendTo($('body'));
184 newImage.click(function() {
185 $(this).remove();
183 });
186 });
184 } else {
187 } else {
185 existingPopups.remove();
188 existingPopups.remove();
@@ -23,7 +23,6 b''
23 for the JavaScript code in this page.
23 for the JavaScript code in this page.
24 */
24 */
25
25
26 var FAV_POST_UPDATE_PERIOD = 10000;
27 var ITEM_VOLUME_LEVEL = 'volumeLevel';
26 var ITEM_VOLUME_LEVEL = 'volumeLevel';
28
27
29 /**
28 /**
@@ -43,60 +42,62 b' function highlightCode(node) {'
43 });
42 });
44 }
43 }
45
44
46 function updateFavPosts() {
45 function updateFavPosts(data) {
47 var includePostBody = $('#fav-panel').is(":visible");
46 var includePostBody = $('#fav-panel').is(":visible");
48 var url = '/api/new_posts/';
47
48 var allNewPostCount = 0;
49
49 if (includePostBody) {
50 if (includePostBody) {
50 url += '?include_posts'
51 var favoriteThreadPanel = $('#fav-panel');
52 favoriteThreadPanel.empty();
51 }
53 }
52 $.getJSON(url,
54
53 function(data) {
55 $.each($.parseJSON(data), function (_, dict) {
54 var allNewPostCount = 0;
56 var newPostCount = dict.new_post_count;
57 allNewPostCount += newPostCount;
55
58
56 if (includePostBody) {
59 if (includePostBody) {
57 var favoriteThreadPanel = $('#fav-panel');
60 var favThreadNode = $('<div class="post"></div>');
58 favoriteThreadPanel.empty();
61 favThreadNode.append($(dict.post_url));
62 favThreadNode.append(' ');
63 favThreadNode.append($('<span class="title">' + dict.title + '</span>'));
64
65 if (newPostCount > 0) {
66 favThreadNode.append(' (<a href="' + dict.newest_post_link + '">+' + newPostCount + "</a>)");
59 }
67 }
60
68
61 $.each(data, function (_, dict) {
69 favoriteThreadPanel.append(favThreadNode);
62 var newPostCount = dict.new_post_count;
63 allNewPostCount += newPostCount;
64
70
65 if (includePostBody) {
71 addRefLinkPreview(favThreadNode[0]);
66 var favThreadNode = $('<div class="post"></div>');
72 }
67 favThreadNode.append($(dict.post_url));
73 });
68 favThreadNode.append(' ');
69 favThreadNode.append($('<span class="title">' + dict.title + '</span>'));
70
71 if (newPostCount > 0) {
72 favThreadNode.append(' (<a href="' + dict.newest_post_link + '">+' + newPostCount + "</a>)");
73 }
74
74
75 favoriteThreadPanel.append(favThreadNode);
75 var newPostCountNode = $('#new-fav-post-count');
76
76 if (allNewPostCount > 0) {
77 addRefLinkPreview(favThreadNode[0]);
77 newPostCountNode.text('(+' + allNewPostCount + ')');
78 }
78 newPostCountNode.show();
79 });
79 } else {
80
80 newPostCountNode.hide();
81 var newPostCountNode = $('#new-fav-post-count');
81 }
82 if (allNewPostCount > 0) {
83 newPostCountNode.text('(+' + allNewPostCount + ')');
84 newPostCountNode.show();
85 } else {
86 newPostCountNode.hide();
87 }
88 }
89 );
90 }
82 }
91
83
92 function initFavPanel() {
84 function initFavPanel() {
93 updateFavPosts();
85 var favPanelButton = $('#fav-panel-btn');
86 if (favPanelButton.length > 0 && typeof SharedWorker != 'undefined') {
87 var worker = new SharedWorker($('body').attr('data-update-script'));
88 worker.port.onmessage = function(e) {
89 updateFavPosts(e.data);
90 };
91 worker.onerror = function(event){
92 throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
93 };
94 worker.port.start();
94
95
95 if ($('#fav-panel-btn').length > 0) {
96 $(favPanelButton).click(function() {
96 setInterval(updateFavPosts, FAV_POST_UPDATE_PERIOD);
97 var favPanel = $('#fav-panel');
97 $('#fav-panel-btn').click(function() {
98 favPanel.toggle();
98 $('#fav-panel').toggle();
99
99 updateFavPosts();
100 worker.port.postMessage({ includePostBody: favPanel.is(':visible')});
100
101
101 return false;
102 return false;
102 });
103 });
@@ -1,8 +1,10 b''
1 var POW_COMPUTING_TIMEOUT = 2;
1 var POW_COMPUTING_TIMEOUT = 2;
2 var POW_HASH_LENGTH = 16;
2 var POW_HASH_LENGTH = 16;
3
3
4 var hasher = null;
4
5
5 function computeHash(iteration, guess, target, payload, timestamp, hasher) {
6
7 function computeHash(iteration, guess, target, payload, timestamp, port) {
6 iteration += 1;
8 iteration += 1;
7 var hash = hasher(payload + iteration).toString();
9 var hash = hasher(payload + iteration).toString();
8 guess = hash.substring(0, POW_HASH_LENGTH);
10 guess = hash.substring(0, POW_HASH_LENGTH);
@@ -17,19 +19,19 b' function computeHash(iteration, guess, t'
17 timestamp: timestamp,
19 timestamp: timestamp,
18 guess: guess
20 guess: guess
19 };
21 };
20 self.postMessage(data);
22 port.postMessage(data);
21 } else {
23 } else {
22 //console.log("Iteration: ", iteration);
24 //console.log("Iteration: ", iteration);
23 //console.log("Guess: ", guess);
25 //console.log("Guess: ", guess);
24 //console.log("Target: ", target);
26 //console.log("Target: ", target);
25
27
26 setTimeout(function() {
28 setTimeout(function() {
27 computeHash(iteration, guess, target, payload, timestamp, hasher);
29 computeHash(iteration, guess, target, payload, timestamp, port);
28 }, POW_COMPUTING_TIMEOUT);
30 }, POW_COMPUTING_TIMEOUT);
29 }
31 }
30 }
32 }
31
33
32 function doWork(message, hasher, difficulty) {
34 function doWork(message, difficulty, port) {
33 var timestamp = Date.now();
35 var timestamp = Date.now();
34 var iteration = 0;
36 var iteration = 0;
35 var payload = timestamp + message;
37 var payload = timestamp + message;
@@ -42,13 +44,23 b' function doWork(message, hasher, difficu'
42 var guess = target + '0';
44 var guess = target + '0';
43
45
44 setTimeout(function() {
46 setTimeout(function() {
45 computeHash(iteration, guess, target, payload, timestamp, hasher);
47 computeHash(iteration, guess, target, payload, timestamp, port);
46 }, POW_COMPUTING_TIMEOUT);
48 }, POW_COMPUTING_TIMEOUT);
47 }
49 }
48
50
49 self.onmessage = function(e) {
51 onconnect = function(e) {
50 var difficulty = e.data.difficulty;
52 var port = e.ports[0];
51 importScripts(e.data.hasher);
53 port.start();
52 var hasher = CryptoJS.SHA256;
54
53 self.doWork(e.data.msg, hasher, difficulty);
55 port.onmessage = function(e) {
54 };
56 var difficulty = e.data.difficulty;
57
58 if (hasher == null) {
59 importScripts(e.data.hasher);
60 hasher = CryptoJS.SHA256;
61 }
62
63 self.doWork(e.data.msg, difficulty, port);
64 };
65 }
66
@@ -1,3 +1,7 b''
1 var LOADING_MSG = "<div class=\"post\">" + gettext('Loading...') + "</div>";
2
3 var CLS_PREVIEW = 'post_preview';
4
1 function $X(path, root) {
5 function $X(path, root) {
2 return document.evaluate(path, root || document, null, 6, null);
6 return document.evaluate(path, root || document, null, 6, null);
3 }
7 }
@@ -46,8 +50,9 b' function addRefLinkPreview(node) {'
46
50
47 function showPostPreview(e) {
51 function showPostPreview(e) {
48 var doc = document;
52 var doc = document;
49 //ref id
53
50 var pNum = $(this).text().match(/\d+/);
54 var reflink = $(this);
55 var pNum = reflink.text().match(/\d+/);
51
56
52 if (pNum == null || pNum.length == 0) {
57 if (pNum == null || pNum.length == 0) {
53 return;
58 return;
@@ -55,40 +60,44 b' function showPostPreview(e) {'
55
60
56 var post = $('#' + pNum);
61 var post = $('#' + pNum);
57 if (post.length > 0 && isElementInViewport(post)) {
62 if (post.length > 0 && isElementInViewport(post)) {
63 // If post is on the same page and visible, just highlight it
58 post.addClass('highlight');
64 post.addClass('highlight');
59 } else {
65 } else {
60 var x = e.clientX + (doc.documentElement.scrollLeft || doc.body.scrollLeft) + 2;
66 var x = reflink.offset().left;
61 var y = e.clientY + (doc.documentElement.scrollTop || doc.body.scrollTop);
67 var y = reflink.offset().top;
62
68
63 var cln = doc.createElement('div');
69 var cln = doc.createElement('div');
64 cln.id = 'pstprev_' + pNum;
70 cln.id = 'pstprev_' + pNum;
65 cln.className = 'post_preview';
71 cln.className = CLS_PREVIEW;
66
72
67 cln.style.cssText = 'top:' + y + 'px;' + (x < doc.body.clientWidth/2 ? 'left:' + x + 'px' : 'right:' + parseInt(doc.body.clientWidth - x + 1) + 'px');
73 cln.style.cssText = 'left:' + x + 'px; top:' + y + 'px';
68
74
69 cln.addEventListener('mouseout', delPostPreview, false);
75 cln.addEventListener('mouseout', delPostPreview, false);
70
76
71 cln.innerHTML = "<div class=\"post\">" + gettext('Loading...') + "</div>";
77 cln.innerHTML = LOADING_MSG;
72
78
73 if(post.length > 0) {
79 if (post.length > 0) {
74 var postdata = post.clone().wrap("<div/>").parent().html();
80 // If post is on the same page but not visible, generate preview from it
81 var postClone = post.clone();
82 postClone.removeAttr('style');
83 var postdata = postClone.wrap("<div/>").parent().html();
75
84
76 mkPreview(cln, postdata);
85 mkPreview(cln, postdata);
77 } else {
86 } else {
87 // If post is from other page, load it
78 $.ajax({
88 $.ajax({
79 url: '/api/post/' + pNum + '/?truncated'
89 url: '/api/post/' + pNum + '/?truncated'
80 })
90 })
81 .success(function(data) {
91 .success(function(data) {
82 var postdata = $(data).wrap("<div/>").parent().html();
92 var postdata = $(data).wrap("<div/>").parent().html();
83
84 //make preview
85 mkPreview(cln, postdata);
86
93
87 })
94 //make preview
88 .error(function() {
95 mkPreview(cln, postdata);
89 cln.innerHTML = "<div class=\"post\">"
96 })
90 + gettext('Post not found') + "</div>";
97 .error(function() {
91 });
98 cln.innerHTML = "<div class=\"post\">"
99 + gettext('Post not found') + "</div>";
100 });
92 }
101 }
93
102
94 $del(doc.getElementById(cln.id));
103 $del(doc.getElementById(cln.id));
@@ -106,7 +115,13 b' function delPostPreview(e) {'
106 $del(clone)
115 $del(clone)
107 });
116 });
108 } else {
117 } else {
109 while(el.nextSibling) $del(el.nextSibling);
118 while (el.nextSibling) {
119 if (el.nextSibling.className == CLS_PREVIEW) {
120 $del(el.nextSibling);
121 } else {
122 break;
123 }
124 }
110 }
125 }
111
126
112 $('.highlight').removeClass('highlight');
127 $('.highlight').removeClass('highlight');
@@ -295,9 +295,11 b' function showNewPostsTitle(newPostCount)'
295 }
295 }
296 unreadPosts = unreadPosts + newPostCount;
296 unreadPosts = unreadPosts + newPostCount;
297
297
298 var newTitle = '* ';
298 var newTitle = null;
299 if (unreadPosts > 0) {
299 if (unreadPosts > 0) {
300 newTitle += '[' + unreadPosts + '] ';
300 newTitle = '[' + unreadPosts + '] ';
301 } else {
302 newTitle = '* ';
301 }
303 }
302 newTitle += documentOriginalTitle;
304 newTitle += documentOriginalTitle;
303
305
@@ -98,6 +98,14 b''
98 {{ tag.get_view|safe }}
98 {{ tag.get_view|safe }}
99 </p>
99 </p>
100 {% endif %}
100 {% endif %}
101 {% if tag.get_children.all %}
102 <p>
103 {% trans "Subsections: " %}
104 {% for child in tag.get_children.all %}
105 {{ child.get_view|safe }}{% if not forloop.last%}, {% endif %}
106 {% endfor %}
107 </p>
108 {% endif %}
101 </div>
109 </div>
102 </div>
110 </div>
103 {% endif %}
111 {% endif %}
@@ -147,7 +155,8 b''
147
155
148 <div class="post-form-w">
156 <div class="post-form-w">
149 <script src="{% static 'js/panel.js' %}"></script>
157 <script src="{% static 'js/panel.js' %}"></script>
150 <div class="post-form">
158 <div class="post-form" data-hasher="{% static 'js/3party/sha256.js' %}"
159 data-pow-script="{% static 'js/proof_of_work.js' %}">
151 <div class="form-title">{% trans "Create new thread" %}</div>
160 <div class="form-title">{% trans "Create new thread" %}</div>
152 <div class="swappable-form-full">
161 <div class="swappable-form-full">
153 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
162 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
@@ -155,6 +164,7 b''
155 <div class="form-submit">
164 <div class="form-submit">
156 <input type="submit" value="{% trans "Post" %}"/>
165 <input type="submit" value="{% trans "Post" %}"/>
157 <button id="preview-button" onclick="return false;">{% trans 'Preview' %}</button>
166 <button id="preview-button" onclick="return false;">{% trans 'Preview' %}</button>
167 <button id="file-source-button" onclick="return false;">{% trans 'Change file source' %}</button>
158 </div>
168 </div>
159 </form>
169 </form>
160 </div>
170 </div>
@@ -171,8 +181,7 b''
171 </div>
181 </div>
172
182
173 <script src="{% static 'js/form.js' %}"></script>
183 <script src="{% static 'js/form.js' %}"></script>
174 <script id="sha256Script" src="{% static 'js/3party/sha256.js' %}"></script>
184 <script src="{% static 'js/3party/jquery.blockUI.js' %}"></script>
175 <script id="powScript" src="{% static 'js/proof_of_work.js' %}"></script>
176 <script src="{% static 'js/thread_create.js' %}"></script>
185 <script src="{% static 'js/thread_create.js' %}"></script>
177
186
178 {% endblock %}
187 {% endblock %}
@@ -192,8 +201,7 b''
192 {% ifequal page current_page.number %}
201 {% ifequal page current_page.number %}
193 class="current_page"
202 class="current_page"
194 {% endifequal %}
203 {% endifequal %}
195 href="{% page_url paginator page %}">{{ page }}</a>
204 href="{% page_url paginator page %}">{{ page }}</a>{% if not forloop.last %},{% endif %}
196 {% if not forloop.last %},{% endif %}
197 {% endfor %}
205 {% endfor %}
198 {% endwith %}
206 {% endwith %}
199 ]
207 ]
@@ -23,12 +23,15 b''
23
23
24 {% block head %}{% endblock %}
24 {% block head %}{% endblock %}
25 </head>
25 </head>
26 <body data-image-viewer="{{ image_viewer }}" data-pow-difficulty="{{ pow_difficulty }}">
26 <body data-image-viewer="{{ image_viewer }}"
27 <script src="{% static 'js/jquery-2.0.1.min.js' %}"></script>
27 data-pow-difficulty="{{ pow_difficulty }}"
28 data-update-script="{% static 'js/updates.js' %}">
29 <script src="{% static 'js/jquery-2.2.0.min.js' %}"></script>
28
30
29 <div class="navigation_panel header">
31 <div class="navigation_panel header">
30 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
32 <a class="link" href="{% url 'index' %}">{% trans "All threads" %}</a>
31 {% if tags_str %}
33 {% if tags_str %}
34 <a href="{% url 'index' %}?filter=fav_tags" title="{% trans "interesting" %}"></a>,
32 {% autoescape off %}
35 {% autoescape off %}
33 {{ tags_str }},
36 {{ tags_str }},
34 {% endautoescape %}
37 {% endautoescape %}
@@ -36,11 +39,13 b''
36 {% trans 'Add tags' %} →
39 {% trans 'Add tags' %} →
37 {% endif %}
40 {% endif %}
38 <a href="{% url 'tags' 'required'%}" title="{% trans 'Tag management' %}">{% trans "tags" %}</a>,
41 <a href="{% url 'tags' 'required'%}" title="{% trans 'Tag management' %}">{% trans "tags" %}</a>,
39 <a href="{% url 'search' %}" title="{% trans 'Search' %}">{% trans 'search' %}</a>,
42 {% if search_enabled %}
43 <a href="{% url 'search' %}" title="{% trans 'Search' %}">{% trans 'search' %}</a>,
44 {% endif %}
40 <a href="{% url 'feed' %}" title="{% trans 'Feed' %}">{% trans 'feed' %}</a>,
45 <a href="{% url 'feed' %}" title="{% trans 'Feed' %}">{% trans 'feed' %}</a>,
41 <a href="{% url 'random' %}" title="{% trans 'Random images' %}">{% trans 'random' %}</a>{% if has_fav_threads %},
46 <a href="{% url 'random' %}" title="{% trans 'Random images' %}">{% trans 'images' %}</a>{% if has_fav_threads %},
42
47
43 <a href="#" id="fav-panel-btn">{% trans 'favorites' %} <span id="new-fav-post-count"></span></a>
48 <a href="{% url 'feed' %}?favorites" id="fav-panel-btn">{% trans 'favorites' %} <span id="new-fav-post-count" {% if not new_post_count %}style="display: none" {% endif %}>{{ new_post_count }}</span></a>
44 {% endif %}
49 {% endif %}
45
50
46 {% if usernames %}
51 {% if usernames %}
@@ -61,8 +61,7 b''
61 {% ifequal page current_page.number %}
61 {% ifequal page current_page.number %}
62 class="current_page"
62 class="current_page"
63 {% endifequal %}
63 {% endifequal %}
64 href="{% page_url paginator page %}">{{ page }}</a>
64 href="{% page_url paginator page %}">{{ page }}</a>{% if not forloop.last %},{% endif %}
65 {% if not forloop.last %},{% endif %}
66 {% endfor %}
65 {% endfor %}
67 {% endwith %}
66 {% endwith %}
68 ]
67 ]
@@ -3,7 +3,7 b''
3
3
4 {% get_current_language as LANGUAGE_CODE %}
4 {% get_current_language as LANGUAGE_CODE %}
5
5
6 <div class="{{ css_class }}" id="{{ post.id }}" data-uid="{{ post.uid }}">
6 <div class="{{ css_class }}" id="{{ post.id }}" data-uid="{{ post.uid }}" {% if tree_depth %}style="margin-left: {{ tree_depth }}em;"{% endif %}>
7 <div class="post-info">
7 <div class="post-info">
8 <a class="post_id" href="{{ post.get_absolute_url }}">#{{ post.get_absolute_id }}</a>
8 <a class="post_id" href="{{ post.get_absolute_url }}">#{{ post.get_absolute_id }}</a>
9 <span class="title">{{ post.title }}</span>
9 <span class="title">{{ post.title }}</span>
@@ -86,13 +86,7 b''
86 {% endautoescape %}
86 {% endautoescape %}
87 </div>
87 </div>
88 {% if post.is_referenced %}
88 {% if post.is_referenced %}
89 {% if mode_tree %}
89 {% if not mode_tree %}
90 <div class="tree_reply">
91 {% for refpost in post.get_referenced_posts %}
92 {% post_view refpost mode_tree=True %}
93 {% endfor %}
94 </div>
95 {% else %}
96 <div class="refmap">
90 <div class="refmap">
97 {% trans "Replies" %}: {{ post.refmap|safe }}
91 {% trans "Replies" %}: {{ post.refmap|safe }}
98 </div>
92 </div>
@@ -24,6 +24,10 b''
24 {% else %}
24 {% else %}
25 <p>{% trans 'No hidden tags.' %}</p>
25 <p>{% trans 'No hidden tags.' %}</p>
26 {% endif %}
26 {% endif %}
27
28 {% for image in image_aliases %}
29 {{ image.alias }}: <img src="{{ image.image.url_200x150 }}" /> <br />
30 {% endfor %}
27 </div>
31 </div>
28
32
29 <div class="post-form-w">
33 <div class="post-form-w">
@@ -22,13 +22,13 b''
22 {% with post.get_first_image as image %}
22 {% with post.get_first_image as image %}
23 {% autoescape off %}
23 {% autoescape off %}
24 {{ image.get_view }}
24 {{ image.get_view }}
25 <div class="gallery_image_metadata">
26 {{ image.width }}x{{ image.height }}
27 {% image_actions image.image.url request.get_host %}
28 <br />
29 <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a>
30 </div>
25 {% endautoescape %}
31 {% endautoescape %}
26 <div class="gallery_image_metadata">
27 {{ image.width }}x{{ image.height }}
28 {% image_actions image.image.url request.get_host %}
29 <br />
30 <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a>
31 </div>
32 {% endwith %}
32 {% endwith %}
33 </div>
33 </div>
34 {% endfor %}
34 {% endfor %}
@@ -43,7 +43,8 b''
43 <div class="post-form-w">
43 <div class="post-form-w">
44 <script src="{% static 'js/panel.js' %}"></script>
44 <script src="{% static 'js/panel.js' %}"></script>
45 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post.id }}<span class="reply-to-message"> {% trans "to message " %} #<span id="reply-to-message-id"></span></span></div>
45 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post.id }}<span class="reply-to-message"> {% trans "to message " %} #<span id="reply-to-message-id"></span></span></div>
46 <div class="post-form" id="compact-form">
46 <div class="post-form" id="compact-form" data-hasher="{% static 'js/3party/sha256.js' %}"
47 data-pow-script="{% static 'js/proof_of_work.js' %}">
47 <div class="swappable-form-full">
48 <div class="swappable-form-full">
48 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
49 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
49 <div class="compact-form-text"></div>
50 <div class="compact-form-text"></div>
@@ -51,6 +52,7 b''
51 <div class="form-submit">
52 <div class="form-submit">
52 <input type="submit" value="{% trans "Post" %}"/>
53 <input type="submit" value="{% trans "Post" %}"/>
53 <button id="preview-button" onclick="return false;">{% trans 'Preview' %}</button>
54 <button id="preview-button" onclick="return false;">{% trans 'Preview' %}</button>
55 <button id="file-source-button" onclick="return false;">{% trans 'Change file source' %}</button>
54 </div>
56 </div>
55 </form>
57 </form>
56 </div>
58 </div>
@@ -68,8 +70,7 b''
68
70
69 <script src="{% static 'js/form.js' %}"></script>
71 <script src="{% static 'js/form.js' %}"></script>
70 <script src="{% static 'js/jquery.form.min.js' %}"></script>
72 <script src="{% static 'js/jquery.form.min.js' %}"></script>
71 <script id="sha256Script" src="{% static 'js/3party/sha256.js' %}"></script>
73 <script src="{% static 'js/3party/jquery.blockUI.js' %}"></script>
72 <script id="powScript" src="{% static 'js/proof_of_work.js' %}"></script>
73 <script src="{% static 'js/thread.js' %}"></script>
74 <script src="{% static 'js/thread.js' %}"></script>
74 <script src="{% static 'js/thread_update.js' %}"></script>
75 <script src="{% static 'js/thread_update.js' %}"></script>
75 {% endif %}
76 {% endif %}
@@ -10,8 +10,8 b''
10 {% get_current_timezone as TIME_ZONE %}
10 {% get_current_timezone as TIME_ZONE %}
11
11
12 <div class="thread">
12 <div class="thread">
13 {% for post in thread.get_top_level_replies %}
13 {% for depth, post in thread.get_reply_tree %}
14 {% post_view post mode_tree=True %}
14 {% post_view post mode_tree=True tree_depth=depth%}
15 {% endfor %}
15 {% endfor %}
16 </div>
16 </div>
17
17
@@ -26,7 +26,7 b' class ParserTest(TestCase):'
26 self.assertEqual('[post]12[/post]\nText',
26 self.assertEqual('[post]12[/post]\nText',
27 preparsed_text, 'Reflink not preparsed.')
27 preparsed_text, 'Reflink not preparsed.')
28
28
29 def preparse_user(self):
29 def test_preparse_user(self):
30 raw_text = '@user\nuser@example.com\n@user\nuser @user'
30 raw_text = '@user\nuser@example.com\n@user\nuser @user'
31 preparsed_text = Parser().preparse(raw_text)
31 preparsed_text = Parser().preparse(raw_text)
32
32
@@ -1,4 +1,4 b''
1 from django.conf.urls import patterns, url
1 from django.conf.urls import url
2 #from django.views.i18n import javascript_catalog
2 #from django.views.i18n import javascript_catalog
3
3
4 from boards import views
4 from boards import views
@@ -20,7 +20,7 b' js_info_dict = {'
20 'packages': ('boards',),
20 'packages': ('boards',),
21 }
21 }
22
22
23 urlpatterns = patterns('',
23 urlpatterns = [
24 # /boards/
24 # /boards/
25 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
25 url(r'^$', all_threads.AllThreadsView.as_view(), name='index'),
26
26
@@ -80,17 +80,18 b" urlpatterns = patterns('',"
80 url(r'^api/sync/get/$', response_get, name='api_sync_pull'),
80 url(r'^api/sync/get/$', response_get, name='api_sync_pull'),
81 # TODO 'get' request
81 # TODO 'get' request
82
82
83 # Search
84 url(r'^search/$', BoardSearchView.as_view(), name='search'),
85
86 # Notifications
83 # Notifications
87 url(r'^notifications/(?P<username>\w+)/$', NotificationView.as_view(), name='notifications'),
84 url(r'^notifications/(?P<username>\w+)/$', NotificationView.as_view(), name='notifications'),
88 url(r'^notifications/$', NotificationView.as_view(), name='notifications'),
85 url(r'^notifications/$', NotificationView.as_view(), name='notifications'),
89
86
90 # Post preview
87 # Post preview
91 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
88 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
92
93 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
89 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
94 name='post_sync_data'),
90 name='post_sync_data'),
91 ]
95
92
96 )
93 # Search
94 if 'haystack' in neboard.settings.INSTALLED_APPS:
95 from boards.views.search import BoardSearchView
96 urlpatterns.append(url(r'^search/$', BoardSearchView.as_view(), name='search'))
97
@@ -13,7 +13,7 b' from django.template.defaultfilters impo'
13 from django.utils import timezone
13 from django.utils import timezone
14 from django.utils.translation import ugettext_lazy as _
14 from django.utils.translation import ugettext_lazy as _
15 import magic
15 import magic
16 from portage import os
16 import os
17
17
18 import boards
18 import boards
19 from boards.settings import get_bool
19 from boards.settings import get_bool
@@ -1,4 +1,3 b''
1 from dbus.decorators import method
2 from django.core.urlresolvers import reverse
1 from django.core.urlresolvers import reverse
3 from django.core.files import File
2 from django.core.files import File
4 from django.core.files.temp import NamedTemporaryFile
3 from django.core.files.temp import NamedTemporaryFile
@@ -64,6 +63,12 b' class AllThreadsView(PostMixin, FileUplo'
64 threads = threads.order_by('-bump_time')
63 threads = threads.order_by('-bump_time')
65 else:
64 else:
66 threads = threads.filter(multi_replies__opening=True).order_by('-multi_replies__pub_time')
65 threads = threads.filter(multi_replies__opening=True).order_by('-multi_replies__pub_time')
66 filter = request.GET.get('filter')
67 if filter == 'fav_tags':
68 fav_tags = self.settings_manager.get_fav_tags()
69 if len(fav_tags) > 0:
70 threads = threads.filter(tags__in=fav_tags)
71 threads = threads.distinct()
67
72
68 paginator = get_paginator(threads,
73 paginator = get_paginator(threads,
69 settings.get_int('View', 'ThreadsPerPage'))
74 settings.get_int('View', 'ThreadsPerPage'))
@@ -133,6 +138,7 b' class AllThreadsView(PostMixin, FileUplo'
133 text = data[FORM_TEXT]
138 text = data[FORM_TEXT]
134 file = form.get_file()
139 file = form.get_file()
135 threads = data[FORM_THREADS]
140 threads = data[FORM_THREADS]
141 images = form.get_images()
136
142
137 text = self._remove_invalid_links(text)
143 text = self._remove_invalid_links(text)
138
144
@@ -142,7 +148,7 b' class AllThreadsView(PostMixin, FileUplo'
142 post = Post.objects.create_post(title=title, text=text, file=file,
148 post = Post.objects.create_post(title=title, text=text, file=file,
143 ip=ip, tags=tags, opening_posts=threads,
149 ip=ip, tags=tags, opening_posts=threads,
144 tripcode=form.get_tripcode(),
150 tripcode=form.get_tripcode(),
145 monochrome=monochrome)
151 monochrome=monochrome, images=images)
146
152
147 # This is required to update the threads to which posts we have replied
153 # This is required to update the threads to which posts we have replied
148 # when creating this one
154 # when creating this one
@@ -12,7 +12,6 b' POSTS_PER_PAGE = 10'
12 PARAMETER_CURRENT_PAGE = 'current_page'
12 PARAMETER_CURRENT_PAGE = 'current_page'
13 PARAMETER_PAGINATOR = 'paginator'
13 PARAMETER_PAGINATOR = 'paginator'
14 PARAMETER_POSTS = 'posts'
14 PARAMETER_POSTS = 'posts'
15 PARAMETER_ADDITONAL_ATTRS = 'additional_attrs'
16
15
17 PARAMETER_PREV_LINK = 'prev_page_link'
16 PARAMETER_PREV_LINK = 'prev_page_link'
18 PARAMETER_NEXT_LINK = 'next_page_link'
17 PARAMETER_NEXT_LINK = 'next_page_link'
@@ -26,6 +25,7 b' class FeedView(PostMixin, BaseBoardView)'
26 def get(self, request):
25 def get(self, request):
27 page = request.GET.get('page', DEFAULT_PAGE)
26 page = request.GET.get('page', DEFAULT_PAGE)
28 tripcode = request.GET.get('tripcode', None)
27 tripcode = request.GET.get('tripcode', None)
28 favorites = 'favorites' in request.GET
29
29
30 params = self.get_context_data(request=request)
30 params = self.get_context_data(request=request)
31
31
@@ -36,17 +36,16 b' class FeedView(PostMixin, BaseBoardView)'
36 '-pub_time').prefetch_related('images', 'thread', 'threads')
36 '-pub_time').prefetch_related('images', 'thread', 'threads')
37 if tripcode:
37 if tripcode:
38 posts = posts.filter(tripcode=tripcode)
38 posts = posts.filter(tripcode=tripcode)
39 if favorites:
40 fav_thread_ops = Post.objects.filter(id__in=settings_manager.get_fav_threads().keys())
41 fav_threads = [op.get_thread() for op in fav_thread_ops]
42 posts = posts.filter(threads__in=fav_threads)
39
43
40 paginator = get_paginator(posts, POSTS_PER_PAGE)
44 paginator = get_paginator(posts, POSTS_PER_PAGE)
41 paginator.current_page = int(page)
45 paginator.current_page = int(page)
42
46
43 params[PARAMETER_POSTS] = paginator.page(page).object_list
47 params[PARAMETER_POSTS] = paginator.page(page).object_list
44
48
45 additional_params = dict()
46 if tripcode:
47 additional_params['tripcode'] = tripcode
48 params[PARAMETER_ADDITONAL_ATTRS] = '&tripcode=' + tripcode
49
50 paginator.set_url(reverse('feed'), request.GET.dict())
49 paginator.set_url(reverse('feed'), request.GET.dict())
51
50
52 self.get_page_context(paginator, params, page)
51 self.get_page_context(paginator, params, page)
@@ -8,6 +8,7 b' from boards.middlewares import SESSION_T'
8 from boards.views.base import BaseBoardView, CONTEXT_FORM
8 from boards.views.base import BaseBoardView, CONTEXT_FORM
9 from boards.forms import SettingsForm, PlainErrorList
9 from boards.forms import SettingsForm, PlainErrorList
10 from boards import settings
10 from boards import settings
11 from boards.models import PostImage
11
12
12 FORM_THEME = 'theme'
13 FORM_THEME = 'theme'
13 FORM_USERNAME = 'username'
14 FORM_USERNAME = 'username'
@@ -15,6 +16,7 b" FORM_TIMEZONE = 'timezone'"
15 FORM_IMAGE_VIEWER = 'image_viewer'
16 FORM_IMAGE_VIEWER = 'image_viewer'
16
17
17 CONTEXT_HIDDEN_TAGS = 'hidden_tags'
18 CONTEXT_HIDDEN_TAGS = 'hidden_tags'
19 CONTEXT_IMAGE_ALIASES = 'image_aliases'
18
20
19 TEMPLATE = 'boards/settings.html'
21 TEMPLATE = 'boards/settings.html'
20
22
@@ -41,6 +43,7 b' class SettingsView(BaseBoardView):'
41
43
42 params[CONTEXT_FORM] = form
44 params[CONTEXT_FORM] = form
43 params[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags()
45 params[CONTEXT_HIDDEN_TAGS] = settings_manager.get_hidden_tags()
46 params[CONTEXT_IMAGE_ALIASES] = PostImage.objects.exclude(alias='').exclude(alias=None)
44
47
45 return render(request, TEMPLATE, params)
48 return render(request, TEMPLATE, params)
46
49
@@ -129,6 +129,7 b' class ThreadView(BaseBoardView, PostMixi'
129 text = data[FORM_TEXT]
129 text = data[FORM_TEXT]
130 file = form.get_file()
130 file = form.get_file()
131 threads = data[FORM_THREADS]
131 threads = data[FORM_THREADS]
132 images = form.get_images()
132
133
133 text = self._remove_invalid_links(text)
134 text = self._remove_invalid_links(text)
134
135
@@ -137,7 +138,8 b' class ThreadView(BaseBoardView, PostMixi'
137 post = Post.objects.create_post(title=title, text=text, file=file,
138 post = Post.objects.create_post(title=title, text=text, file=file,
138 thread=post_thread, ip=ip,
139 thread=post_thread, ip=ip,
139 opening_posts=threads,
140 opening_posts=threads,
140 tripcode=form.get_tripcode())
141 tripcode=form.get_tripcode(),
142 images=images)
141 post.notify_clients()
143 post.notify_clients()
142
144
143 if html_response:
145 if html_response:
@@ -75,3 +75,11 b' more simple now'
75 * Posting to many threads by one post
75 * Posting to many threads by one post
76 * Tag details
76 * Tag details
77 * Removed compact form
77 * Removed compact form
78
79 # 2.12.0 Lyekka
80 * Interesting threads feed for favorite tag threads
81 * Don't close image popups opened from the reflink popups
82 * Shared workers for PoW and favorites update
83 * Add random number of spaces to spoiler
84 * Monochrome threads
85 * CSRF protection
@@ -1,4 +1,4 b''
1 from django.conf.urls import patterns, include, url
1 from django.conf.urls import include, url
2
2
3 # Uncomment the next two lines to enable the admin:
3 # Uncomment the next two lines to enable the admin:
4 from django.conf.urls.static import static
4 from django.conf.urls.static import static
@@ -9,12 +9,12 b' from boards.views.not_found import NotFo'
9
9
10 admin.autodiscover()
10 admin.autodiscover()
11
11
12 urlpatterns = patterns('',
12 urlpatterns = [
13 # Uncomment the admin/doc line below to enable admin documentation:
13 # Uncomment the admin/doc line below to enable admin documentation:
14 # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
14 # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
15
15
16 url(r'^admin/', include(admin.site.urls), name='admin'),
16 url(r'^admin/', include(admin.site.urls), name='admin'),
17 url(r'^', include('boards.urls')),
17 url(r'^', include('boards.urls')),
18 ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
18 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
19
19
20 handler404 = NotFoundView.as_view()
20 handler404 = NotFoundView.as_view()
@@ -1,3 +1,4 b''
1 python-magic
1 httplib2
2 httplib2
2 simplejson
3 simplejson
3 magic
4 magic
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now