· 8 years ago · Sep 09, 2017, 06:22 PM
1/* DAS PR0GRAMM MAG JAVASCRIPT UND...
2
3jquery
4 http://jquery.com/
5
6jquery-cookie
7 https://github.com/carhartl/jquery-cookie
8
9jquery-tagsinput
10 https://github.com/xoxco/jQuery-Tags-Input
11
12John Resig's Simple JavaScript Inheritance
13 http://ejohn.org/blog/simple-javascript-inheritance/
14*/
15/* Amalgamation 2017-08-22 16:55:03 */
16"use strict";
17window.p = {
18 NAVIGATE: {
19 DEFAULT: 0,
20 SILENT: 1,
21 FORCE: 2
22 },
23 path: 'frontend/',
24 currentView: null,
25 $container: null,
26 dispatchFromHistory: false,
27 mobile: (/mobile|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)),
28 _routes: [],
29 _loaded: {
30 'lib/pproject.js': true
31 },
32 _current: [],
33 _loadedCache: {},
34 _navigationStack: [],
35 _hasPushState: (window.history && window.history.pushState),
36 location: '--p-invalid',
37 debug: false,
38 log: function() {
39 if (this.debug) {
40 console.log.apply(console, arguments);
41 }
42 },
43 token: function() {
44 return Math.random().toString(36).substr(2);
45 },
46 copy: function(object) {
47 if (!object || typeof(object) != 'object' || object instanceof p.Class || object === null) {
48 return object;
49 } else if (object instanceof Array) {
50 var c = [];
51 for (var i = 0, l = object.length; i < l; i++) {
52 c[i] = p.copy(object[i]);
53 }
54 return c;
55 } else {
56 var c = {};
57 for (var i in object) {
58 c[i] = p.copy(object[i]);
59 }
60 return c;
61 }
62 },
63 merge: function(original, extended) {
64 for (var key in extended) {
65 var ext = extended[key];
66 if (typeof(ext) != 'object' || ext instanceof HTMLElement || ext instanceof p.Class || ext === null) {
67 original[key] = ext;
68 } else {
69 if (!original[key] || typeof(original[key]) != 'object') {
70 original[key] = (ext instanceof Array) ? [] : {};
71 }
72 p.merge(original[key], ext);
73 }
74 }
75 return original;
76 },
77 load: function(file, asObject) {
78 var request = new XMLHttpRequest();
79 request.open('GET', '/' + file, false);
80 request.send();
81 return (asObject === false) ? request.responseText : {
82 src: request.responseText,
83 path: file
84 };
85 },
86 require: function(file) {
87 if (this._loaded[file]) {
88 return;
89 }
90 if ([].indexOf && this._current.indexOf(file) !== -1) {
91 console.log('Circular dependency: ' + this._current.join(' -> ') + ' -> ' + file);
92 return;
93 }
94 this._current.push(file);
95 var code = this.load(this.path + file, false) + "\n //# sourceURL=" + this.path + file;
96 try {
97 eval.call(window, code);
98 } catch (error) {
99 console.error(error, error.message, error.lineNumber, this.path + file);
100 }
101 this._current.pop();
102 this._loaded[file] = true;
103 },
104 _cachedRegexp: {
105 escapeQuotes: /'/g,
106 escapeBackslashes: /\\/g,
107 unescapeQuotes: /\\'/g,
108 removeWhitspace: /[\r\t\n]+/g,
109 printEscaped: /\{\{([\w\.\,\(\)\[\]\"]+?)\}\}/mg,
110 print: /\{([\w\.\,\(\)\[\]\"]+?)\}/g,
111 js: /<\?js(.*?)\?>/mg
112 },
113 compileTemplate: function(t) {
114 var path = t.path || 'unknown';
115 t = t.src || t;
116 try {
117 var re = this._cachedRegexp;
118 var compiled = new Function("data", "try {" + "data = data || {};" + "var _parts = [];" + "var print = function(a){ _parts.push(a); };" + "with(data){ _parts.push('" +
119 t.replace(re.escapeBackslashes, "\\\\").replace(re.escapeQuotes, "\\'").replace(re.removeWhitspace, " ").replace(re.printEscaped, function(m, js) {
120 return "'," + js.replace(re.unescapeQuotes, "'") + ".escape(),'";
121 }).replace(re.print, function(m, js) {
122 return "'," + js.replace(re.unescapeQuotes, "'") + ",'";
123 }).replace(re.js, function(m, js) {
124 return "');" + js.replace(re.unescapeQuotes, "'") + ";_parts.push('";
125 }) +
126 "');} " + "} catch( error ) { console.error(error.message + ' in " + path + "'); }" + "return _parts.join('');");
127 } catch (error) {
128 console.error(error.message, path);
129 }
130 return compiled;
131 },
132 link: function(link) {
133 return '#' + link;
134 },
135 getURL: function() {
136 var f = '';
137 if (document.location.pathname != '/') {
138 f = document.location.pathname.substr(1);
139 } else {
140 var match = window.location.href.match(/#(.*)$/);
141 f = match ? match[1] : '';
142 }
143 return f;
144 },
145 getLocation: function() {
146 return this.getURL().split(':')[0];
147 },
148 getFragment: function() {
149 return this.getURL().split(':')[1] || '';
150 },
151 navigateTo: function(location, mode) {
152 this._navigateSilent = (mode == p.NAVIGATE.SILENT);
153 if (this._hasPushState) {
154 var url = '/' + location;
155 window.history.pushState({}, document.title, url);
156 this._dispatch(null, mode == p.NAVIGATE.FORCE);
157 } else {
158 var url = document.location.href.replace(/#.*$/, '') + '#' + location;
159 document.location.assign(url);
160 }
161 if (CONFIG.ANALYTICS.ENABLED && window.ga) {
162 ga('send', 'pageview', {
163 page: location
164 });
165 }
166 },
167 navigateToPopStack: function() {
168 if (!this._navigationStack.length) {
169 this.navigateTo('');
170 } else {
171 this.navigateTo(this._navigationStack.pop());
172 }
173 },
174 navigateToPushStack: function(location) {
175 this._navigationStack.push(this.getLocation());
176 this.navigateTo(location);
177 },
178 addRoute: function(viewClass, rule) {
179 if (!viewClass) {
180 throw ('Invalid viewClass ' + viewClass + ' for rule ' + rule);
181 }
182 var compiledRegexp = /(.*)/,
183 names = [];
184 if (rule !== '*') {
185 names = rule.match(/<([^>]+)>/g) || [];
186 for (var i = 0; names && i < names.length; i++) {
187 names[i] = names[i].replace(/<|:.*>|>/g, '');
188 }
189 var regexp = rule.replace(/\//g, '\\/').replace(/<\w+:d>/g, '(\\d+)').replace(/<\w+:(.*?)>/g, '($1)').replace(/<\w+>/g, '([^\\/]+)');
190 compiledRegexp = new RegExp('^' + regexp + '$');
191 }
192 this._routes.push({
193 rule: compiledRegexp,
194 paramNames: names,
195 viewClass: viewClass
196 });
197 },
198 setView: function(viewClass, params) {
199 if (!this.currentView || this.currentView.classId !== viewClass.classId) {
200 if (this.currentView) {
201 this.currentView.hide();
202 }
203 var newView = new(viewClass)(this.$container);
204 if (newView.aborted) {
205 return;
206 }
207 this.currentView = newView;
208 }
209 if (this.onsetview) {
210 this.onsetview(this.currentView);
211 }
212 this.currentView.show(params);
213 },
214 reload: function() {
215 window.location.reload(true);
216 },
217 _dispatch: function(event, force) {
218 var prevLocation = this.location;
219 this.location = this.getLocation();
220 var prevFragment = this.fragment;
221 this.fragment = this.getFragment();
222 if (this._navigateSilent || (prevLocation == this.location && force !== true)) {
223 this._navigateSilent = false;
224 if (prevFragment != this.fragment && this.currentView && this.currentView.fragmentChange) {
225 this.currentView.fragmentChange(this.fragment);
226 }
227 return;
228 }
229 var matches = null;
230 for (var r = 0; r < this._routes.length; r++) {
231 var route = this._routes[r];
232 if ((matches = this.location.match(route.rule))) {
233 var params = {};
234 for (var i = 0; i < route.paramNames.length; i++) {
235 params[route.paramNames[i]] = decodeURIComponent(matches[i + 1]);
236 }
237 this.dispatchFromHistory = !!event;
238 this.setView(this._routes[r].viewClass, params);
239 this.dispatchFromHistory = false;
240 return;
241 }
242 }
243 },
244 _started: false,
245 start: function(container) {
246 if (this._started) {
247 return;
248 }
249 var hashMatch = window.location.href.match(/#(.+)$/);
250 if (this._hasPushState && hashMatch) {
251 window.history.replaceState({}, document.title, '/' + hashMatch[1]);
252 } else if (!this._hasPushState && document.location.pathname != '/') {
253 document.location.href = '/#' + this.getLocation();
254 return;
255 }
256 this._started = true;
257 this.$container = $(container || 'body');
258 var ev = this._hasPushState ? 'popstate' : 'hashchange';
259 $(window).bind(ev, this._dispatch.bind(this));
260 this._dispatch();
261 }
262};
263"use strict";
264(function(window) {
265 var initializing = false,
266 fnTest = /xyz/.test(function() {
267 xyz;
268 }) ? /\bparent\b/ : /.*/;
269 window.p.Class = function() {};
270 window.p.Class.extend = function(prop) {
271 var parent = this.prototype;
272 initializing = true;
273 var prototype = new this();
274 initializing = false;
275 for (var name in prop) {
276 if (typeof(prop[name]) == "function" && typeof(parent[name]) == "function" && fnTest.test(prop[name])) {
277 prototype[name] = (function(name, fn) {
278 return function() {
279 var tmp = this.parent;
280 this.parent = parent[name];
281 var ret = fn.apply(this, arguments);
282 this.parent = tmp;
283 return ret;
284 };
285 })(name, prop[name]);
286 } else {
287 prototype[name] = prop[name];
288 }
289 }
290
291 function Class() {
292 if (!initializing) {
293 if (this.staticInstantiate) {
294 var obj = this.staticInstantiate.apply(this, arguments);
295 if (obj) {
296 return obj;
297 }
298 }
299 for (var prop in this) {
300 if (typeof(this[prop]) == 'object') {
301 this[prop] = p.copy(this[prop]);
302 }
303 }
304 if (this.init) {
305 this.init.apply(this, arguments);
306 }
307 }
308 return this;
309 }
310 Class.prototype = prototype;
311 Class.prototype.constructor = Class;
312 Class.extend = window.p.Class.extend;
313 Class.classId = prototype.classId = ++window.p.Class._lastId;
314 return Class;
315 };
316 window.p.Class._lastId = 0;
317})(window);
318! function(a, b) {
319 "object" == typeof module && "object" == typeof module.exports ? module.exports = a.document ? b(a, !0) : function(a) {
320 if (!a.document) throw new Error("jQuery requires a window with a document");
321 return b(a)
322 } : b(a)
323}("undefined" != typeof window ? window : this, function(a, b) {
324 var c = [],
325 d = c.slice,
326 e = c.concat,
327 f = c.push,
328 g = c.indexOf,
329 h = {},
330 i = h.toString,
331 j = h.hasOwnProperty,
332 k = "".trim,
333 l = {},
334 m = a.document,
335 n = "2.1.0",
336 o = function(a, b) {
337 return new o.fn.init(a, b)
338 },
339 p = /^-ms-/,
340 q = /-([\da-z])/gi,
341 r = function(a, b) {
342 return b.toUpperCase()
343 };
344 o.fn = o.prototype = {
345 jquery: n,
346 constructor: o,
347 selector: "",
348 length: 0,
349 toArray: function() {
350 return d.call(this)
351 },
352 get: function(a) {
353 return null != a ? 0 > a ? this[a + this.length] : this[a] : d.call(this)
354 },
355 pushStack: function(a) {
356 var b = o.merge(this.constructor(), a);
357 return b.prevObject = this, b.context = this.context, b
358 },
359 each: function(a, b) {
360 return o.each(this, a, b)
361 },
362 map: function(a) {
363 return this.pushStack(o.map(this, function(b, c) {
364 return a.call(b, c, b)
365 }))
366 },
367 slice: function() {
368 return this.pushStack(d.apply(this, arguments))
369 },
370 first: function() {
371 return this.eq(0)
372 },
373 last: function() {
374 return this.eq(-1)
375 },
376 eq: function(a) {
377 var b = this.length,
378 c = +a + (0 > a ? b : 0);
379 return this.pushStack(c >= 0 && b > c ? [this[c]] : [])
380 },
381 end: function() {
382 return this.prevObject || this.constructor(null)
383 },
384 push: f,
385 sort: c.sort,
386 splice: c.splice
387 }, o.extend = o.fn.extend = function() {
388 var a, b, c, d, e, f, g = arguments[0] || {},
389 h = 1,
390 i = arguments.length,
391 j = !1;
392 for ("boolean" == typeof g && (j = g, g = arguments[h] || {}, h++), "object" == typeof g || o.isFunction(g) || (g = {}), h === i && (g = this, h--); i > h; h++)
393 if (null != (a = arguments[h]))
394 for (b in a) c = g[b], d = a[b], g !== d && (j && d && (o.isPlainObject(d) || (e = o.isArray(d))) ? (e ? (e = !1, f = c && o.isArray(c) ? c : []) : f = c && o.isPlainObject(c) ? c : {}, g[b] = o.extend(j, f, d)) : void 0 !== d && (g[b] = d));
395 return g
396 }, o.extend({
397 expando: "jQuery" + (n + Math.random()).replace(/\D/g, ""),
398 isReady: !0,
399 error: function(a) {
400 throw new Error(a)
401 },
402 noop: function() {},
403 isFunction: function(a) {
404 return "function" === o.type(a)
405 },
406 isArray: Array.isArray,
407 isWindow: function(a) {
408 return null != a && a === a.window
409 },
410 isNumeric: function(a) {
411 return a - parseFloat(a) >= 0
412 },
413 isPlainObject: function(a) {
414 if ("object" !== o.type(a) || a.nodeType || o.isWindow(a)) return !1;
415 try {
416 if (a.constructor && !j.call(a.constructor.prototype, "isPrototypeOf")) return !1
417 } catch (b) {
418 return !1
419 }
420 return !0
421 },
422 isEmptyObject: function(a) {
423 var b;
424 for (b in a) return !1;
425 return !0
426 },
427 type: function(a) {
428 return null == a ? a + "" : "object" == typeof a || "function" == typeof a ? h[i.call(a)] || "object" : typeof a
429 },
430 globalEval: function(a) {
431 var b, c = eval;
432 a = o.trim(a), a && (1 === a.indexOf("use strict") ? (b = m.createElement("script"), b.text = a, m.head.appendChild(b).parentNode.removeChild(b)) : c(a))
433 },
434 camelCase: function(a) {
435 return a.replace(p, "ms-").replace(q, r)
436 },
437 nodeName: function(a, b) {
438 return a.nodeName && a.nodeName.toLowerCase() === b.toLowerCase()
439 },
440 each: function(a, b, c) {
441 var d, e = 0,
442 f = a.length,
443 g = s(a);
444 if (c) {
445 if (g) {
446 for (; f > e; e++)
447 if (d = b.apply(a[e], c), d === !1) break
448 } else
449 for (e in a)
450 if (d = b.apply(a[e], c), d === !1) break
451 } else if (g) {
452 for (; f > e; e++)
453 if (d = b.call(a[e], e, a[e]), d === !1) break
454 } else
455 for (e in a)
456 if (d = b.call(a[e], e, a[e]), d === !1) break;
457 return a
458 },
459 trim: function(a) {
460 return null == a ? "" : k.call(a)
461 },
462 makeArray: function(a, b) {
463 var c = b || [];
464 return null != a && (s(Object(a)) ? o.merge(c, "string" == typeof a ? [a] : a) : f.call(c, a)), c
465 },
466 inArray: function(a, b, c) {
467 return null == b ? -1 : g.call(b, a, c)
468 },
469 merge: function(a, b) {
470 for (var c = +b.length, d = 0, e = a.length; c > d; d++) a[e++] = b[d];
471 return a.length = e, a
472 },
473 grep: function(a, b, c) {
474 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]);
475 return e
476 },
477 map: function(a, b, c) {
478 var d, f = 0,
479 g = a.length,
480 h = s(a),
481 i = [];
482 if (h)
483 for (; g > f; f++) d = b(a[f], f, c), null != d && i.push(d);
484 else
485 for (f in a) d = b(a[f], f, c), null != d && i.push(d);
486 return e.apply([], i)
487 },
488 guid: 1,
489 proxy: function(a, b) {
490 var c, e, f;
491 return "string" == typeof b && (c = a[b], b = a, a = c), o.isFunction(a) ? (e = d.call(arguments, 2), f = function() {
492 return a.apply(b || this, e.concat(d.call(arguments)))
493 }, f.guid = a.guid = a.guid || o.guid++, f) : void 0
494 },
495 now: Date.now,
496 support: l
497 }), o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(a, b) {
498 h["[object " + b + "]"] = b.toLowerCase()
499 });
500
501 function s(a) {
502 var b = a.length,
503 c = o.type(a);
504 return "function" === c || o.isWindow(a) ? !1 : 1 === a.nodeType && b ? !0 : "array" === c || 0 === b || "number" == typeof b && b > 0 && b - 1 in a
505 }
506 var t = function(a) {
507 var b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s = "sizzle" + -new Date,
508 t = a.document,
509 u = 0,
510 v = 0,
511 w = eb(),
512 x = eb(),
513 y = eb(),
514 z = function(a, b) {
515 return a === b && (j = !0), 0
516 },
517 A = "undefined",
518 B = 1 << 31,
519 C = {}.hasOwnProperty,
520 D = [],
521 E = D.pop,
522 F = D.push,
523 G = D.push,
524 H = D.slice,
525 I = D.indexOf || function(a) {
526 for (var b = 0, c = this.length; c > b; b++)
527 if (this[b] === a) return b;
528 return -1
529 },
530 J = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
531 K = "[\\x20\\t\\r\\n\\f]",
532 L = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
533 M = L.replace("w", "w#"),
534 N = "\\[" + K + "*(" + L + ")" + K + "*(?:([*^$|!~]?=)" + K + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + M + ")|)|)" + K + "*\\]",
535 O = ":(" + L + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + N.replace(3, 8) + ")*)|.*)\\)|)",
536 P = new RegExp("^" + K + "+|((?:^|[^\\\\])(?:\\\\.)*)" + K + "+$", "g"),
537 Q = new RegExp("^" + K + "*," + K + "*"),
538 R = new RegExp("^" + K + "*([>+~]|" + K + ")" + K + "*"),
539 S = new RegExp("=" + K + "*([^\\]'\"]*?)" + K + "*\\]", "g"),
540 T = new RegExp(O),
541 U = new RegExp("^" + M + "$"),
542 V = {
543 ID: new RegExp("^#(" + L + ")"),
544 CLASS: new RegExp("^\\.(" + L + ")"),
545 TAG: new RegExp("^(" + L.replace("w", "w*") + ")"),
546 ATTR: new RegExp("^" + N),
547 PSEUDO: new RegExp("^" + O),
548 CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + K + "*(even|odd|(([+-]|)(\\d*)n|)" + K + "*(?:([+-]|)" + K + "*(\\d+)|))" + K + "*\\)|)", "i"),
549 bool: new RegExp("^(?:" + J + ")$", "i"),
550 needsContext: new RegExp("^" + K + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + K + "*((?:-\\d)?\\d*)" + K + "*\\)|)(?=[^-]|$)", "i")
551 },
552 W = /^(?:input|select|textarea|button)$/i,
553 X = /^h\d$/i,
554 Y = /^[^{]+\{\s*\[native \w/,
555 Z = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
556 $ = /[+~]/,
557 _ = /'|\\/g,
558 ab = new RegExp("\\\\([\\da-f]{1,6}" + K + "?|(" + K + ")|.)", "ig"),
559 bb = function(a, b, c) {
560 var d = "0x" + b - 65536;
561 return d !== d || c ? b : 0 > d ? String.fromCharCode(d + 65536) : String.fromCharCode(d >> 10 | 55296, 1023 & d | 56320)
562 };
563 try {
564 G.apply(D = H.call(t.childNodes), t.childNodes), D[t.childNodes.length].nodeType
565 } catch (cb) {
566 G = {
567 apply: D.length ? function(a, b) {
568 F.apply(a, H.call(b))
569 } : function(a, b) {
570 var c = a.length,
571 d = 0;
572 while (a[c++] = b[d++]);
573 a.length = c - 1
574 }
575 }
576 }
577
578 function db(a, b, d, e) {
579 var f, g, h, i, j, m, p, q, u, v;
580 if ((b ? b.ownerDocument || b : t) !== l && k(b), b = b || l, d = d || [], !a || "string" != typeof a) return d;
581 if (1 !== (i = b.nodeType) && 9 !== i) return [];
582 if (n && !e) {
583 if (f = Z.exec(a))
584 if (h = f[1]) {
585 if (9 === i) {
586 if (g = b.getElementById(h), !g || !g.parentNode) return d;
587 if (g.id === h) return d.push(g), d
588 } else if (b.ownerDocument && (g = b.ownerDocument.getElementById(h)) && r(b, g) && g.id === h) return d.push(g), d
589 } else {
590 if (f[2]) return G.apply(d, b.getElementsByTagName(a)), d;
591 if ((h = f[3]) && c.getElementsByClassName && b.getElementsByClassName) return G.apply(d, b.getElementsByClassName(h)), d
592 }
593 if (c.qsa && (!o || !o.test(a))) {
594 if (q = p = s, u = b, v = 9 === i && a, 1 === i && "object" !== b.nodeName.toLowerCase()) {
595 m = ob(a), (p = b.getAttribute("id")) ? q = p.replace(_, "\\$&") : b.setAttribute("id", q), q = "[id='" + q + "'] ", j = m.length;
596 while (j--) m[j] = q + pb(m[j]);
597 u = $.test(a) && mb(b.parentNode) || b, v = m.join(",")
598 }
599 if (v) try {
600 return G.apply(d, u.querySelectorAll(v)), d
601 } catch (w) {} finally {
602 p || b.removeAttribute("id")
603 }
604 }
605 }
606 return xb(a.replace(P, "$1"), b, d, e)
607 }
608
609 function eb() {
610 var a = [];
611
612 function b(c, e) {
613 return a.push(c + " ") > d.cacheLength && delete b[a.shift()], b[c + " "] = e
614 }
615 return b
616 }
617
618 function fb(a) {
619 return a[s] = !0, a
620 }
621
622 function gb(a) {
623 var b = l.createElement("div");
624 try {
625 return !!a(b)
626 } catch (c) {
627 return !1
628 } finally {
629 b.parentNode && b.parentNode.removeChild(b), b = null
630 }
631 }
632
633 function hb(a, b) {
634 var c = a.split("|"),
635 e = a.length;
636 while (e--) d.attrHandle[c[e]] = b
637 }
638
639 function ib(a, b) {
640 var c = b && a,
641 d = c && 1 === a.nodeType && 1 === b.nodeType && (~b.sourceIndex || B) - (~a.sourceIndex || B);
642 if (d) return d;
643 if (c)
644 while (c = c.nextSibling)
645 if (c === b) return -1;
646 return a ? 1 : -1
647 }
648
649 function jb(a) {
650 return function(b) {
651 var c = b.nodeName.toLowerCase();
652 return "input" === c && b.type === a
653 }
654 }
655
656 function kb(a) {
657 return function(b) {
658 var c = b.nodeName.toLowerCase();
659 return ("input" === c || "button" === c) && b.type === a
660 }
661 }
662
663 function lb(a) {
664 return fb(function(b) {
665 return b = +b, fb(function(c, d) {
666 var e, f = a([], c.length, b),
667 g = f.length;
668 while (g--) c[e = f[g]] && (c[e] = !(d[e] = c[e]))
669 })
670 })
671 }
672
673 function mb(a) {
674 return a && typeof a.getElementsByTagName !== A && a
675 }
676 c = db.support = {}, f = db.isXML = function(a) {
677 var b = a && (a.ownerDocument || a).documentElement;
678 return b ? "HTML" !== b.nodeName : !1
679 }, k = db.setDocument = function(a) {
680 var b, e = a ? a.ownerDocument || a : t,
681 g = e.defaultView;
682 return e !== l && 9 === e.nodeType && e.documentElement ? (l = e, m = e.documentElement, n = !f(e), g && g !== g.top && (g.addEventListener ? g.addEventListener("unload", function() {
683 k()
684 }, !1) : g.attachEvent && g.attachEvent("onunload", function() {
685 k()
686 })), c.attributes = gb(function(a) {
687 return a.className = "i", !a.getAttribute("className")
688 }), c.getElementsByTagName = gb(function(a) {
689 return a.appendChild(e.createComment("")), !a.getElementsByTagName("*").length
690 }), c.getElementsByClassName = Y.test(e.getElementsByClassName) && gb(function(a) {
691 return a.innerHTML = "<div class='a'></div><div class='a i'></div>", a.firstChild.className = "i", 2 === a.getElementsByClassName("i").length
692 }), c.getById = gb(function(a) {
693 return m.appendChild(a).id = s, !e.getElementsByName || !e.getElementsByName(s).length
694 }), c.getById ? (d.find.ID = function(a, b) {
695 if (typeof b.getElementById !== A && n) {
696 var c = b.getElementById(a);
697 return c && c.parentNode ? [c] : []
698 }
699 }, d.filter.ID = function(a) {
700 var b = a.replace(ab, bb);
701 return function(a) {
702 return a.getAttribute("id") === b
703 }
704 }) : (delete d.find.ID, d.filter.ID = function(a) {
705 var b = a.replace(ab, bb);
706 return function(a) {
707 var c = typeof a.getAttributeNode !== A && a.getAttributeNode("id");
708 return c && c.value === b
709 }
710 }), d.find.TAG = c.getElementsByTagName ? function(a, b) {
711 return typeof b.getElementsByTagName !== A ? b.getElementsByTagName(a) : void 0
712 } : function(a, b) {
713 var c, d = [],
714 e = 0,
715 f = b.getElementsByTagName(a);
716 if ("*" === a) {
717 while (c = f[e++]) 1 === c.nodeType && d.push(c);
718 return d
719 }
720 return f
721 }, d.find.CLASS = c.getElementsByClassName && function(a, b) {
722 return typeof b.getElementsByClassName !== A && n ? b.getElementsByClassName(a) : void 0
723 }, p = [], o = [], (c.qsa = Y.test(e.querySelectorAll)) && (gb(function(a) {
724 a.innerHTML = "<select t=''><option selected=''></option></select>", a.querySelectorAll("[t^='']").length && o.push("[*^$]=" + K + "*(?:''|\"\")"), a.querySelectorAll("[selected]").length || o.push("\\[" + K + "*(?:value|" + J + ")"), a.querySelectorAll(":checked").length || o.push(":checked")
725 }), gb(function(a) {
726 var b = e.createElement("input");
727 b.setAttribute("type", "hidden"), a.appendChild(b).setAttribute("name", "D"), a.querySelectorAll("[name=d]").length && o.push("name" + K + "*[*^$|!~]?="), a.querySelectorAll(":enabled").length || o.push(":enabled", ":disabled"), a.querySelectorAll("*,:x"), o.push(",.*:")
728 })), (c.matchesSelector = Y.test(q = m.webkitMatchesSelector || m.mozMatchesSelector || m.oMatchesSelector || m.msMatchesSelector)) && gb(function(a) {
729 c.disconnectedMatch = q.call(a, "div"), q.call(a, "[s!='']:x"), p.push("!=", O)
730 }), o = o.length && new RegExp(o.join("|")), p = p.length && new RegExp(p.join("|")), b = Y.test(m.compareDocumentPosition), r = b || Y.test(m.contains) ? function(a, b) {
731 var c = 9 === a.nodeType ? a.documentElement : a,
732 d = b && b.parentNode;
733 return a === d || !(!d || 1 !== d.nodeType || !(c.contains ? c.contains(d) : a.compareDocumentPosition && 16 & a.compareDocumentPosition(d)))
734 } : function(a, b) {
735 if (b)
736 while (b = b.parentNode)
737 if (b === a) return !0;
738 return !1
739 }, z = b ? function(a, b) {
740 if (a === b) return j = !0, 0;
741 var d = !a.compareDocumentPosition - !b.compareDocumentPosition;
742 return d ? d : (d = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) : 1, 1 & d || !c.sortDetached && b.compareDocumentPosition(a) === d ? a === e || a.ownerDocument === t && r(t, a) ? -1 : b === e || b.ownerDocument === t && r(t, b) ? 1 : i ? I.call(i, a) - I.call(i, b) : 0 : 4 & d ? -1 : 1)
743 } : function(a, b) {
744 if (a === b) return j = !0, 0;
745 var c, d = 0,
746 f = a.parentNode,
747 g = b.parentNode,
748 h = [a],
749 k = [b];
750 if (!f || !g) return a === e ? -1 : b === e ? 1 : f ? -1 : g ? 1 : i ? I.call(i, a) - I.call(i, b) : 0;
751 if (f === g) return ib(a, b);
752 c = a;
753 while (c = c.parentNode) h.unshift(c);
754 c = b;
755 while (c = c.parentNode) k.unshift(c);
756 while (h[d] === k[d]) d++;
757 return d ? ib(h[d], k[d]) : h[d] === t ? -1 : k[d] === t ? 1 : 0
758 }, e) : l
759 }, db.matches = function(a, b) {
760 return db(a, null, null, b)
761 }, db.matchesSelector = function(a, b) {
762 if ((a.ownerDocument || a) !== l && k(a), b = b.replace(S, "='$1']"), !(!c.matchesSelector || !n || p && p.test(b) || o && o.test(b))) try {
763 var d = q.call(a, b);
764 if (d || c.disconnectedMatch || a.document && 11 !== a.document.nodeType) return d
765 } catch (e) {}
766 return db(b, l, null, [a]).length > 0
767 }, db.contains = function(a, b) {
768 return (a.ownerDocument || a) !== l && k(a), r(a, b)
769 }, db.attr = function(a, b) {
770 (a.ownerDocument || a) !== l && k(a);
771 var e = d.attrHandle[b.toLowerCase()],
772 f = e && C.call(d.attrHandle, b.toLowerCase()) ? e(a, b, !n) : void 0;
773 return void 0 !== f ? f : c.attributes || !n ? a.getAttribute(b) : (f = a.getAttributeNode(b)) && f.specified ? f.value : null
774 }, db.error = function(a) {
775 throw new Error("Syntax error, unrecognized expression: " + a)
776 }, db.uniqueSort = function(a) {
777 var b, d = [],
778 e = 0,
779 f = 0;
780 if (j = !c.detectDuplicates, i = !c.sortStable && a.slice(0), a.sort(z), j) {
781 while (b = a[f++]) b === a[f] && (e = d.push(f));
782 while (e--) a.splice(d[e], 1)
783 }
784 return i = null, a
785 }, e = db.getText = function(a) {
786 var b, c = "",
787 d = 0,
788 f = a.nodeType;
789 if (f) {
790 if (1 === f || 9 === f || 11 === f) {
791 if ("string" == typeof a.textContent) return a.textContent;
792 for (a = a.firstChild; a; a = a.nextSibling) c += e(a)
793 } else if (3 === f || 4 === f) return a.nodeValue
794 } else
795 while (b = a[d++]) c += e(b);
796 return c
797 }, d = db.selectors = {
798 cacheLength: 50,
799 createPseudo: fb,
800 match: V,
801 attrHandle: {},
802 find: {},
803 relative: {
804 ">": {
805 dir: "parentNode",
806 first: !0
807 },
808 " ": {
809 dir: "parentNode"
810 },
811 "+": {
812 dir: "previousSibling",
813 first: !0
814 },
815 "~": {
816 dir: "previousSibling"
817 }
818 },
819 preFilter: {
820 ATTR: function(a) {
821 return a[1] = a[1].replace(ab, bb), a[3] = (a[4] || a[5] || "").replace(ab, bb), "~=" === a[2] && (a[3] = " " + a[3] + " "), a.slice(0, 4)
822 },
823 CHILD: function(a) {
824 return a[1] = a[1].toLowerCase(), "nth" === a[1].slice(0, 3) ? (a[3] || db.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] && db.error(a[0]), a
825 },
826 PSEUDO: function(a) {
827 var b, c = !a[5] && a[2];
828 return V.CHILD.test(a[0]) ? null : (a[3] && void 0 !== a[4] ? a[2] = a[4] : c && T.test(c) && (b = ob(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))
829 }
830 },
831 filter: {
832 TAG: function(a) {
833 var b = a.replace(ab, bb).toLowerCase();
834 return "*" === a ? function() {
835 return !0
836 } : function(a) {
837 return a.nodeName && a.nodeName.toLowerCase() === b
838 }
839 },
840 CLASS: function(a) {
841 var b = w[a + " "];
842 return b || (b = new RegExp("(^|" + K + ")" + a + "(" + K + "|$)")) && w(a, function(a) {
843 return b.test("string" == typeof a.className && a.className || typeof a.getAttribute !== A && a.getAttribute("class") || "")
844 })
845 },
846 ATTR: function(a, b, c) {
847 return function(d) {
848 var e = db.attr(d, a);
849 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 + " ").indexOf(c) > -1 : "|=" === b ? e === c || e.slice(0, c.length + 1) === c + "-" : !1) : !0
850 }
851 },
852 CHILD: function(a, b, c, d, e) {
853 var f = "nth" !== a.slice(0, 3),
854 g = "last" !== a.slice(-4),
855 h = "of-type" === b;
856 return 1 === d && 0 === e ? function(a) {
857 return !!a.parentNode
858 } : function(b, c, i) {
859 var j, k, l, m, n, o, p = f !== g ? "nextSibling" : "previousSibling",
860 q = b.parentNode,
861 r = h && b.nodeName.toLowerCase(),
862 t = !i && !h;
863 if (q) {
864 if (f) {
865 while (p) {
866 l = b;
867 while (l = l[p])
868 if (h ? l.nodeName.toLowerCase() === r : 1 === l.nodeType) return !1;
869 o = p = "only" === a && !o && "nextSibling"
870 }
871 return !0
872 }
873 if (o = [g ? q.firstChild : q.lastChild], g && t) {
874 k = q[s] || (q[s] = {}), j = k[a] || [], n = j[0] === u && j[1], m = j[0] === u && j[2], l = n && q.childNodes[n];
875 while (l = ++n && l && l[p] || (m = n = 0) || o.pop())
876 if (1 === l.nodeType && ++m && l === b) {
877 k[a] = [u, n, m];
878 break
879 }
880 } else if (t && (j = (b[s] || (b[s] = {}))[a]) && j[0] === u) m = j[1];
881 else
882 while (l = ++n && l && l[p] || (m = n = 0) || o.pop())
883 if ((h ? l.nodeName.toLowerCase() === r : 1 === l.nodeType) && ++m && (t && ((l[s] || (l[s] = {}))[a] = [u, m]), l === b)) break;
884 return m -= e, m === d || m % d === 0 && m / d >= 0
885 }
886 }
887 },
888 PSEUDO: function(a, b) {
889 var c, e = d.pseudos[a] || d.setFilters[a.toLowerCase()] || db.error("unsupported pseudo: " + a);
890 return e[s] ? e(b) : e.length > 1 ? (c = [a, a, "", b], d.setFilters.hasOwnProperty(a.toLowerCase()) ? fb(function(a, c) {
891 var d, f = e(a, b),
892 g = f.length;
893 while (g--) d = I.call(a, f[g]), a[d] = !(c[d] = f[g])
894 }) : function(a) {
895 return e(a, 0, c)
896 }) : e
897 }
898 },
899 pseudos: {
900 not: fb(function(a) {
901 var b = [],
902 c = [],
903 d = g(a.replace(P, "$1"));
904 return d[s] ? fb(function(a, b, c, e) {
905 var f, g = d(a, null, e, []),
906 h = a.length;
907 while (h--)(f = g[h]) && (a[h] = !(b[h] = f))
908 }) : function(a, e, f) {
909 return b[0] = a, d(b, null, f, c), !c.pop()
910 }
911 }),
912 has: fb(function(a) {
913 return function(b) {
914 return db(a, b).length > 0
915 }
916 }),
917 contains: fb(function(a) {
918 return function(b) {
919 return (b.textContent || b.innerText || e(b)).indexOf(a) > -1
920 }
921 }),
922 lang: fb(function(a) {
923 return U.test(a || "") || db.error("unsupported lang: " + a), a = a.replace(ab, bb).toLowerCase(),
924 function(b) {
925 var c;
926 do
927 if (c = n ? 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);
928 return !1
929 }
930 }),
931 target: function(b) {
932 var c = a.location && a.location.hash;
933 return c && c.slice(1) === b.id
934 },
935 root: function(a) {
936 return a === m
937 },
938 focus: function(a) {
939 return a === l.activeElement && (!l.hasFocus || l.hasFocus()) && !!(a.type || a.href || ~a.tabIndex)
940 },
941 enabled: function(a) {
942 return a.disabled === !1
943 },
944 disabled: function(a) {
945 return a.disabled === !0
946 },
947 checked: function(a) {
948 var b = a.nodeName.toLowerCase();
949 return "input" === b && !!a.checked || "option" === b && !!a.selected
950 },
951 selected: function(a) {
952 return a.parentNode && a.parentNode.selectedIndex, a.selected === !0
953 },
954 empty: function(a) {
955 for (a = a.firstChild; a; a = a.nextSibling)
956 if (a.nodeType < 6) return !1;
957 return !0
958 },
959 parent: function(a) {
960 return !d.pseudos.empty(a)
961 },
962 header: function(a) {
963 return X.test(a.nodeName)
964 },
965 input: function(a) {
966 return W.test(a.nodeName)
967 },
968 button: function(a) {
969 var b = a.nodeName.toLowerCase();
970 return "input" === b && "button" === a.type || "button" === b
971 },
972 text: function(a) {
973 var b;
974 return "input" === a.nodeName.toLowerCase() && "text" === a.type && (null == (b = a.getAttribute("type")) || "text" === b.toLowerCase())
975 },
976 first: lb(function() {
977 return [0]
978 }),
979 last: lb(function(a, b) {
980 return [b - 1]
981 }),
982 eq: lb(function(a, b, c) {
983 return [0 > c ? c + b : c]
984 }),
985 even: lb(function(a, b) {
986 for (var c = 0; b > c; c += 2) a.push(c);
987 return a
988 }),
989 odd: lb(function(a, b) {
990 for (var c = 1; b > c; c += 2) a.push(c);
991 return a
992 }),
993 lt: lb(function(a, b, c) {
994 for (var d = 0 > c ? c + b : c; --d >= 0;) a.push(d);
995 return a
996 }),
997 gt: lb(function(a, b, c) {
998 for (var d = 0 > c ? c + b : c; ++d < b;) a.push(d);
999 return a
1000 })
1001 }
1002 }, d.pseudos.nth = d.pseudos.eq;
1003 for (b in {
1004 radio: !0,
1005 checkbox: !0,
1006 file: !0,
1007 password: !0,
1008 image: !0
1009 }) d.pseudos[b] = jb(b);
1010 for (b in {
1011 submit: !0,
1012 reset: !0
1013 }) d.pseudos[b] = kb(b);
1014
1015 function nb() {}
1016 nb.prototype = d.filters = d.pseudos, d.setFilters = new nb;
1017
1018 function ob(a, b) {
1019 var c, e, f, g, h, i, j, k = x[a + " "];
1020 if (k) return b ? 0 : k.slice(0);
1021 h = a, i = [], j = d.preFilter;
1022 while (h) {
1023 (!c || (e = Q.exec(h))) && (e && (h = h.slice(e[0].length) || h), i.push(f = [])), c = !1, (e = R.exec(h)) && (c = e.shift(), f.push({
1024 value: c,
1025 type: e[0].replace(P, " ")
1026 }), h = h.slice(c.length));
1027 for (g in d.filter) !(e = V[g].exec(h)) || j[g] && !(e = j[g](e)) || (c = e.shift(), f.push({
1028 value: c,
1029 type: g,
1030 matches: e
1031 }), h = h.slice(c.length));
1032 if (!c) break
1033 }
1034 return b ? h.length : h ? db.error(a) : x(a, i).slice(0)
1035 }
1036
1037 function pb(a) {
1038 for (var b = 0, c = a.length, d = ""; c > b; b++) d += a[b].value;
1039 return d
1040 }
1041
1042 function qb(a, b, c) {
1043 var d = b.dir,
1044 e = c && "parentNode" === d,
1045 f = v++;
1046 return b.first ? function(b, c, f) {
1047 while (b = b[d])
1048 if (1 === b.nodeType || e) return a(b, c, f)
1049 } : function(b, c, g) {
1050 var h, i, j = [u, f];
1051 if (g) {
1052 while (b = b[d])
1053 if ((1 === b.nodeType || e) && a(b, c, g)) return !0
1054 } else
1055 while (b = b[d])
1056 if (1 === b.nodeType || e) {
1057 if (i = b[s] || (b[s] = {}), (h = i[d]) && h[0] === u && h[1] === f) return j[2] = h[2];
1058 if (i[d] = j, j[2] = a(b, c, g)) return !0
1059 }
1060 }
1061 }
1062
1063 function rb(a) {
1064 return a.length > 1 ? function(b, c, d) {
1065 var e = a.length;
1066 while (e--)
1067 if (!a[e](b, c, d)) return !1;
1068 return !0
1069 } : a[0]
1070 }
1071
1072 function sb(a, b, c, d, e) {
1073 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));
1074 return g
1075 }
1076
1077 function tb(a, b, c, d, e, f) {
1078 return d && !d[s] && (d = tb(d)), e && !e[s] && (e = tb(e, f)), fb(function(f, g, h, i) {
1079 var j, k, l, m = [],
1080 n = [],
1081 o = g.length,
1082 p = f || wb(b || "*", h.nodeType ? [h] : h, []),
1083 q = !a || !f && b ? p : sb(p, m, a, h, i),
1084 r = c ? e || (f ? a : o || d) ? [] : g : q;
1085 if (c && c(q, r, h, i), d) {
1086 j = sb(r, n), d(j, [], h, i), k = j.length;
1087 while (k--)(l = j[k]) && (r[n[k]] = !(q[n[k]] = l))
1088 }
1089 if (f) {
1090 if (e || a) {
1091 if (e) {
1092 j = [], k = r.length;
1093 while (k--)(l = r[k]) && j.push(q[k] = l);
1094 e(null, r = [], j, i)
1095 }
1096 k = r.length;
1097 while (k--)(l = r[k]) && (j = e ? I.call(f, l) : m[k]) > -1 && (f[j] = !(g[j] = l))
1098 }
1099 } else r = sb(r === g ? r.splice(o, r.length) : r), e ? e(null, g, r, i) : G.apply(g, r)
1100 })
1101 }
1102
1103 function ub(a) {
1104 for (var b, c, e, f = a.length, g = d.relative[a[0].type], i = g || d.relative[" "], j = g ? 1 : 0, k = qb(function(a) {
1105 return a === b
1106 }, i, !0), l = qb(function(a) {
1107 return I.call(b, a) > -1
1108 }, i, !0), m = [function(a, c, d) {
1109 return !g && (d || c !== h) || ((b = c).nodeType ? k(a, c, d) : l(a, c, d))
1110 }]; f > j; j++)
1111 if (c = d.relative[a[j].type]) m = [qb(rb(m), c)];
1112 else {
1113 if (c = d.filter[a[j].type].apply(null, a[j].matches), c[s]) {
1114 for (e = ++j; f > e; e++)
1115 if (d.relative[a[e].type]) break;
1116 return tb(j > 1 && rb(m), j > 1 && pb(a.slice(0, j - 1).concat({
1117 value: " " === a[j - 2].type ? "*" : ""
1118 })).replace(P, "$1"), c, e > j && ub(a.slice(j, e)), f > e && ub(a = a.slice(e)), f > e && pb(a))
1119 }
1120 m.push(c)
1121 }
1122 return rb(m)
1123 }
1124
1125 function vb(a, b) {
1126 var c = b.length > 0,
1127 e = a.length > 0,
1128 f = function(f, g, i, j, k) {
1129 var m, n, o, p = 0,
1130 q = "0",
1131 r = f && [],
1132 s = [],
1133 t = h,
1134 v = f || e && d.find.TAG("*", k),
1135 w = u += null == t ? 1 : Math.random() || .1,
1136 x = v.length;
1137 for (k && (h = g !== l && g); q !== x && null != (m = v[q]); q++) {
1138 if (e && m) {
1139 n = 0;
1140 while (o = a[n++])
1141 if (o(m, g, i)) {
1142 j.push(m);
1143 break
1144 }
1145 k && (u = w)
1146 }
1147 c && ((m = !o && m) && p--, f && r.push(m))
1148 }
1149 if (p += q, c && q !== p) {
1150 n = 0;
1151 while (o = b[n++]) o(r, s, g, i);
1152 if (f) {
1153 if (p > 0)
1154 while (q--) r[q] || s[q] || (s[q] = E.call(j));
1155 s = sb(s)
1156 }
1157 G.apply(j, s), k && !f && s.length > 0 && p + b.length > 1 && db.uniqueSort(j)
1158 }
1159 return k && (u = w, h = t), r
1160 };
1161 return c ? fb(f) : f
1162 }
1163 g = db.compile = function(a, b) {
1164 var c, d = [],
1165 e = [],
1166 f = y[a + " "];
1167 if (!f) {
1168 b || (b = ob(a)), c = b.length;
1169 while (c--) f = ub(b[c]), f[s] ? d.push(f) : e.push(f);
1170 f = y(a, vb(e, d))
1171 }
1172 return f
1173 };
1174
1175 function wb(a, b, c) {
1176 for (var d = 0, e = b.length; e > d; d++) db(a, b[d], c);
1177 return c
1178 }
1179
1180 function xb(a, b, e, f) {
1181 var h, i, j, k, l, m = ob(a);
1182 if (!f && 1 === m.length) {
1183 if (i = m[0] = m[0].slice(0), i.length > 2 && "ID" === (j = i[0]).type && c.getById && 9 === b.nodeType && n && d.relative[i[1].type]) {
1184 if (b = (d.find.ID(j.matches[0].replace(ab, bb), b) || [])[0], !b) return e;
1185 a = a.slice(i.shift().value.length)
1186 }
1187 h = V.needsContext.test(a) ? 0 : i.length;
1188 while (h--) {
1189 if (j = i[h], d.relative[k = j.type]) break;
1190 if ((l = d.find[k]) && (f = l(j.matches[0].replace(ab, bb), $.test(i[0].type) && mb(b.parentNode) || b))) {
1191 if (i.splice(h, 1), a = f.length && pb(i), !a) return G.apply(e, f), e;
1192 break
1193 }
1194 }
1195 }
1196 return g(a, m)(f, b, !n, e, $.test(a) && mb(b.parentNode) || b), e
1197 }
1198 return c.sortStable = s.split("").sort(z).join("") === s, c.detectDuplicates = !!j, k(), c.sortDetached = gb(function(a) {
1199 return 1 & a.compareDocumentPosition(l.createElement("div"))
1200 }), gb(function(a) {
1201 return a.innerHTML = "<a href='#'></a>", "#" === a.firstChild.getAttribute("href")
1202 }) || hb("type|href|height|width", function(a, b, c) {
1203 return c ? void 0 : a.getAttribute(b, "type" === b.toLowerCase() ? 1 : 2)
1204 }), c.attributes && gb(function(a) {
1205 return a.innerHTML = "<input/>", a.firstChild.setAttribute("value", ""), "" === a.firstChild.getAttribute("value")
1206 }) || hb("value", function(a, b, c) {
1207 return c || "input" !== a.nodeName.toLowerCase() ? void 0 : a.defaultValue
1208 }), gb(function(a) {
1209 return null == a.getAttribute("disabled")
1210 }) || hb(J, function(a, b, c) {
1211 var d;
1212 return c ? void 0 : a[b] === !0 ? b.toLowerCase() : (d = a.getAttributeNode(b)) && d.specified ? d.value : null
1213 }), db
1214 }(a);
1215 o.find = t, o.expr = t.selectors, o.expr[":"] = o.expr.pseudos, o.unique = t.uniqueSort, o.text = t.getText, o.isXMLDoc = t.isXML, o.contains = t.contains;
1216 var u = o.expr.match.needsContext,
1217 v = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
1218 w = /^.[^:#\[\.,]*$/;
1219
1220 function x(a, b, c) {
1221 if (o.isFunction(b)) return o.grep(a, function(a, d) {
1222 return !!b.call(a, d, a) !== c
1223 });
1224 if (b.nodeType) return o.grep(a, function(a) {
1225 return a === b !== c
1226 });
1227 if ("string" == typeof b) {
1228 if (w.test(b)) return o.filter(b, a, c);
1229 b = o.filter(b, a)
1230 }
1231 return o.grep(a, function(a) {
1232 return g.call(b, a) >= 0 !== c
1233 })
1234 }
1235 o.filter = function(a, b, c) {
1236 var d = b[0];
1237 return c && (a = ":not(" + a + ")"), 1 === b.length && 1 === d.nodeType ? o.find.matchesSelector(d, a) ? [d] : [] : o.find.matches(a, o.grep(b, function(a) {
1238 return 1 === a.nodeType
1239 }))
1240 }, o.fn.extend({
1241 find: function(a) {
1242 var b, c = this.length,
1243 d = [],
1244 e = this;
1245 if ("string" != typeof a) return this.pushStack(o(a).filter(function() {
1246 for (b = 0; c > b; b++)
1247 if (o.contains(e[b], this)) return !0
1248 }));
1249 for (b = 0; c > b; b++) o.find(a, e[b], d);
1250 return d = this.pushStack(c > 1 ? o.unique(d) : d), d.selector = this.selector ? this.selector + " " + a : a, d
1251 },
1252 filter: function(a) {
1253 return this.pushStack(x(this, a || [], !1))
1254 },
1255 not: function(a) {
1256 return this.pushStack(x(this, a || [], !0))
1257 },
1258 is: function(a) {
1259 return !!x(this, "string" == typeof a && u.test(a) ? o(a) : a || [], !1).length
1260 }
1261 });
1262 var y, z = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
1263 A = o.fn.init = function(a, b) {
1264 var c, d;
1265 if (!a) return this;
1266 if ("string" == typeof a) {
1267 if (c = "<" === a[0] && ">" === a[a.length - 1] && a.length >= 3 ? [null, a, null] : z.exec(a), !c || !c[1] && b) return !b || b.jquery ? (b || y).find(a) : this.constructor(b).find(a);
1268 if (c[1]) {
1269 if (b = b instanceof o ? b[0] : b, o.merge(this, o.parseHTML(c[1], b && b.nodeType ? b.ownerDocument || b : m, !0)), v.test(c[1]) && o.isPlainObject(b))
1270 for (c in b) o.isFunction(this[c]) ? this[c](b[c]) : this.attr(c, b[c]);
1271 return this
1272 }
1273 return d = m.getElementById(c[2]), d && d.parentNode && (this.length = 1, this[0] = d), this.context = m, this.selector = a, this
1274 }
1275 return a.nodeType ? (this.context = this[0] = a, this.length = 1, this) : o.isFunction(a) ? "undefined" != typeof y.ready ? y.ready(a) : a(o) : (void 0 !== a.selector && (this.selector = a.selector, this.context = a.context), o.makeArray(a, this))
1276 };
1277 A.prototype = o.fn, y = o(m);
1278 var B = /^(?:parents|prev(?:Until|All))/,
1279 C = {
1280 children: !0,
1281 contents: !0,
1282 next: !0,
1283 prev: !0
1284 };
1285 o.extend({
1286 dir: function(a, b, c) {
1287 var d = [],
1288 e = void 0 !== c;
1289 while ((a = a[b]) && 9 !== a.nodeType)
1290 if (1 === a.nodeType) {
1291 if (e && o(a).is(c)) break;
1292 d.push(a)
1293 }
1294 return d
1295 },
1296 sibling: function(a, b) {
1297 for (var c = []; a; a = a.nextSibling) 1 === a.nodeType && a !== b && c.push(a);
1298 return c
1299 }
1300 }), o.fn.extend({
1301 has: function(a) {
1302 var b = o(a, this),
1303 c = b.length;
1304 return this.filter(function() {
1305 for (var a = 0; c > a; a++)
1306 if (o.contains(this, b[a])) return !0
1307 })
1308 },
1309 closest: function(a, b) {
1310 for (var c, d = 0, e = this.length, f = [], g = u.test(a) || "string" != typeof a ? o(a, b || this.context) : 0; e > d; d++)
1311 for (c = this[d]; c && c !== b; c = c.parentNode)
1312 if (c.nodeType < 11 && (g ? g.index(c) > -1 : 1 === c.nodeType && o.find.matchesSelector(c, a))) {
1313 f.push(c);
1314 break
1315 }
1316 return this.pushStack(f.length > 1 ? o.unique(f) : f)
1317 },
1318 index: function(a) {
1319 return a ? "string" == typeof a ? g.call(o(a), this[0]) : g.call(this, a.jquery ? a[0] : a) : this[0] && this[0].parentNode ? this.first().prevAll().length : -1
1320 },
1321 add: function(a, b) {
1322 return this.pushStack(o.unique(o.merge(this.get(), o(a, b))))
1323 },
1324 addBack: function(a) {
1325 return this.add(null == a ? this.prevObject : this.prevObject.filter(a))
1326 }
1327 });
1328
1329 function D(a, b) {
1330 while ((a = a[b]) && 1 !== a.nodeType);
1331 return a
1332 }
1333 o.each({
1334 parent: function(a) {
1335 var b = a.parentNode;
1336 return b && 11 !== b.nodeType ? b : null
1337 },
1338 parents: function(a) {
1339 return o.dir(a, "parentNode")
1340 },
1341 parentsUntil: function(a, b, c) {
1342 return o.dir(a, "parentNode", c)
1343 },
1344 next: function(a) {
1345 return D(a, "nextSibling")
1346 },
1347 prev: function(a) {
1348 return D(a, "previousSibling")
1349 },
1350 nextAll: function(a) {
1351 return o.dir(a, "nextSibling")
1352 },
1353 prevAll: function(a) {
1354 return o.dir(a, "previousSibling")
1355 },
1356 nextUntil: function(a, b, c) {
1357 return o.dir(a, "nextSibling", c)
1358 },
1359 prevUntil: function(a, b, c) {
1360 return o.dir(a, "previousSibling", c)
1361 },
1362 siblings: function(a) {
1363 return o.sibling((a.parentNode || {}).firstChild, a)
1364 },
1365 children: function(a) {
1366 return o.sibling(a.firstChild)
1367 },
1368 contents: function(a) {
1369 return a.contentDocument || o.merge([], a.childNodes)
1370 }
1371 }, function(a, b) {
1372 o.fn[a] = function(c, d) {
1373 var e = o.map(this, b, c);
1374 return "Until" !== a.slice(-5) && (d = c), d && "string" == typeof d && (e = o.filter(d, e)), this.length > 1 && (C[a] || o.unique(e), B.test(a) && e.reverse()), this.pushStack(e)
1375 }
1376 });
1377 var E = /\S+/g,
1378 F = {};
1379
1380 function G(a) {
1381 var b = F[a] = {};
1382 return o.each(a.match(E) || [], function(a, c) {
1383 b[c] = !0
1384 }), b
1385 }
1386 o.Callbacks = function(a) {
1387 a = "string" == typeof a ? F[a] || G(a) : o.extend({}, a);
1388 var b, c, d, e, f, g, h = [],
1389 i = !a.once && [],
1390 j = function(l) {
1391 for (b = a.memory && l, c = !0, g = e || 0, e = 0, f = h.length, d = !0; h && f > g; g++)
1392 if (h[g].apply(l[0], l[1]) === !1 && a.stopOnFalse) {
1393 b = !1;
1394 break
1395 }
1396 d = !1, h && (i ? i.length && j(i.shift()) : b ? h = [] : k.disable())
1397 },
1398 k = {
1399 add: function() {
1400 if (h) {
1401 var c = h.length;
1402 ! function g(b) {
1403 o.each(b, function(b, c) {
1404 var d = o.type(c);
1405 "function" === d ? a.unique && k.has(c) || h.push(c) : c && c.length && "string" !== d && g(c)
1406 })
1407 }(arguments), d ? f = h.length : b && (e = c, j(b))
1408 }
1409 return this
1410 },
1411 remove: function() {
1412 return h && o.each(arguments, function(a, b) {
1413 var c;
1414 while ((c = o.inArray(b, h, c)) > -1) h.splice(c, 1), d && (f >= c && f--, g >= c && g--)
1415 }), this
1416 },
1417 has: function(a) {
1418 return a ? o.inArray(a, h) > -1 : !(!h || !h.length)
1419 },
1420 empty: function() {
1421 return h = [], f = 0, this
1422 },
1423 disable: function() {
1424 return h = i = b = void 0, this
1425 },
1426 disabled: function() {
1427 return !h
1428 },
1429 lock: function() {
1430 return i = void 0, b || k.disable(), this
1431 },
1432 locked: function() {
1433 return !i
1434 },
1435 fireWith: function(a, b) {
1436 return !h || c && !i || (b = b || [], b = [a, b.slice ? b.slice() : b], d ? i.push(b) : j(b)), this
1437 },
1438 fire: function() {
1439 return k.fireWith(this, arguments), this
1440 },
1441 fired: function() {
1442 return !!c
1443 }
1444 };
1445 return k
1446 }, o.extend({
1447 Deferred: function(a) {
1448 var b = [
1449 ["resolve", "done", o.Callbacks("once memory"), "resolved"],
1450 ["reject", "fail", o.Callbacks("once memory"), "rejected"],
1451 ["notify", "progress", o.Callbacks("memory")]
1452 ],
1453 c = "pending",
1454 d = {
1455 state: function() {
1456 return c
1457 },
1458 always: function() {
1459 return e.done(arguments).fail(arguments), this
1460 },
1461 then: function() {
1462 var a = arguments;
1463 return o.Deferred(function(c) {
1464 o.each(b, function(b, f) {
1465 var g = o.isFunction(a[b]) && a[b];
1466 e[f[1]](function() {
1467 var a = g && g.apply(this, arguments);
1468 a && o.isFunction(a.promise) ? a.promise().done(c.resolve).fail(c.reject).progress(c.notify) : c[f[0] + "With"](this === d ? c.promise() : this, g ? [a] : arguments)
1469 })
1470 }), a = null
1471 }).promise()
1472 },
1473 promise: function(a) {
1474 return null != a ? o.extend(a, d) : d
1475 }
1476 },
1477 e = {};
1478 return d.pipe = d.then, o.each(b, function(a, f) {
1479 var g = f[2],
1480 h = f[3];
1481 d[f[1]] = g.add, h && g.add(function() {
1482 c = h
1483 }, b[1 ^ a][2].disable, b[2][2].lock), e[f[0]] = function() {
1484 return e[f[0] + "With"](this === e ? d : this, arguments), this
1485 }, e[f[0] + "With"] = g.fireWith
1486 }), d.promise(e), a && a.call(e, e), e
1487 },
1488 when: function(a) {
1489 var b = 0,
1490 c = d.call(arguments),
1491 e = c.length,
1492 f = 1 !== e || a && o.isFunction(a.promise) ? e : 0,
1493 g = 1 === f ? a : o.Deferred(),
1494 h = function(a, b, c) {
1495 return function(e) {
1496 b[a] = this, c[a] = arguments.length > 1 ? d.call(arguments) : e, c === i ? g.notifyWith(b, c) : --f || g.resolveWith(b, c)
1497 }
1498 },
1499 i, j, k;
1500 if (e > 1)
1501 for (i = new Array(e), j = new Array(e), k = new Array(e); e > b; b++) c[b] && o.isFunction(c[b].promise) ? c[b].promise().done(h(b, k, c)).fail(g.reject).progress(h(b, j, i)) : --f;
1502 return f || g.resolveWith(k, c), g.promise()
1503 }
1504 });
1505 var H;
1506 o.fn.ready = function(a) {
1507 return o.ready.promise().done(a), this
1508 }, o.extend({
1509 isReady: !1,
1510 readyWait: 1,
1511 holdReady: function(a) {
1512 a ? o.readyWait++ : o.ready(!0)
1513 },
1514 ready: function(a) {
1515 (a === !0 ? --o.readyWait : o.isReady) || (o.isReady = !0, a !== !0 && --o.readyWait > 0 || (H.resolveWith(m, [o]), o.fn.trigger && o(m).trigger("ready").off("ready")))
1516 }
1517 });
1518
1519 function I() {
1520 m.removeEventListener("DOMContentLoaded", I, !1), a.removeEventListener("load", I, !1), o.ready()
1521 }
1522 o.ready.promise = function(b) {
1523 return H || (H = o.Deferred(), "complete" === m.readyState ? setTimeout(o.ready) : (m.addEventListener("DOMContentLoaded", I, !1), a.addEventListener("load", I, !1))), H.promise(b)
1524 }, o.ready.promise();
1525 var J = o.access = function(a, b, c, d, e, f, g) {
1526 var h = 0,
1527 i = a.length,
1528 j = null == c;
1529 if ("object" === o.type(c)) {
1530 e = !0;
1531 for (h in c) o.access(a, b, h, c[h], !0, f, g)
1532 } else if (void 0 !== d && (e = !0, o.isFunction(d) || (g = !0), j && (g ? (b.call(a, d), b = null) : (j = b, b = function(a, b, c) {
1533 return j.call(o(a), c)
1534 })), b))
1535 for (; i > h; h++) b(a[h], c, g ? d : d.call(a[h], h, b(a[h], c)));
1536 return e ? a : j ? b.call(a) : i ? b(a[0], c) : f
1537 };
1538 o.acceptData = function(a) {
1539 return 1 === a.nodeType || 9 === a.nodeType || !+a.nodeType
1540 };
1541
1542 function K() {
1543 Object.defineProperty(this.cache = {}, 0, {
1544 get: function() {
1545 return {}
1546 }
1547 }), this.expando = o.expando + Math.random()
1548 }
1549 K.uid = 1, K.accepts = o.acceptData, K.prototype = {
1550 key: function(a) {
1551 if (!K.accepts(a)) return 0;
1552 var b = {},
1553 c = a[this.expando];
1554 if (!c) {
1555 c = K.uid++;
1556 try {
1557 b[this.expando] = {
1558 value: c
1559 }, Object.defineProperties(a, b)
1560 } catch (d) {
1561 b[this.expando] = c, o.extend(a, b)
1562 }
1563 }
1564 return this.cache[c] || (this.cache[c] = {}), c
1565 },
1566 set: function(a, b, c) {
1567 var d, e = this.key(a),
1568 f = this.cache[e];
1569 if ("string" == typeof b) f[b] = c;
1570 else if (o.isEmptyObject(f)) o.extend(this.cache[e], b);
1571 else
1572 for (d in b) f[d] = b[d];
1573 return f
1574 },
1575 get: function(a, b) {
1576 var c = this.cache[this.key(a)];
1577 return void 0 === b ? c : c[b]
1578 },
1579 access: function(a, b, c) {
1580 var d;
1581 return void 0 === b || b && "string" == typeof b && void 0 === c ? (d = this.get(a, b), void 0 !== d ? d : this.get(a, o.camelCase(b))) : (this.set(a, b, c), void 0 !== c ? c : b)
1582 },
1583 remove: function(a, b) {
1584 var c, d, e, f = this.key(a),
1585 g = this.cache[f];
1586 if (void 0 === b) this.cache[f] = {};
1587 else {
1588 o.isArray(b) ? d = b.concat(b.map(o.camelCase)) : (e = o.camelCase(b), b in g ? d = [b, e] : (d = e, d = d in g ? [d] : d.match(E) || [])), c = d.length;
1589 while (c--) delete g[d[c]]
1590 }
1591 },
1592 hasData: function(a) {
1593 return !o.isEmptyObject(this.cache[a[this.expando]] || {})
1594 },
1595 discard: function(a) {
1596 a[this.expando] && delete this.cache[a[this.expando]]
1597 }
1598 };
1599 var L = new K,
1600 M = new K,
1601 N = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
1602 O = /([A-Z])/g;
1603
1604 function P(a, b, c) {
1605 var d;
1606 if (void 0 === c && 1 === a.nodeType)
1607 if (d = "data-" + b.replace(O, "-$1").toLowerCase(), c = a.getAttribute(d), "string" == typeof c) {
1608 try {
1609 c = "true" === c ? !0 : "false" === c ? !1 : "null" === c ? null : +c + "" === c ? +c : N.test(c) ? o.parseJSON(c) : c
1610 } catch (e) {}
1611 M.set(a, b, c)
1612 } else c = void 0;
1613 return c
1614 }
1615 o.extend({
1616 hasData: function(a) {
1617 return M.hasData(a) || L.hasData(a)
1618 },
1619 data: function(a, b, c) {
1620 return M.access(a, b, c)
1621 },
1622 removeData: function(a, b) {
1623 M.remove(a, b)
1624 },
1625 _data: function(a, b, c) {
1626 return L.access(a, b, c)
1627 },
1628 _removeData: function(a, b) {
1629 L.remove(a, b)
1630 }
1631 }), o.fn.extend({
1632 data: function(a, b) {
1633 var c, d, e, f = this[0],
1634 g = f && f.attributes;
1635 if (void 0 === a) {
1636 if (this.length && (e = M.get(f), 1 === f.nodeType && !L.get(f, "hasDataAttrs"))) {
1637 c = g.length;
1638 while (c--) d = g[c].name, 0 === d.indexOf("data-") && (d = o.camelCase(d.slice(5)), P(f, d, e[d]));
1639 L.set(f, "hasDataAttrs", !0)
1640 }
1641 return e
1642 }
1643 return "object" == typeof a ? this.each(function() {
1644 M.set(this, a)
1645 }) : J(this, function(b) {
1646 var c, d = o.camelCase(a);
1647 if (f && void 0 === b) {
1648 if (c = M.get(f, a), void 0 !== c) return c;
1649 if (c = M.get(f, d), void 0 !== c) return c;
1650 if (c = P(f, d, void 0), void 0 !== c) return c
1651 } else this.each(function() {
1652 var c = M.get(this, d);
1653 M.set(this, d, b), -1 !== a.indexOf("-") && void 0 !== c && M.set(this, a, b)
1654 })
1655 }, null, b, arguments.length > 1, null, !0)
1656 },
1657 removeData: function(a) {
1658 return this.each(function() {
1659 M.remove(this, a)
1660 })
1661 }
1662 }), o.extend({
1663 queue: function(a, b, c) {
1664 var d;
1665 return a ? (b = (b || "fx") + "queue", d = L.get(a, b), c && (!d || o.isArray(c) ? d = L.access(a, b, o.makeArray(c)) : d.push(c)), d || []) : void 0
1666 },
1667 dequeue: function(a, b) {
1668 b = b || "fx";
1669 var c = o.queue(a, b),
1670 d = c.length,
1671 e = c.shift(),
1672 f = o._queueHooks(a, b),
1673 g = function() {
1674 o.dequeue(a, b)
1675 };
1676 "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()
1677 },
1678 _queueHooks: function(a, b) {
1679 var c = b + "queueHooks";
1680 return L.get(a, c) || L.access(a, c, {
1681 empty: o.Callbacks("once memory").add(function() {
1682 L.remove(a, [b + "queue", c])
1683 })
1684 })
1685 }
1686 }), o.fn.extend({
1687 queue: function(a, b) {
1688 var c = 2;
1689 return "string" != typeof a && (b = a, a = "fx", c--), arguments.length < c ? o.queue(this[0], a) : void 0 === b ? this : this.each(function() {
1690 var c = o.queue(this, a, b);
1691 o._queueHooks(this, a), "fx" === a && "inprogress" !== c[0] && o.dequeue(this, a)
1692 })
1693 },
1694 dequeue: function(a) {
1695 return this.each(function() {
1696 o.dequeue(this, a)
1697 })
1698 },
1699 clearQueue: function(a) {
1700 return this.queue(a || "fx", [])
1701 },
1702 promise: function(a, b) {
1703 var c, d = 1,
1704 e = o.Deferred(),
1705 f = this,
1706 g = this.length,
1707 h = function() {
1708 --d || e.resolveWith(f, [f])
1709 };
1710 "string" != typeof a && (b = a, a = void 0), a = a || "fx";
1711 while (g--) c = L.get(f[g], a + "queueHooks"), c && c.empty && (d++, c.empty.add(h));
1712 return h(), e.promise(b)
1713 }
1714 });
1715 var Q = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
1716 R = ["Top", "Right", "Bottom", "Left"],
1717 S = function(a, b) {
1718 return a = b || a, "none" === o.css(a, "display") || !o.contains(a.ownerDocument, a)
1719 },
1720 T = /^(?:checkbox|radio)$/i;
1721 ! function() {
1722 var a = m.createDocumentFragment(),
1723 b = a.appendChild(m.createElement("div"));
1724 b.innerHTML = "<input type='radio' checked='checked' name='t'/>", l.checkClone = b.cloneNode(!0).cloneNode(!0).lastChild.checked, b.innerHTML = "<textarea>x</textarea>", l.noCloneChecked = !!b.cloneNode(!0).lastChild.defaultValue
1725 }();
1726 var U = "undefined";
1727 l.focusinBubbles = "onfocusin" in a;
1728 var V = /^key/,
1729 W = /^(?:mouse|contextmenu)|click/,
1730 X = /^(?:focusinfocus|focusoutblur)$/,
1731 Y = /^([^.]*)(?:\.(.+)|)$/;
1732
1733 function Z() {
1734 return !0
1735 }
1736
1737 function $() {
1738 return !1
1739 }
1740
1741 function _() {
1742 try {
1743 return m.activeElement
1744 } catch (a) {}
1745 }
1746 o.event = {
1747 global: {},
1748 add: function(a, b, c, d, e) {
1749 var f, g, h, i, j, k, l, m, n, p, q, r = L.get(a);
1750 if (r) {
1751 c.handler && (f = c, c = f.handler, e = f.selector), c.guid || (c.guid = o.guid++), (i = r.events) || (i = r.events = {}), (g = r.handle) || (g = r.handle = function(b) {
1752 return typeof o !== U && o.event.triggered !== b.type ? o.event.dispatch.apply(a, arguments) : void 0
1753 }), b = (b || "").match(E) || [""], j = b.length;
1754 while (j--) h = Y.exec(b[j]) || [], n = q = h[1], p = (h[2] || "").split(".").sort(), n && (l = o.event.special[n] || {}, n = (e ? l.delegateType : l.bindType) || n, l = o.event.special[n] || {}, k = o.extend({
1755 type: n,
1756 origType: q,
1757 data: d,
1758 handler: c,
1759 guid: c.guid,
1760 selector: e,
1761 needsContext: e && o.expr.match.needsContext.test(e),
1762 namespace: p.join(".")
1763 }, f), (m = i[n]) || (m = i[n] = [], m.delegateCount = 0, l.setup && l.setup.call(a, d, p, g) !== !1 || a.addEventListener && a.addEventListener(n, g, !1)), 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), o.event.global[n] = !0)
1764 }
1765 },
1766 remove: function(a, b, c, d, e) {
1767 var f, g, h, i, j, k, l, m, n, p, q, r = L.hasData(a) && L.get(a);
1768 if (r && (i = r.events)) {
1769 b = (b || "").match(E) || [""], j = b.length;
1770 while (j--)
1771 if (h = Y.exec(b[j]) || [], n = q = h[1], p = (h[2] || "").split(".").sort(), n) {
1772 l = o.event.special[n] || {}, n = (d ? l.delegateType : l.bindType) || n, m = i[n] || [], h = h[2] && new RegExp("(^|\\.)" + p.join("\\.(?:.*\\.|)") + "(\\.|$)"), g = f = m.length;
1773 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));
1774 g && !m.length && (l.teardown && l.teardown.call(a, p, r.handle) !== !1 || o.removeEvent(a, n, r.handle), delete i[n])
1775 } else
1776 for (n in i) o.event.remove(a, n + b[j], c, d, !0);
1777 o.isEmptyObject(i) && (delete r.handle, L.remove(a, "events"))
1778 }
1779 },
1780 trigger: function(b, c, d, e) {
1781 var f, g, h, i, k, l, n, p = [d || m],
1782 q = j.call(b, "type") ? b.type : b,
1783 r = j.call(b, "namespace") ? b.namespace.split(".") : [];
1784 if (g = h = d = d || m, 3 !== d.nodeType && 8 !== d.nodeType && !X.test(q + o.event.triggered) && (q.indexOf(".") >= 0 && (r = q.split("."), q = r.shift(), r.sort()), k = q.indexOf(":") < 0 && "on" + q, b = b[o.expando] ? b : new o.Event(q, "object" == typeof b && b), b.isTrigger = e ? 2 : 3, b.namespace = r.join("."), b.namespace_re = b.namespace ? new RegExp("(^|\\.)" + r.join("\\.(?:.*\\.|)") + "(\\.|$)") : null, b.result = void 0, b.target || (b.target = d), c = null == c ? [b] : o.makeArray(c, [b]), n = o.event.special[q] || {}, e || !n.trigger || n.trigger.apply(d, c) !== !1)) {
1785 if (!e && !n.noBubble && !o.isWindow(d)) {
1786 for (i = n.delegateType || q, X.test(i + q) || (g = g.parentNode); g; g = g.parentNode) p.push(g), h = g;
1787 h === (d.ownerDocument || m) && p.push(h.defaultView || h.parentWindow || a)
1788 }
1789 f = 0;
1790 while ((g = p[f++]) && !b.isPropagationStopped()) b.type = f > 1 ? i : n.bindType || q, l = (L.get(g, "events") || {})[b.type] && L.get(g, "handle"), l && l.apply(g, c), l = k && g[k], l && l.apply && o.acceptData(g) && (b.result = l.apply(g, c), b.result === !1 && b.preventDefault());
1791 return b.type = q, e || b.isDefaultPrevented() || n._default && n._default.apply(p.pop(), c) !== !1 || !o.acceptData(d) || k && o.isFunction(d[q]) && !o.isWindow(d) && (h = d[k], h && (d[k] = null), o.event.triggered = q, d[q](), o.event.triggered = void 0, h && (d[k] = h)), b.result
1792 }
1793 },
1794 dispatch: function(a) {
1795 a = o.event.fix(a);
1796 var b, c, e, f, g, h = [],
1797 i = d.call(arguments),
1798 j = (L.get(this, "events") || {})[a.type] || [],
1799 k = o.event.special[a.type] || {};
1800 if (i[0] = a, a.delegateTarget = this, !k.preDispatch || k.preDispatch.call(this, a) !== !1) {
1801 h = o.event.handlers.call(this, a, j), b = 0;
1802 while ((f = h[b++]) && !a.isPropagationStopped()) {
1803 a.currentTarget = f.elem, c = 0;
1804 while ((g = f.handlers[c++]) && !a.isImmediatePropagationStopped())(!a.namespace_re || a.namespace_re.test(g.namespace)) && (a.handleObj = g, a.data = g.data, e = ((o.event.special[g.origType] || {}).handle || g.handler).apply(f.elem, i), void 0 !== e && (a.result = e) === !1 && (a.preventDefault(), a.stopPropagation()))
1805 }
1806 return k.postDispatch && k.postDispatch.call(this, a), a.result
1807 }
1808 },
1809 handlers: function(a, b) {
1810 var c, d, e, f, g = [],
1811 h = b.delegateCount,
1812 i = a.target;
1813 if (h && i.nodeType && (!a.button || "click" !== a.type))
1814 for (; i !== this; i = i.parentNode || this)
1815 if (i.disabled !== !0 || "click" !== a.type) {
1816 for (d = [], c = 0; h > c; c++) f = b[c], e = f.selector + " ", void 0 === d[e] && (d[e] = f.needsContext ? o(e, this).index(i) >= 0 : o.find(e, this, null, [i]).length), d[e] && d.push(f);
1817 d.length && g.push({
1818 elem: i,
1819 handlers: d
1820 })
1821 }
1822 return h < b.length && g.push({
1823 elem: this,
1824 handlers: b.slice(h)
1825 }), g
1826 },
1827 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
1828 fixHooks: {},
1829 keyHooks: {
1830 props: "char charCode key keyCode".split(" "),
1831 filter: function(a, b) {
1832 return null == a.which && (a.which = null != b.charCode ? b.charCode : b.keyCode), a
1833 }
1834 },
1835 mouseHooks: {
1836 props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
1837 filter: function(a, b) {
1838 var c, d, e, f = b.button;
1839 return null == a.pageX && null != b.clientX && (c = a.target.ownerDocument || m, d = c.documentElement, e = c.body, a.pageX = b.clientX + (d && d.scrollLeft || e && e.scrollLeft || 0) - (d && d.clientLeft || e && e.clientLeft || 0), a.pageY = b.clientY + (d && d.scrollTop || e && e.scrollTop || 0) - (d && d.clientTop || e && e.clientTop || 0)), a.which || void 0 === f || (a.which = 1 & f ? 1 : 2 & f ? 3 : 4 & f ? 2 : 0), a
1840 }
1841 },
1842 fix: function(a) {
1843 if (a[o.expando]) return a;
1844 var b, c, d, e = a.type,
1845 f = a,
1846 g = this.fixHooks[e];
1847 g || (this.fixHooks[e] = g = W.test(e) ? this.mouseHooks : V.test(e) ? this.keyHooks : {}), d = g.props ? this.props.concat(g.props) : this.props, a = new o.Event(f), b = d.length;
1848 while (b--) c = d[b], a[c] = f[c];
1849 return a.target || (a.target = m), 3 === a.target.nodeType && (a.target = a.target.parentNode), g.filter ? g.filter(a, f) : a
1850 },
1851 special: {
1852 load: {
1853 noBubble: !0
1854 },
1855 focus: {
1856 trigger: function() {
1857 return this !== _() && this.focus ? (this.focus(), !1) : void 0
1858 },
1859 delegateType: "focusin"
1860 },
1861 blur: {
1862 trigger: function() {
1863 return this === _() && this.blur ? (this.blur(), !1) : void 0
1864 },
1865 delegateType: "focusout"
1866 },
1867 click: {
1868 trigger: function() {
1869 return "checkbox" === this.type && this.click && o.nodeName(this, "input") ? (this.click(), !1) : void 0
1870 },
1871 _default: function(a) {
1872 return o.nodeName(a.target, "a")
1873 }
1874 },
1875 beforeunload: {
1876 postDispatch: function(a) {
1877 void 0 !== a.result && (a.originalEvent.returnValue = a.result)
1878 }
1879 }
1880 },
1881 simulate: function(a, b, c, d) {
1882 var e = o.extend(new o.Event, c, {
1883 type: a,
1884 isSimulated: !0,
1885 originalEvent: {}
1886 });
1887 d ? o.event.trigger(e, null, b) : o.event.dispatch.call(b, e), e.isDefaultPrevented() && c.preventDefault()
1888 }
1889 }, o.removeEvent = function(a, b, c) {
1890 a.removeEventListener && a.removeEventListener(b, c, !1)
1891 }, o.Event = function(a, b) {
1892 return this instanceof o.Event ? (a && a.type ? (this.originalEvent = a, this.type = a.type, this.isDefaultPrevented = a.defaultPrevented || void 0 === a.defaultPrevented && a.getPreventDefault && a.getPreventDefault() ? Z : $) : this.type = a, b && o.extend(this, b), this.timeStamp = a && a.timeStamp || o.now(), void(this[o.expando] = !0)) : new o.Event(a, b)
1893 }, o.Event.prototype = {
1894 isDefaultPrevented: $,
1895 isPropagationStopped: $,
1896 isImmediatePropagationStopped: $,
1897 preventDefault: function() {
1898 var a = this.originalEvent;
1899 this.isDefaultPrevented = Z, a && a.preventDefault && a.preventDefault()
1900 },
1901 stopPropagation: function() {
1902 var a = this.originalEvent;
1903 this.isPropagationStopped = Z, a && a.stopPropagation && a.stopPropagation()
1904 },
1905 stopImmediatePropagation: function() {
1906 this.isImmediatePropagationStopped = Z, this.stopPropagation()
1907 }
1908 }, o.each({
1909 mouseenter: "mouseover",
1910 mouseleave: "mouseout"
1911 }, function(a, b) {
1912 o.event.special[a] = {
1913 delegateType: b,
1914 bindType: b,
1915 handle: function(a) {
1916 var c, d = this,
1917 e = a.relatedTarget,
1918 f = a.handleObj;
1919 return (!e || e !== d && !o.contains(d, e)) && (a.type = f.origType, c = f.handler.apply(this, arguments), a.type = b), c
1920 }
1921 }
1922 }), l.focusinBubbles || o.each({
1923 focus: "focusin",
1924 blur: "focusout"
1925 }, function(a, b) {
1926 var c = function(a) {
1927 o.event.simulate(b, a.target, o.event.fix(a), !0)
1928 };
1929 o.event.special[b] = {
1930 setup: function() {
1931 var d = this.ownerDocument || this,
1932 e = L.access(d, b);
1933 e || d.addEventListener(a, c, !0), L.access(d, b, (e || 0) + 1)
1934 },
1935 teardown: function() {
1936 var d = this.ownerDocument || this,
1937 e = L.access(d, b) - 1;
1938 e ? L.access(d, b, e) : (d.removeEventListener(a, c, !0), L.remove(d, b))
1939 }
1940 }
1941 }), o.fn.extend({
1942 on: function(a, b, c, d, e) {
1943 var f, g;
1944 if ("object" == typeof a) {
1945 "string" != typeof b && (c = c || b, b = void 0);
1946 for (g in a) this.on(g, b, c, a[g], e);
1947 return this
1948 }
1949 if (null == c && null == d ? (d = b, c = b = void 0) : null == d && ("string" == typeof b ? (d = c, c = void 0) : (d = c, c = b, b = void 0)), d === !1) d = $;
1950 else if (!d) return this;
1951 return 1 === e && (f = d, d = function(a) {
1952 return o().off(a), f.apply(this, arguments)
1953 }, d.guid = f.guid || (f.guid = o.guid++)), this.each(function() {
1954 o.event.add(this, a, d, c, b)
1955 })
1956 },
1957 one: function(a, b, c, d) {
1958 return this.on(a, b, c, d, 1)
1959 },
1960 off: function(a, b, c) {
1961 var d, e;
1962 if (a && a.preventDefault && a.handleObj) return d = a.handleObj, o(a.delegateTarget).off(d.namespace ? d.origType + "." + d.namespace : d.origType, d.selector, d.handler), this;
1963 if ("object" == typeof a) {
1964 for (e in a) this.off(e, b, a[e]);
1965 return this
1966 }
1967 return (b === !1 || "function" == typeof b) && (c = b, b = void 0), c === !1 && (c = $), this.each(function() {
1968 o.event.remove(this, a, c, b)
1969 })
1970 },
1971 trigger: function(a, b) {
1972 return this.each(function() {
1973 o.event.trigger(a, b, this)
1974 })
1975 },
1976 triggerHandler: function(a, b) {
1977 var c = this[0];
1978 return c ? o.event.trigger(a, b, c, !0) : void 0
1979 }
1980 });
1981 var ab = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
1982 bb = /<([\w:]+)/,
1983 cb = /<|&#?\w+;/,
1984 db = /<(?:script|style|link)/i,
1985 eb = /checked\s*(?:[^=]|=\s*.checked.)/i,
1986 fb = /^$|\/(?:java|ecma)script/i,
1987 gb = /^true\/(.*)/,
1988 hb = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
1989 ib = {
1990 option: [1, "<select multiple='multiple'>", "</select>"],
1991 thead: [1, "<table>", "</table>"],
1992 col: [2, "<table><colgroup>", "</colgroup></table>"],
1993 tr: [2, "<table><tbody>", "</tbody></table>"],
1994 td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
1995 _default: [0, "", ""]
1996 };
1997 ib.optgroup = ib.option, ib.tbody = ib.tfoot = ib.colgroup = ib.caption = ib.thead, ib.th = ib.td;
1998
1999 function jb(a, b) {
2000 return o.nodeName(a, "table") && o.nodeName(11 !== b.nodeType ? b : b.firstChild, "tr") ? a.getElementsByTagName("tbody")[0] || a.appendChild(a.ownerDocument.createElement("tbody")) : a
2001 }
2002
2003 function kb(a) {
2004 return a.type = (null !== a.getAttribute("type")) + "/" + a.type, a
2005 }
2006
2007 function lb(a) {
2008 var b = gb.exec(a.type);
2009 return b ? a.type = b[1] : a.removeAttribute("type"), a
2010 }
2011
2012 function mb(a, b) {
2013 for (var c = 0, d = a.length; d > c; c++) L.set(a[c], "globalEval", !b || L.get(b[c], "globalEval"))
2014 }
2015
2016 function nb(a, b) {
2017 var c, d, e, f, g, h, i, j;
2018 if (1 === b.nodeType) {
2019 if (L.hasData(a) && (f = L.access(a), g = L.set(b, f), j = f.events)) {
2020 delete g.handle, g.events = {};
2021 for (e in j)
2022 for (c = 0, d = j[e].length; d > c; c++) o.event.add(b, e, j[e][c])
2023 }
2024 M.hasData(a) && (h = M.access(a), i = o.extend({}, h), M.set(b, i))
2025 }
2026 }
2027
2028 function ob(a, b) {
2029 var c = a.getElementsByTagName ? a.getElementsByTagName(b || "*") : a.querySelectorAll ? a.querySelectorAll(b || "*") : [];
2030 return void 0 === b || b && o.nodeName(a, b) ? o.merge([a], c) : c
2031 }
2032
2033 function pb(a, b) {
2034 var c = b.nodeName.toLowerCase();
2035 "input" === c && T.test(a.type) ? b.checked = a.checked : ("input" === c || "textarea" === c) && (b.defaultValue = a.defaultValue)
2036 }
2037 o.extend({
2038 clone: function(a, b, c) {
2039 var d, e, f, g, h = a.cloneNode(!0),
2040 i = o.contains(a.ownerDocument, a);
2041 if (!(l.noCloneChecked || 1 !== a.nodeType && 11 !== a.nodeType || o.isXMLDoc(a)))
2042 for (g = ob(h), f = ob(a), d = 0, e = f.length; e > d; d++) pb(f[d], g[d]);
2043 if (b)
2044 if (c)
2045 for (f = f || ob(a), g = g || ob(h), d = 0, e = f.length; e > d; d++) nb(f[d], g[d]);
2046 else nb(a, h);
2047 return g = ob(h, "script"), g.length > 0 && mb(g, !i && ob(a, "script")), h
2048 },
2049 buildFragment: function(a, b, c, d) {
2050 for (var e, f, g, h, i, j, k = b.createDocumentFragment(), l = [], m = 0, n = a.length; n > m; m++)
2051 if (e = a[m], e || 0 === e)
2052 if ("object" === o.type(e)) o.merge(l, e.nodeType ? [e] : e);
2053 else if (cb.test(e)) {
2054 f = f || k.appendChild(b.createElement("div")), g = (bb.exec(e) || ["", ""])[1].toLowerCase(), h = ib[g] || ib._default, f.innerHTML = h[1] + e.replace(ab, "<$1></$2>") + h[2], j = h[0];
2055 while (j--) f = f.lastChild;
2056 o.merge(l, f.childNodes), f = k.firstChild, f.textContent = ""
2057 } else l.push(b.createTextNode(e));
2058 k.textContent = "", m = 0;
2059 while (e = l[m++])
2060 if ((!d || -1 === o.inArray(e, d)) && (i = o.contains(e.ownerDocument, e), f = ob(k.appendChild(e), "script"), i && mb(f), c)) {
2061 j = 0;
2062 while (e = f[j++]) fb.test(e.type || "") && c.push(e)
2063 }
2064 return k
2065 },
2066 cleanData: function(a) {
2067 for (var b, c, d, e, f, g, h = o.event.special, i = 0; void 0 !== (c = a[i]); i++) {
2068 if (o.acceptData(c) && (f = c[L.expando], f && (b = L.cache[f]))) {
2069 if (d = Object.keys(b.events || {}), d.length)
2070 for (g = 0; void 0 !== (e = d[g]); g++) h[e] ? o.event.remove(c, e) : o.removeEvent(c, e, b.handle);
2071 L.cache[f] && delete L.cache[f]
2072 }
2073 delete M.cache[c[M.expando]]
2074 }
2075 }
2076 }), o.fn.extend({
2077 text: function(a) {
2078 return J(this, function(a) {
2079 return void 0 === a ? o.text(this) : this.empty().each(function() {
2080 (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) && (this.textContent = a)
2081 })
2082 }, null, a, arguments.length)
2083 },
2084 append: function() {
2085 return this.domManip(arguments, function(a) {
2086 if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) {
2087 var b = jb(this, a);
2088 b.appendChild(a)
2089 }
2090 })
2091 },
2092 prepend: function() {
2093 return this.domManip(arguments, function(a) {
2094 if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) {
2095 var b = jb(this, a);
2096 b.insertBefore(a, b.firstChild)
2097 }
2098 })
2099 },
2100 before: function() {
2101 return this.domManip(arguments, function(a) {
2102 this.parentNode && this.parentNode.insertBefore(a, this)
2103 })
2104 },
2105 after: function() {
2106 return this.domManip(arguments, function(a) {
2107 this.parentNode && this.parentNode.insertBefore(a, this.nextSibling)
2108 })
2109 },
2110 remove: function(a, b) {
2111 for (var c, d = a ? o.filter(a, this) : this, e = 0; null != (c = d[e]); e++) b || 1 !== c.nodeType || o.cleanData(ob(c)), c.parentNode && (b && o.contains(c.ownerDocument, c) && mb(ob(c, "script")), c.parentNode.removeChild(c));
2112 return this
2113 },
2114 empty: function() {
2115 for (var a, b = 0; null != (a = this[b]); b++) 1 === a.nodeType && (o.cleanData(ob(a, !1)), a.textContent = "");
2116 return this
2117 },
2118 clone: function(a, b) {
2119 return a = null == a ? !1 : a, b = null == b ? a : b, this.map(function() {
2120 return o.clone(this, a, b)
2121 })
2122 },
2123 html: function(a) {
2124 return J(this, function(a) {
2125 var b = this[0] || {},
2126 c = 0,
2127 d = this.length;
2128 if (void 0 === a && 1 === b.nodeType) return b.innerHTML;
2129 if ("string" == typeof a && !db.test(a) && !ib[(bb.exec(a) || ["", ""])[1].toLowerCase()]) {
2130 a = a.replace(ab, "<$1></$2>");
2131 try {
2132 for (; d > c; c++) b = this[c] || {}, 1 === b.nodeType && (o.cleanData(ob(b, !1)), b.innerHTML = a);
2133 b = 0
2134 } catch (e) {}
2135 }
2136 b && this.empty().append(a)
2137 }, null, a, arguments.length)
2138 },
2139 replaceWith: function() {
2140 var a = arguments[0];
2141 return this.domManip(arguments, function(b) {
2142 a = this.parentNode, o.cleanData(ob(this)), a && a.replaceChild(b, this)
2143 }), a && (a.length || a.nodeType) ? this : this.remove()
2144 },
2145 detach: function(a) {
2146 return this.remove(a, !0)
2147 },
2148 domManip: function(a, b) {
2149 a = e.apply([], a);
2150 var c, d, f, g, h, i, j = 0,
2151 k = this.length,
2152 m = this,
2153 n = k - 1,
2154 p = a[0],
2155 q = o.isFunction(p);
2156 if (q || k > 1 && "string" == typeof p && !l.checkClone && eb.test(p)) return this.each(function(c) {
2157 var d = m.eq(c);
2158 q && (a[0] = p.call(this, c, d.html())), d.domManip(a, b)
2159 });
2160 if (k && (c = o.buildFragment(a, this[0].ownerDocument, !1, this), d = c.firstChild, 1 === c.childNodes.length && (c = d), d)) {
2161 for (f = o.map(ob(c, "script"), kb), g = f.length; k > j; j++) h = c, j !== n && (h = o.clone(h, !0, !0), g && o.merge(f, ob(h, "script"))), b.call(this[j], h, j);
2162 if (g)
2163 for (i = f[f.length - 1].ownerDocument, o.map(f, lb), j = 0; g > j; j++) h = f[j], fb.test(h.type || "") && !L.access(h, "globalEval") && o.contains(i, h) && (h.src ? o._evalUrl && o._evalUrl(h.src) : o.globalEval(h.textContent.replace(hb, "")))
2164 }
2165 return this
2166 }
2167 }), o.each({
2168 appendTo: "append",
2169 prependTo: "prepend",
2170 insertBefore: "before",
2171 insertAfter: "after",
2172 replaceAll: "replaceWith"
2173 }, function(a, b) {
2174 o.fn[a] = function(a) {
2175 for (var c, d = [], e = o(a), g = e.length - 1, h = 0; g >= h; h++) c = h === g ? this : this.clone(!0), o(e[h])[b](c), f.apply(d, c.get());
2176 return this.pushStack(d)
2177 }
2178 });
2179 var qb, rb = {};
2180
2181 function sb(b, c) {
2182 var d = o(c.createElement(b)).appendTo(c.body),
2183 e = a.getDefaultComputedStyle ? a.getDefaultComputedStyle(d[0]).display : o.css(d[0], "display");
2184 return d.detach(), e
2185 }
2186
2187 function tb(a) {
2188 var b = m,
2189 c = rb[a];
2190 return c || (c = sb(a, b), "none" !== c && c || (qb = (qb || o("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement), b = qb[0].contentDocument, b.write(), b.close(), c = sb(a, b), qb.detach()), rb[a] = c), c
2191 }
2192 var ub = /^margin/,
2193 vb = new RegExp("^(" + Q + ")(?!px)[a-z%]+$", "i"),
2194 wb = function(a) {
2195 return a.ownerDocument.defaultView.getComputedStyle(a, null)
2196 };
2197
2198 function xb(a, b, c) {
2199 var d, e, f, g, h = a.style;
2200 return c = c || wb(a), c && (g = c.getPropertyValue(b) || c[b]), c && ("" !== g || o.contains(a.ownerDocument, a) || (g = o.style(a, b)), vb.test(g) && ub.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
2201 }
2202
2203 function yb(a, b) {
2204 return {
2205 get: function() {
2206 return a() ? void delete this.get : (this.get = b).apply(this, arguments)
2207 }
2208 }
2209 }! function() {
2210 var b, c, d = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",
2211 e = m.documentElement,
2212 f = m.createElement("div"),
2213 g = m.createElement("div");
2214 g.style.backgroundClip = "content-box", g.cloneNode(!0).style.backgroundClip = "", l.clearCloneStyle = "content-box" === g.style.backgroundClip, f.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px", f.appendChild(g);
2215
2216 function h() {
2217 g.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%", e.appendChild(f);
2218 var d = a.getComputedStyle(g, null);
2219 b = "1%" !== d.top, c = "4px" === d.width, e.removeChild(f)
2220 }
2221 a.getComputedStyle && o.extend(l, {
2222 pixelPosition: function() {
2223 return h(), b
2224 },
2225 boxSizingReliable: function() {
2226 return null == c && h(), c
2227 },
2228 reliableMarginRight: function() {
2229 var b, c = g.appendChild(m.createElement("div"));
2230 return c.style.cssText = g.style.cssText = d, c.style.marginRight = c.style.width = "0", g.style.width = "1px", e.appendChild(f), b = !parseFloat(a.getComputedStyle(c, null).marginRight), e.removeChild(f), g.innerHTML = "", b
2231 }
2232 })
2233 }(), o.swap = function(a, b, c, d) {
2234 var e, f, g = {};
2235 for (f in b) g[f] = a.style[f], a.style[f] = b[f];
2236 e = c.apply(a, d || []);
2237 for (f in b) a.style[f] = g[f];
2238 return e
2239 };
2240 var zb = /^(none|table(?!-c[ea]).+)/,
2241 Ab = new RegExp("^(" + Q + ")(.*)$", "i"),
2242 Bb = new RegExp("^([+-])=(" + Q + ")", "i"),
2243 Cb = {
2244 position: "absolute",
2245 visibility: "hidden",
2246 display: "block"
2247 },
2248 Db = {
2249 letterSpacing: 0,
2250 fontWeight: 400
2251 },
2252 Eb = ["Webkit", "O", "Moz", "ms"];
2253
2254 function Fb(a, b) {
2255 if (b in a) return b;
2256 var c = b[0].toUpperCase() + b.slice(1),
2257 d = b,
2258 e = Eb.length;
2259 while (e--)
2260 if (b = Eb[e] + c, b in a) return b;
2261 return d
2262 }
2263
2264 function Gb(a, b, c) {
2265 var d = Ab.exec(b);
2266 return d ? Math.max(0, d[1] - (c || 0)) + (d[2] || "px") : b
2267 }
2268
2269 function Hb(a, b, c, d, e) {
2270 for (var f = c === (d ? "border" : "content") ? 4 : "width" === b ? 1 : 0, g = 0; 4 > f; f += 2) "margin" === c && (g += o.css(a, c + R[f], !0, e)), d ? ("content" === c && (g -= o.css(a, "padding" + R[f], !0, e)), "margin" !== c && (g -= o.css(a, "border" + R[f] + "Width", !0, e))) : (g += o.css(a, "padding" + R[f], !0, e), "padding" !== c && (g += o.css(a, "border" + R[f] + "Width", !0, e)));
2271 return g
2272 }
2273
2274 function Ib(a, b, c) {
2275 var d = !0,
2276 e = "width" === b ? a.offsetWidth : a.offsetHeight,
2277 f = wb(a),
2278 g = "border-box" === o.css(a, "boxSizing", !1, f);
2279 if (0 >= e || null == e) {
2280 if (e = xb(a, b, f), (0 > e || null == e) && (e = a.style[b]), vb.test(e)) return e;
2281 d = g && (l.boxSizingReliable() || e === a.style[b]), e = parseFloat(e) || 0
2282 }
2283 return e + Hb(a, b, c || (g ? "border" : "content"), d, f) + "px"
2284 }
2285
2286 function Jb(a, b) {
2287 for (var c, d, e, f = [], g = 0, h = a.length; h > g; g++) d = a[g], d.style && (f[g] = L.get(d, "olddisplay"), c = d.style.display, b ? (f[g] || "none" !== c || (d.style.display = ""), "" === d.style.display && S(d) && (f[g] = L.access(d, "olddisplay", tb(d.nodeName)))) : f[g] || (e = S(d), (c && "none" !== c || !e) && L.set(d, "olddisplay", e ? c : o.css(d, "display"))));
2288 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"));
2289 return a
2290 }
2291 o.extend({
2292 cssHooks: {
2293 opacity: {
2294 get: function(a, b) {
2295 if (b) {
2296 var c = xb(a, "opacity");
2297 return "" === c ? "1" : c
2298 }
2299 }
2300 }
2301 },
2302 cssNumber: {
2303 columnCount: !0,
2304 fillOpacity: !0,
2305 fontWeight: !0,
2306 lineHeight: !0,
2307 opacity: !0,
2308 order: !0,
2309 orphans: !0,
2310 widows: !0,
2311 zIndex: !0,
2312 zoom: !0
2313 },
2314 cssProps: {
2315 "float": "cssFloat"
2316 },
2317 style: function(a, b, c, d) {
2318 if (a && 3 !== a.nodeType && 8 !== a.nodeType && a.style) {
2319 var e, f, g, h = o.camelCase(b),
2320 i = a.style;
2321 return b = o.cssProps[h] || (o.cssProps[h] = Fb(i, h)), g = o.cssHooks[b] || o.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 = Bb.exec(c)) && (c = (e[1] + 1) * e[2] + parseFloat(o.css(a, b)), f = "number"), null != c && c === c && ("number" !== f || o.cssNumber[h] || (c += "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] = "", i[b] = c)), void 0)
2322 }
2323 },
2324 css: function(a, b, c, d) {
2325 var e, f, g, h = o.camelCase(b);
2326 return b = o.cssProps[h] || (o.cssProps[h] = Fb(a.style, h)), g = o.cssHooks[b] || o.cssHooks[h], g && "get" in g && (e = g.get(a, !0, c)), void 0 === e && (e = xb(a, b, d)), "normal" === e && b in Db && (e = Db[b]), "" === c || c ? (f = parseFloat(e), c === !0 || o.isNumeric(f) ? f || 0 : e) : e
2327 }
2328 }), o.each(["height", "width"], function(a, b) {
2329 o.cssHooks[b] = {
2330 get: function(a, c, d) {
2331 return c ? 0 === a.offsetWidth && zb.test(o.css(a, "display")) ? o.swap(a, Cb, function() {
2332 return Ib(a, b, d)
2333 }) : Ib(a, b, d) : void 0
2334 },
2335 set: function(a, c, d) {
2336 var e = d && wb(a);
2337 return Gb(a, c, d ? Hb(a, b, d, "border-box" === o.css(a, "boxSizing", !1, e), e) : 0)
2338 }
2339 }
2340 }), o.cssHooks.marginRight = yb(l.reliableMarginRight, function(a, b) {
2341 return b ? o.swap(a, {
2342 display: "inline-block"
2343 }, xb, [a, "marginRight"]) : void 0
2344 }), o.each({
2345 margin: "",
2346 padding: "",
2347 border: "Width"
2348 }, function(a, b) {
2349 o.cssHooks[a + b] = {
2350 expand: function(c) {
2351 for (var d = 0, e = {}, f = "string" == typeof c ? c.split(" ") : [c]; 4 > d; d++) e[a + R[d] + b] = f[d] || f[d - 2] || f[0];
2352 return e
2353 }
2354 }, ub.test(a) || (o.cssHooks[a + b].set = Gb)
2355 }), o.fn.extend({
2356 css: function(a, b) {
2357 return J(this, function(a, b, c) {
2358 var d, e, f = {},
2359 g = 0;
2360 if (o.isArray(b)) {
2361 for (d = wb(a), e = b.length; e > g; g++) f[b[g]] = o.css(a, b[g], !1, d);
2362 return f
2363 }
2364 return void 0 !== c ? o.style(a, b, c) : o.css(a, b)
2365 }, a, b, arguments.length > 1)
2366 },
2367 show: function() {
2368 return Jb(this, !0)
2369 },
2370 hide: function() {
2371 return Jb(this)
2372 },
2373 toggle: function(a) {
2374 return "boolean" == typeof a ? a ? this.show() : this.hide() : this.each(function() {
2375 S(this) ? o(this).show() : o(this).hide()
2376 })
2377 }
2378 });
2379
2380 function Kb(a, b, c, d, e) {
2381 return new Kb.prototype.init(a, b, c, d, e)
2382 }
2383 o.Tween = Kb, Kb.prototype = {
2384 constructor: Kb,
2385 init: function(a, b, c, d, e, f) {
2386 this.elem = a, this.prop = c, this.easing = e || "swing", this.options = b, this.start = this.now = this.cur(), this.end = d, this.unit = f || (o.cssNumber[c] ? "" : "px")
2387 },
2388 cur: function() {
2389 var a = Kb.propHooks[this.prop];
2390 return a && a.get ? a.get(this) : Kb.propHooks._default.get(this)
2391 },
2392 run: function(a) {
2393 var b, c = Kb.propHooks[this.prop];
2394 return this.pos = b = this.options.duration ? o.easing[this.easing](a, this.options.duration * a, 0, 1, this.options.duration) : 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) : Kb.propHooks._default.set(this), this
2395 }
2396 }, Kb.prototype.init.prototype = Kb.prototype, Kb.propHooks = {
2397 _default: {
2398 get: function(a) {
2399 var b;
2400 return null == a.elem[a.prop] || a.elem.style && null != a.elem.style[a.prop] ? (b = o.css(a.elem, a.prop, ""), b && "auto" !== b ? b : 0) : a.elem[a.prop]
2401 },
2402 set: function(a) {
2403 o.fx.step[a.prop] ? o.fx.step[a.prop](a) : a.elem.style && (null != a.elem.style[o.cssProps[a.prop]] || o.cssHooks[a.prop]) ? o.style(a.elem, a.prop, a.now + a.unit) : a.elem[a.prop] = a.now
2404 }
2405 }
2406 }, Kb.propHooks.scrollTop = Kb.propHooks.scrollLeft = {
2407 set: function(a) {
2408 a.elem.nodeType && a.elem.parentNode && (a.elem[a.prop] = a.now)
2409 }
2410 }, o.easing = {
2411 linear: function(a) {
2412 return a
2413 },
2414 swing: function(a) {
2415 return .5 - Math.cos(a * Math.PI) / 2
2416 }
2417 }, o.fx = Kb.prototype.init, o.fx.step = {};
2418 var Lb, Mb, Nb = /^(?:toggle|show|hide)$/,
2419 Ob = new RegExp("^(?:([+-])=|)(" + Q + ")([a-z%]*)$", "i"),
2420 Pb = /queueHooks$/,
2421 Qb = [Vb],
2422 Rb = {
2423 "*": [function(a, b) {
2424 var c = this.createTween(a, b),
2425 d = c.cur(),
2426 e = Ob.exec(b),
2427 f = e && e[3] || (o.cssNumber[a] ? "" : "px"),
2428 g = (o.cssNumber[a] || "px" !== f && +d) && Ob.exec(o.css(c.elem, a)),
2429 h = 1,
2430 i = 20;
2431 if (g && g[3] !== f) {
2432 f = f || g[3], e = e || [], g = +d || 1;
2433 do h = h || ".5", g /= h, o.style(c.elem, a, g + f); while (h !== (h = c.cur() / d) && 1 !== h && --i)
2434 }
2435 return e && (g = c.start = +g || +d || 0, c.unit = f, c.end = e[1] ? g + (e[1] + 1) * e[2] : +e[2]), c
2436 }]
2437 };
2438
2439 function Sb() {
2440 return setTimeout(function() {
2441 Lb = void 0
2442 }), Lb = o.now()
2443 }
2444
2445 function Tb(a, b) {
2446 var c, d = 0,
2447 e = {
2448 height: a
2449 };
2450 for (b = b ? 1 : 0; 4 > d; d += 2 - b) c = R[d], e["margin" + c] = e["padding" + c] = a;
2451 return b && (e.opacity = e.width = a), e
2452 }
2453
2454 function Ub(a, b, c) {
2455 for (var d, e = (Rb[b] || []).concat(Rb["*"]), f = 0, g = e.length; g > f; f++)
2456 if (d = e[f].call(c, b, a)) return d
2457 }
2458
2459 function Vb(a, b, c) {
2460 var d, e, f, g, h, i, j, k = this,
2461 l = {},
2462 m = a.style,
2463 n = a.nodeType && S(a),
2464 p = L.get(a, "fxshow");
2465 c.queue || (h = o._queueHooks(a, "fx"), null == h.unqueued && (h.unqueued = 0, i = h.empty.fire, h.empty.fire = function() {
2466 h.unqueued || i()
2467 }), h.unqueued++, k.always(function() {
2468 k.always(function() {
2469 h.unqueued--, o.queue(a, "fx").length || h.empty.fire()
2470 })
2471 })), 1 === a.nodeType && ("height" in b || "width" in b) && (c.overflow = [m.overflow, m.overflowX, m.overflowY], j = o.css(a, "display"), "none" === j && (j = tb(a.nodeName)), "inline" === j && "none" === o.css(a, "float") && (m.display = "inline-block")), c.overflow && (m.overflow = "hidden", k.always(function() {
2472 m.overflow = c.overflow[0], m.overflowX = c.overflow[1], m.overflowY = c.overflow[2]
2473 }));
2474 for (d in b)
2475 if (e = b[d], Nb.exec(e)) {
2476 if (delete b[d], f = f || "toggle" === e, e === (n ? "hide" : "show")) {
2477 if ("show" !== e || !p || void 0 === p[d]) continue;
2478 n = !0
2479 }
2480 l[d] = p && p[d] || o.style(a, d)
2481 }
2482 if (!o.isEmptyObject(l)) {
2483 p ? "hidden" in p && (n = p.hidden) : p = L.access(a, "fxshow", {}), f && (p.hidden = !n), n ? o(a).show() : k.done(function() {
2484 o(a).hide()
2485 }), k.done(function() {
2486 var b;
2487 L.remove(a, "fxshow");
2488 for (b in l) o.style(a, b, l[b])
2489 });
2490 for (d in l) g = Ub(n ? p[d] : 0, d, k), d in p || (p[d] = g.start, n && (g.end = g.start, g.start = "width" === d || "height" === d ? 1 : 0))
2491 }
2492 }
2493
2494 function Wb(a, b) {
2495 var c, d, e, f, g;
2496 for (c in a)
2497 if (d = o.camelCase(c), e = b[d], f = a[c], o.isArray(f) && (e = f[1], f = a[c] = f[0]), c !== d && (a[d] = f, delete a[c]), g = o.cssHooks[d], g && "expand" in g) {
2498 f = g.expand(f), delete a[d];
2499 for (c in f) c in a || (a[c] = f[c], b[c] = e)
2500 } else b[d] = e
2501 }
2502
2503 function Xb(a, b, c) {
2504 var d, e, f = 0,
2505 g = Qb.length,
2506 h = o.Deferred().always(function() {
2507 delete i.elem
2508 }),
2509 i = function() {
2510 if (e) return !1;
2511 for (var b = Lb || Sb(), 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);
2512 return h.notifyWith(a, [j, f, c]), 1 > f && i ? c : (h.resolveWith(a, [j]), !1)
2513 },
2514 j = h.promise({
2515 elem: a,
2516 props: o.extend({}, b),
2517 opts: o.extend(!0, {
2518 specialEasing: {}
2519 }, c),
2520 originalProperties: b,
2521 originalOptions: c,
2522 startTime: Lb || Sb(),
2523 duration: c.duration,
2524 tweens: [],
2525 createTween: function(b, c) {
2526 var d = o.Tween(a, j.opts, b, c, j.opts.specialEasing[b] || j.opts.easing);
2527 return j.tweens.push(d), d
2528 },
2529 stop: function(b) {
2530 var c = 0,
2531 d = b ? j.tweens.length : 0;
2532 if (e) return this;
2533 for (e = !0; d > c; c++) j.tweens[c].run(1);
2534 return b ? h.resolveWith(a, [j, b]) : h.rejectWith(a, [j, b]), this
2535 }
2536 }),
2537 k = j.props;
2538 for (Wb(k, j.opts.specialEasing); g > f; f++)
2539 if (d = Qb[f].call(j, a, k, j.opts)) return d;
2540 return o.map(k, Ub, j), o.isFunction(j.opts.start) && j.opts.start.call(a, j), o.fx.timer(o.extend(i, {
2541 elem: a,
2542 anim: j,
2543 queue: j.opts.queue
2544 })), j.progress(j.opts.progress).done(j.opts.done, j.opts.complete).fail(j.opts.fail).always(j.opts.always)
2545 }
2546 o.Animation = o.extend(Xb, {
2547 tweener: function(a, b) {
2548 o.isFunction(a) ? (b = a, a = ["*"]) : a = a.split(" ");
2549 for (var c, d = 0, e = a.length; e > d; d++) c = a[d], Rb[c] = Rb[c] || [], Rb[c].unshift(b)
2550 },
2551 prefilter: function(a, b) {
2552 b ? Qb.unshift(a) : Qb.push(a)
2553 }
2554 }), o.speed = function(a, b, c) {
2555 var d = a && "object" == typeof a ? o.extend({}, a) : {
2556 complete: c || !c && b || o.isFunction(a) && a,
2557 duration: a,
2558 easing: c && b || b && !o.isFunction(b) && b
2559 };
2560 return d.duration = o.fx.off ? 0 : "number" == typeof d.duration ? d.duration : d.duration in o.fx.speeds ? o.fx.speeds[d.duration] : o.fx.speeds._default, (null == d.queue || d.queue === !0) && (d.queue = "fx"), d.old = d.complete, d.complete = function() {
2561 o.isFunction(d.old) && d.old.call(this), d.queue && o.dequeue(this, d.queue)
2562 }, d
2563 }, o.fn.extend({
2564 fadeTo: function(a, b, c, d) {
2565 return this.filter(S).css("opacity", 0).show().end().animate({
2566 opacity: b
2567 }, a, c, d)
2568 },
2569 animate: function(a, b, c, d) {
2570 var e = o.isEmptyObject(a),
2571 f = o.speed(b, c, d),
2572 g = function() {
2573 var b = Xb(this, o.extend({}, a), f);
2574 (e || L.get(this, "finish")) && b.stop(!0)
2575 };
2576 return g.finish = g, e || f.queue === !1 ? this.each(g) : this.queue(f.queue, g)
2577 },
2578 stop: function(a, b, c) {
2579 var d = function(a) {
2580 var b = a.stop;
2581 delete a.stop, b(c)
2582 };
2583 return "string" != typeof a && (c = b, b = a, a = void 0), b && a !== !1 && this.queue(a || "fx", []), this.each(function() {
2584 var b = !0,
2585 e = null != a && a + "queueHooks",
2586 f = o.timers,
2587 g = L.get(this);
2588 if (e) g[e] && g[e].stop && d(g[e]);
2589 else
2590 for (e in g) g[e] && g[e].stop && Pb.test(e) && d(g[e]);
2591 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));
2592 (b || !c) && o.dequeue(this, a)
2593 })
2594 },
2595 finish: function(a) {
2596 return a !== !1 && (a = a || "fx"), this.each(function() {
2597 var b, c = L.get(this),
2598 d = c[a + "queue"],
2599 e = c[a + "queueHooks"],
2600 f = o.timers,
2601 g = d ? d.length : 0;
2602 for (c.finish = !0, o.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));
2603 for (b = 0; g > b; b++) d[b] && d[b].finish && d[b].finish.call(this);
2604 delete c.finish
2605 })
2606 }
2607 }), o.each(["toggle", "show", "hide"], function(a, b) {
2608 var c = o.fn[b];
2609 o.fn[b] = function(a, d, e) {
2610 return null == a || "boolean" == typeof a ? c.apply(this, arguments) : this.animate(Tb(b, !0), a, d, e)
2611 }
2612 }), o.each({
2613 slideDown: Tb("show"),
2614 slideUp: Tb("hide"),
2615 slideToggle: Tb("toggle"),
2616 fadeIn: {
2617 opacity: "show"
2618 },
2619 fadeOut: {
2620 opacity: "hide"
2621 },
2622 fadeToggle: {
2623 opacity: "toggle"
2624 }
2625 }, function(a, b) {
2626 o.fn[a] = function(a, c, d) {
2627 return this.animate(b, a, c, d)
2628 }
2629 }), o.timers = [], o.fx.tick = function() {
2630 var a, b = 0,
2631 c = o.timers;
2632 for (Lb = o.now(); b < c.length; b++) a = c[b], a() || c[b] !== a || c.splice(b--, 1);
2633 c.length || o.fx.stop(), Lb = void 0
2634 }, o.fx.timer = function(a) {
2635 o.timers.push(a), a() ? o.fx.start() : o.timers.pop()
2636 }, o.fx.interval = 13, o.fx.start = function() {
2637 Mb || (Mb = setInterval(o.fx.tick, o.fx.interval))
2638 }, o.fx.stop = function() {
2639 clearInterval(Mb), Mb = null
2640 }, o.fx.speeds = {
2641 slow: 600,
2642 fast: 200,
2643 _default: 400
2644 }, o.fn.delay = function(a, b) {
2645 return a = o.fx ? o.fx.speeds[a] || a : a, b = b || "fx", this.queue(b, function(b, c) {
2646 var d = setTimeout(b, a);
2647 c.stop = function() {
2648 clearTimeout(d)
2649 }
2650 })
2651 },
2652 function() {
2653 var a = m.createElement("input"),
2654 b = m.createElement("select"),
2655 c = b.appendChild(m.createElement("option"));
2656 a.type = "checkbox", l.checkOn = "" !== a.value, l.optSelected = c.selected, b.disabled = !0, l.optDisabled = !c.disabled, a = m.createElement("input"), a.value = "t", a.type = "radio", l.radioValue = "t" === a.value
2657 }();
2658 var Yb, Zb, $b = o.expr.attrHandle;
2659 o.fn.extend({
2660 attr: function(a, b) {
2661 return J(this, o.attr, a, b, arguments.length > 1)
2662 },
2663 removeAttr: function(a) {
2664 return this.each(function() {
2665 o.removeAttr(this, a)
2666 })
2667 }
2668 }), o.extend({
2669 attr: function(a, b, c) {
2670 var d, e, f = a.nodeType;
2671 if (a && 3 !== f && 8 !== f && 2 !== f) return typeof a.getAttribute === U ? o.prop(a, b, c) : (1 === f && o.isXMLDoc(a) || (b = b.toLowerCase(), d = o.attrHooks[b] || (o.expr.match.bool.test(b) ? Zb : Yb)), void 0 === c ? d && "get" in d && null !== (e = d.get(a, b)) ? e : (e = o.find.attr(a, b), null == e ? void 0 : e) : null !== c ? d && "set" in d && void 0 !== (e = d.set(a, c, b)) ? e : (a.setAttribute(b, c + ""), c) : void o.removeAttr(a, b))
2672 },
2673 removeAttr: function(a, b) {
2674 var c, d, e = 0,
2675 f = b && b.match(E);
2676 if (f && 1 === a.nodeType)
2677 while (c = f[e++]) d = o.propFix[c] || c, o.expr.match.bool.test(c) && (a[d] = !1), a.removeAttribute(c)
2678 },
2679 attrHooks: {
2680 type: {
2681 set: function(a, b) {
2682 if (!l.radioValue && "radio" === b && o.nodeName(a, "input")) {
2683 var c = a.value;
2684 return a.setAttribute("type", b), c && (a.value = c), b
2685 }
2686 }
2687 }
2688 }
2689 }), Zb = {
2690 set: function(a, b, c) {
2691 return b === !1 ? o.removeAttr(a, c) : a.setAttribute(c, c), c
2692 }
2693 }, o.each(o.expr.match.bool.source.match(/\w+/g), function(a, b) {
2694 var c = $b[b] || o.find.attr;
2695 $b[b] = function(a, b, d) {
2696 var e, f;
2697 return d || (f = $b[b], $b[b] = e, e = null != c(a, b, d) ? b.toLowerCase() : null, $b[b] = f), e
2698 }
2699 });
2700 var _b = /^(?:input|select|textarea|button)$/i;
2701 o.fn.extend({
2702 prop: function(a, b) {
2703 return J(this, o.prop, a, b, arguments.length > 1)
2704 },
2705 removeProp: function(a) {
2706 return this.each(function() {
2707 delete this[o.propFix[a] || a]
2708 })
2709 }
2710 }), o.extend({
2711 propFix: {
2712 "for": "htmlFor",
2713 "class": "className"
2714 },
2715 prop: function(a, b, c) {
2716 var d, e, f, g = a.nodeType;
2717 if (a && 3 !== g && 8 !== g && 2 !== g) return f = 1 !== g || !o.isXMLDoc(a), f && (b = o.propFix[b] || b, e = o.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]
2718 },
2719 propHooks: {
2720 tabIndex: {
2721 get: function(a) {
2722 return a.hasAttribute("tabindex") || _b.test(a.nodeName) || a.href ? a.tabIndex : -1
2723 }
2724 }
2725 }
2726 }), l.optSelected || (o.propHooks.selected = {
2727 get: function(a) {
2728 var b = a.parentNode;
2729 return b && b.parentNode && b.parentNode.selectedIndex, null
2730 }
2731 }), o.each(["tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable"], function() {
2732 o.propFix[this.toLowerCase()] = this
2733 });
2734 var ac = /[\t\r\n\f]/g;
2735 o.fn.extend({
2736 addClass: function(a) {
2737 var b, c, d, e, f, g, h = "string" == typeof a && a,
2738 i = 0,
2739 j = this.length;
2740 if (o.isFunction(a)) return this.each(function(b) {
2741 o(this).addClass(a.call(this, b, this.className))
2742 });
2743 if (h)
2744 for (b = (a || "").match(E) || []; j > i; i++)
2745 if (c = this[i], d = 1 === c.nodeType && (c.className ? (" " + c.className + " ").replace(ac, " ") : " ")) {
2746 f = 0;
2747 while (e = b[f++]) d.indexOf(" " + e + " ") < 0 && (d += e + " ");
2748 g = o.trim(d), c.className !== g && (c.className = g)
2749 }
2750 return this
2751 },
2752 removeClass: function(a) {
2753 var b, c, d, e, f, g, h = 0 === arguments.length || "string" == typeof a && a,
2754 i = 0,
2755 j = this.length;
2756 if (o.isFunction(a)) return this.each(function(b) {
2757 o(this).removeClass(a.call(this, b, this.className))
2758 });
2759 if (h)
2760 for (b = (a || "").match(E) || []; j > i; i++)
2761 if (c = this[i], d = 1 === c.nodeType && (c.className ? (" " + c.className + " ").replace(ac, " ") : "")) {
2762 f = 0;
2763 while (e = b[f++])
2764 while (d.indexOf(" " + e + " ") >= 0) d = d.replace(" " + e + " ", " ");
2765 g = a ? o.trim(d) : "", c.className !== g && (c.className = g)
2766 }
2767 return this
2768 },
2769 toggleClass: function(a, b) {
2770 var c = typeof a;
2771 return "boolean" == typeof b && "string" === c ? b ? this.addClass(a) : this.removeClass(a) : this.each(o.isFunction(a) ? function(c) {
2772 o(this).toggleClass(a.call(this, c, this.className, b), b)
2773 } : function() {
2774 if ("string" === c) {
2775 var b, d = 0,
2776 e = o(this),
2777 f = a.match(E) || [];
2778 while (b = f[d++]) e.hasClass(b) ? e.removeClass(b) : e.addClass(b)
2779 } else(c === U || "boolean" === c) && (this.className && L.set(this, "__className__", this.className), this.className = this.className || a === !1 ? "" : L.get(this, "__className__") || "")
2780 })
2781 },
2782 hasClass: function(a) {
2783 for (var b = " " + a + " ", c = 0, d = this.length; d > c; c++)
2784 if (1 === this[c].nodeType && (" " + this[c].className + " ").replace(ac, " ").indexOf(b) >= 0) return !0;
2785 return !1
2786 }
2787 });
2788 var bc = /\r/g;
2789 o.fn.extend({
2790 val: function(a) {
2791 var b, c, d, e = this[0]; {
2792 if (arguments.length) return d = o.isFunction(a), this.each(function(c) {
2793 var e;
2794 1 === this.nodeType && (e = d ? a.call(this, c, o(this).val()) : a, null == e ? e = "" : "number" == typeof e ? e += "" : o.isArray(e) && (e = o.map(e, function(a) {
2795 return null == a ? "" : a + ""
2796 })), b = o.valHooks[this.type] || o.valHooks[this.nodeName.toLowerCase()], b && "set" in b && void 0 !== b.set(this, e, "value") || (this.value = e))
2797 });
2798 if (e) return b = o.valHooks[e.type] || o.valHooks[e.nodeName.toLowerCase()], b && "get" in b && void 0 !== (c = b.get(e, "value")) ? c : (c = e.value, "string" == typeof c ? c.replace(bc, "") : null == c ? "" : c)
2799 }
2800 }
2801 }), o.extend({
2802 valHooks: {
2803 select: {
2804 get: function(a) {
2805 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++)
2806 if (c = d[i], !(!c.selected && i !== e || (l.optDisabled ? c.disabled : null !== c.getAttribute("disabled")) || c.parentNode.disabled && o.nodeName(c.parentNode, "optgroup"))) {
2807 if (b = o(c).val(), f) return b;
2808 g.push(b)
2809 }
2810 return g
2811 },
2812 set: function(a, b) {
2813 var c, d, e = a.options,
2814 f = o.makeArray(b),
2815 g = e.length;
2816 while (g--) d = e[g], (d.selected = o.inArray(o(d).val(), f) >= 0) && (c = !0);
2817 return c || (a.selectedIndex = -1), f
2818 }
2819 }
2820 }
2821 }), o.each(["radio", "checkbox"], function() {
2822 o.valHooks[this] = {
2823 set: function(a, b) {
2824 return o.isArray(b) ? a.checked = o.inArray(o(a).val(), b) >= 0 : void 0
2825 }
2826 }, l.checkOn || (o.valHooks[this].get = function(a) {
2827 return null === a.getAttribute("value") ? "on" : a.value
2828 })
2829 }), o.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) {
2830 o.fn[b] = function(a, c) {
2831 return arguments.length > 0 ? this.on(b, null, a, c) : this.trigger(b)
2832 }
2833 }), o.fn.extend({
2834 hover: function(a, b) {
2835 return this.mouseenter(a).mouseleave(b || a)
2836 },
2837 bind: function(a, b, c) {
2838 return this.on(a, null, b, c)
2839 },
2840 unbind: function(a, b) {
2841 return this.off(a, null, b)
2842 },
2843 delegate: function(a, b, c, d) {
2844 return this.on(b, a, c, d)
2845 },
2846 undelegate: function(a, b, c) {
2847 return 1 === arguments.length ? this.off(a, "**") : this.off(b, a || "**", c)
2848 }
2849 });
2850 var cc = o.now(),
2851 dc = /\?/;
2852 o.parseJSON = function(a) {
2853 return JSON.parse(a + "")
2854 }, o.parseXML = function(a) {
2855 var b, c;
2856 if (!a || "string" != typeof a) return null;
2857 try {
2858 c = new DOMParser, b = c.parseFromString(a, "text/xml")
2859 } catch (d) {
2860 b = void 0
2861 }
2862 return (!b || b.getElementsByTagName("parsererror").length) && o.error("Invalid XML: " + a), b
2863 };
2864 var ec, fc, gc = /#.*$/,
2865 hc = /([?&])_=[^&]*/,
2866 ic = /^(.*?):[ \t]*([^\r\n]*)$/gm,
2867 jc = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
2868 kc = /^(?:GET|HEAD)$/,
2869 lc = /^\/\//,
2870 mc = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
2871 nc = {},
2872 oc = {},
2873 pc = "*/".concat("*");
2874 try {
2875 fc = location.href
2876 } catch (qc) {
2877 fc = m.createElement("a"), fc.href = "", fc = fc.href
2878 }
2879 ec = mc.exec(fc.toLowerCase()) || [];
2880
2881 function rc(a) {
2882 return function(b, c) {
2883 "string" != typeof b && (c = b, b = "*");
2884 var d, e = 0,
2885 f = b.toLowerCase().match(E) || [];
2886 if (o.isFunction(c))
2887 while (d = f[e++]) "+" === d[0] ? (d = d.slice(1) || "*", (a[d] = a[d] || []).unshift(c)) : (a[d] = a[d] || []).push(c)
2888 }
2889 }
2890
2891 function sc(a, b, c, d) {
2892 var e = {},
2893 f = a === oc;
2894
2895 function g(h) {
2896 var i;
2897 return e[h] = !0, o.each(a[h] || [], function(a, h) {
2898 var j = h(b, c, d);
2899 return "string" != typeof j || f || e[j] ? f ? !(i = j) : void 0 : (b.dataTypes.unshift(j), g(j), !1)
2900 }), i
2901 }
2902 return g(b.dataTypes[0]) || !e["*"] && g("*")
2903 }
2904
2905 function tc(a, b) {
2906 var c, d, e = o.ajaxSettings.flatOptions || {};
2907 for (c in b) void 0 !== b[c] && ((e[c] ? a : d || (d = {}))[c] = b[c]);
2908 return d && o.extend(!0, a, d), a
2909 }
2910
2911 function uc(a, b, c) {
2912 var d, e, f, g, h = a.contents,
2913 i = a.dataTypes;
2914 while ("*" === i[0]) i.shift(), void 0 === d && (d = a.mimeType || b.getResponseHeader("Content-Type"));
2915 if (d)
2916 for (e in h)
2917 if (h[e] && h[e].test(d)) {
2918 i.unshift(e);
2919 break
2920 }
2921 if (i[0] in c) f = i[0];
2922 else {
2923 for (e in c) {
2924 if (!i[0] || a.converters[e + " " + i[0]]) {
2925 f = e;
2926 break
2927 }
2928 g || (g = e)
2929 }
2930 f = f || g
2931 }
2932 return f ? (f !== i[0] && i.unshift(f), c[f]) : void 0
2933 }
2934
2935 function vc(a, b, c, d) {
2936 var e, f, g, h, i, j = {},
2937 k = a.dataTypes.slice();
2938 if (k[1])
2939 for (g in a.converters) j[g.toLowerCase()] = a.converters[g];
2940 f = k.shift();
2941 while (f)
2942 if (a.responseFields[f] && (c[a.responseFields[f]] = b), !i && d && a.dataFilter && (b = a.dataFilter(b, a.dataType)), i = f, f = k.shift())
2943 if ("*" === f) f = i;
2944 else if ("*" !== i && i !== f) {
2945 if (g = j[i + " " + f] || j["* " + f], !g)
2946 for (e in j)
2947 if (h = e.split(" "), h[1] === f && (g = j[i + " " + h[0]] || j["* " + h[0]])) {
2948 g === !0 ? g = j[e] : j[e] !== !0 && (f = h[0], k.unshift(h[1]));
2949 break
2950 }
2951 if (g !== !0)
2952 if (g && a["throws"]) b = g(b);
2953 else try {
2954 b = g(b)
2955 } catch (l) {
2956 return {
2957 state: "parsererror",
2958 error: g ? l : "No conversion from " + i + " to " + f
2959 }
2960 }
2961 }
2962 return {
2963 state: "success",
2964 data: b
2965 }
2966 }
2967 o.extend({
2968 active: 0,
2969 lastModified: {},
2970 etag: {},
2971 ajaxSettings: {
2972 url: fc,
2973 type: "GET",
2974 isLocal: jc.test(ec[1]),
2975 global: !0,
2976 processData: !0,
2977 async: !0,
2978 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
2979 accepts: {
2980 "*": pc,
2981 text: "text/plain",
2982 html: "text/html",
2983 xml: "application/xml, text/xml",
2984 json: "application/json, text/javascript"
2985 },
2986 contents: {
2987 xml: /xml/,
2988 html: /html/,
2989 json: /json/
2990 },
2991 responseFields: {
2992 xml: "responseXML",
2993 text: "responseText",
2994 json: "responseJSON"
2995 },
2996 converters: {
2997 "* text": String,
2998 "text html": !0,
2999 "text json": o.parseJSON,
3000 "text xml": o.parseXML
3001 },
3002 flatOptions: {
3003 url: !0,
3004 context: !0
3005 }
3006 },
3007 ajaxSetup: function(a, b) {
3008 return b ? tc(tc(a, o.ajaxSettings), b) : tc(o.ajaxSettings, a)
3009 },
3010 ajaxPrefilter: rc(nc),
3011 ajaxTransport: rc(oc),
3012 ajax: function(a, b) {
3013 "object" == typeof a && (b = a, a = void 0), b = b || {};
3014 var c, d, e, f, g, h, i, j, k = o.ajaxSetup({}, b),
3015 l = k.context || k,
3016 m = k.context && (l.nodeType || l.jquery) ? o(l) : o.event,
3017 n = o.Deferred(),
3018 p = o.Callbacks("once memory"),
3019 q = k.statusCode || {},
3020 r = {},
3021 s = {},
3022 t = 0,
3023 u = "canceled",
3024 v = {
3025 readyState: 0,
3026 getResponseHeader: function(a) {
3027 var b;
3028 if (2 === t) {
3029 if (!f) {
3030 f = {};
3031 while (b = ic.exec(e)) f[b[1].toLowerCase()] = b[2]
3032 }
3033 b = f[a.toLowerCase()]
3034 }
3035 return null == b ? null : b
3036 },
3037 getAllResponseHeaders: function() {
3038 return 2 === t ? e : null
3039 },
3040 setRequestHeader: function(a, b) {
3041 var c = a.toLowerCase();
3042 return t || (a = s[c] = s[c] || a, r[a] = b), this
3043 },
3044 overrideMimeType: function(a) {
3045 return t || (k.mimeType = a), this
3046 },
3047 statusCode: function(a) {
3048 var b;
3049 if (a)
3050 if (2 > t)
3051 for (b in a) q[b] = [q[b], a[b]];
3052 else v.always(a[v.status]);
3053 return this
3054 },
3055 abort: function(a) {
3056 var b = a || u;
3057 return c && c.abort(b), x(0, b), this
3058 }
3059 };
3060 if (n.promise(v).complete = p.add, v.success = v.done, v.error = v.fail, k.url = ((a || k.url || fc) + "").replace(gc, "").replace(lc, ec[1] + "//"), k.type = b.method || b.type || k.method || k.type, k.dataTypes = o.trim(k.dataType || "*").toLowerCase().match(E) || [""], null == k.crossDomain && (h = mc.exec(k.url.toLowerCase()), k.crossDomain = !(!h || h[1] === ec[1] && h[2] === ec[2] && (h[3] || ("http:" === h[1] ? "80" : "443")) === (ec[3] || ("http:" === ec[1] ? "80" : "443")))), k.data && k.processData && "string" != typeof k.data && (k.data = o.param(k.data, k.traditional)), sc(nc, k, b, v), 2 === t) return v;
3061 i = k.global, i && 0 === o.active++ && o.event.trigger("ajaxStart"), k.type = k.type.toUpperCase(), k.hasContent = !kc.test(k.type), d = k.url, k.hasContent || (k.data && (d = k.url += (dc.test(d) ? "&" : "?") + k.data, delete k.data), k.cache === !1 && (k.url = hc.test(d) ? d.replace(hc, "$1_=" + cc++) : d + (dc.test(d) ? "&" : "?") + "_=" + cc++)), k.ifModified && (o.lastModified[d] && v.setRequestHeader("If-Modified-Since", o.lastModified[d]), o.etag[d] && v.setRequestHeader("If-None-Match", o.etag[d])), (k.data && k.hasContent && k.contentType !== !1 || b.contentType) && v.setRequestHeader("Content-Type", k.contentType), v.setRequestHeader("Accept", k.dataTypes[0] && k.accepts[k.dataTypes[0]] ? k.accepts[k.dataTypes[0]] + ("*" !== k.dataTypes[0] ? ", " + pc + "; q=0.01" : "") : k.accepts["*"]);
3062 for (j in k.headers) v.setRequestHeader(j, k.headers[j]);
3063 if (k.beforeSend && (k.beforeSend.call(l, v, k) === !1 || 2 === t)) return v.abort();
3064 u = "abort";
3065 for (j in {
3066 success: 1,
3067 error: 1,
3068 complete: 1
3069 }) v[j](k[j]);
3070 if (c = sc(oc, k, b, v)) {
3071 v.readyState = 1, i && m.trigger("ajaxSend", [v, k]), k.async && k.timeout > 0 && (g = setTimeout(function() {
3072 v.abort("timeout")
3073 }, k.timeout));
3074 try {
3075 t = 1, c.send(r, x)
3076 } catch (w) {
3077 if (!(2 > t)) throw w;
3078 x(-1, w)
3079 }
3080 } else x(-1, "No Transport");
3081
3082 function x(a, b, f, h) {
3083 var j, r, s, u, w, x = b;
3084 2 !== t && (t = 2, g && clearTimeout(g), c = void 0, e = h || "", v.readyState = a > 0 ? 4 : 0, j = a >= 200 && 300 > a || 304 === a, f && (u = uc(k, v, f)), u = vc(k, u, v, j), j ? (k.ifModified && (w = v.getResponseHeader("Last-Modified"), w && (o.lastModified[d] = w), w = v.getResponseHeader("etag"), w && (o.etag[d] = w)), 204 === a || "HEAD" === k.type ? x = "nocontent" : 304 === a ? x = "notmodified" : (x = u.state, r = u.data, s = u.error, j = !s)) : (s = x, (a || !x) && (x = "error", 0 > a && (a = 0))), v.status = a, v.statusText = (b || x) + "", j ? n.resolveWith(l, [r, x, v]) : n.rejectWith(l, [v, x, s]), v.statusCode(q), q = void 0, i && m.trigger(j ? "ajaxSuccess" : "ajaxError", [v, k, j ? r : s]), p.fireWith(l, [v, x]), i && (m.trigger("ajaxComplete", [v, k]), --o.active || o.event.trigger("ajaxStop")))
3085 }
3086 return v
3087 },
3088 getJSON: function(a, b, c) {
3089 return o.get(a, b, c, "json")
3090 },
3091 getScript: function(a, b) {
3092 return o.get(a, void 0, b, "script")
3093 }
3094 }), o.each(["get", "post"], function(a, b) {
3095 o[b] = function(a, c, d, e) {
3096 return o.isFunction(c) && (e = e || d, d = c, c = void 0), o.ajax({
3097 url: a,
3098 type: b,
3099 dataType: e,
3100 data: c,
3101 success: d
3102 })
3103 }
3104 }), o.each(["ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend"], function(a, b) {
3105 o.fn[b] = function(a) {
3106 return this.on(b, a)
3107 }
3108 }), o._evalUrl = function(a) {
3109 return o.ajax({
3110 url: a,
3111 type: "GET",
3112 dataType: "script",
3113 async: !1,
3114 global: !1,
3115 "throws": !0
3116 })
3117 }, o.fn.extend({
3118 wrapAll: function(a) {
3119 var b;
3120 return o.isFunction(a) ? this.each(function(b) {
3121 o(this).wrapAll(a.call(this, b))
3122 }) : (this[0] && (b = o(a, this[0].ownerDocument).eq(0).clone(!0), this[0].parentNode && b.insertBefore(this[0]), b.map(function() {
3123 var a = this;
3124 while (a.firstElementChild) a = a.firstElementChild;
3125 return a
3126 }).append(this)), this)
3127 },
3128 wrapInner: function(a) {
3129 return this.each(o.isFunction(a) ? function(b) {
3130 o(this).wrapInner(a.call(this, b))
3131 } : function() {
3132 var b = o(this),
3133 c = b.contents();
3134 c.length ? c.wrapAll(a) : b.append(a)
3135 })
3136 },
3137 wrap: function(a) {
3138 var b = o.isFunction(a);
3139 return this.each(function(c) {
3140 o(this).wrapAll(b ? a.call(this, c) : a)
3141 })
3142 },
3143 unwrap: function() {
3144 return this.parent().each(function() {
3145 o.nodeName(this, "body") || o(this).replaceWith(this.childNodes)
3146 }).end()
3147 }
3148 }), o.expr.filters.hidden = function(a) {
3149 return a.offsetWidth <= 0 && a.offsetHeight <= 0
3150 }, o.expr.filters.visible = function(a) {
3151 return !o.expr.filters.hidden(a)
3152 };
3153 var wc = /%20/g,
3154 xc = /\[\]$/,
3155 yc = /\r?\n/g,
3156 zc = /^(?:submit|button|image|reset|file)$/i,
3157 Ac = /^(?:input|select|textarea|keygen)/i;
3158
3159 function Bc(a, b, c, d) {
3160 var e;
3161 if (o.isArray(b)) o.each(b, function(b, e) {
3162 c || xc.test(a) ? d(a, e) : Bc(a + "[" + ("object" == typeof e ? b : "") + "]", e, c, d)
3163 });
3164 else if (c || "object" !== o.type(b)) d(a, b);
3165 else
3166 for (e in b) Bc(a + "[" + e + "]", b[e], c, d)
3167 }
3168 o.param = function(a, b) {
3169 var c, d = [],
3170 e = function(a, b) {
3171 b = o.isFunction(b) ? b() : null == b ? "" : b, d[d.length] = encodeURIComponent(a) + "=" + encodeURIComponent(b)
3172 };
3173 if (void 0 === b && (b = o.ajaxSettings && o.ajaxSettings.traditional), o.isArray(a) || a.jquery && !o.isPlainObject(a)) o.each(a, function() {
3174 e(this.name, this.value)
3175 });
3176 else
3177 for (c in a) Bc(c, a[c], b, e);
3178 return d.join("&").replace(wc, "+")
3179 }, o.fn.extend({
3180 serialize: function() {
3181 return o.param(this.serializeArray())
3182 },
3183 serializeArray: function() {
3184 return this.map(function() {
3185 var a = o.prop(this, "elements");
3186 return a ? o.makeArray(a) : this
3187 }).filter(function() {
3188 var a = this.type;
3189 return this.name && !o(this).is(":disabled") && Ac.test(this.nodeName) && !zc.test(a) && (this.checked || !T.test(a))
3190 }).map(function(a, b) {
3191 var c = o(this).val();
3192 return null == c ? null : o.isArray(c) ? o.map(c, function(a) {
3193 return {
3194 name: b.name,
3195 value: a.replace(yc, "\r\n")
3196 }
3197 }) : {
3198 name: b.name,
3199 value: c.replace(yc, "\r\n")
3200 }
3201 }).get()
3202 }
3203 }), o.ajaxSettings.xhr = function() {
3204 try {
3205 return new XMLHttpRequest
3206 } catch (a) {}
3207 };
3208 var Cc = 0,
3209 Dc = {},
3210 Ec = {
3211 0: 200,
3212 1223: 204
3213 },
3214 Fc = o.ajaxSettings.xhr();
3215 a.ActiveXObject && o(a).on("unload", function() {
3216 for (var a in Dc) Dc[a]()
3217 }), l.cors = !!Fc && "withCredentials" in Fc, l.ajax = Fc = !!Fc, o.ajaxTransport(function(a) {
3218 var b;
3219 return l.cors || Fc && !a.crossDomain ? {
3220 send: function(c, d) {
3221 var e, f = a.xhr(),
3222 g = ++Cc;
3223 if (f.open(a.type, a.url, a.async, a.username, a.password), a.xhrFields)
3224 for (e in a.xhrFields) f[e] = a.xhrFields[e];
3225 a.mimeType && f.overrideMimeType && f.overrideMimeType(a.mimeType), a.crossDomain || c["X-Requested-With"] || (c["X-Requested-With"] = "XMLHttpRequest");
3226 for (e in c) f.setRequestHeader(e, c[e]);
3227 b = function(a) {
3228 return function() {
3229 b && (delete Dc[g], b = f.onload = f.onerror = null, "abort" === a ? f.abort() : "error" === a ? d(f.status, f.statusText) : d(Ec[f.status] || f.status, f.statusText, "string" == typeof f.responseText ? {
3230 text: f.responseText
3231 } : void 0, f.getAllResponseHeaders()))
3232 }
3233 }, f.onload = b(), f.onerror = b("error"), b = Dc[g] = b("abort"), f.send(a.hasContent && a.data || null)
3234 },
3235 abort: function() {
3236 b && b()
3237 }
3238 } : void 0
3239 }), o.ajaxSetup({
3240 accepts: {
3241 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
3242 },
3243 contents: {
3244 script: /(?:java|ecma)script/
3245 },
3246 converters: {
3247 "text script": function(a) {
3248 return o.globalEval(a), a
3249 }
3250 }
3251 }), o.ajaxPrefilter("script", function(a) {
3252 void 0 === a.cache && (a.cache = !1), a.crossDomain && (a.type = "GET")
3253 }), o.ajaxTransport("script", function(a) {
3254 if (a.crossDomain) {
3255 var b, c;
3256 return {
3257 send: function(d, e) {
3258 b = o("<script>").prop({
3259 async: !0,
3260 charset: a.scriptCharset,
3261 src: a.url
3262 }).on("load error", c = function(a) {
3263 b.remove(), c = null, a && e("error" === a.type ? 404 : 200, a.type)
3264 }), m.head.appendChild(b[0])
3265 },
3266 abort: function() {
3267 c && c()
3268 }
3269 }
3270 }
3271 });
3272 var Gc = [],
3273 Hc = /(=)\?(?=&|$)|\?\?/;
3274 o.ajaxSetup({
3275 jsonp: "callback",
3276 jsonpCallback: function() {
3277 var a = Gc.pop() || o.expando + "_" + cc++;
3278 return this[a] = !0, a
3279 }
3280 }), o.ajaxPrefilter("json jsonp", function(b, c, d) {
3281 var e, f, g, h = b.jsonp !== !1 && (Hc.test(b.url) ? "url" : "string" == typeof b.data && !(b.contentType || "").indexOf("application/x-www-form-urlencoded") && Hc.test(b.data) && "data");
3282 return h || "jsonp" === b.dataTypes[0] ? (e = b.jsonpCallback = o.isFunction(b.jsonpCallback) ? b.jsonpCallback() : b.jsonpCallback, h ? b[h] = b[h].replace(Hc, "$1" + e) : b.jsonp !== !1 && (b.url += (dc.test(b.url) ? "&" : "?") + b.jsonp + "=" + e), b.converters["script json"] = function() {
3283 return g || o.error(e + " was not called"), g[0]
3284 }, b.dataTypes[0] = "json", f = a[e], a[e] = function() {
3285 g = arguments
3286 }, d.always(function() {
3287 a[e] = f, b[e] && (b.jsonpCallback = c.jsonpCallback, Gc.push(e)), g && o.isFunction(f) && f(g[0]), g = f = void 0
3288 }), "script") : void 0
3289 }), o.parseHTML = function(a, b, c) {
3290 if (!a || "string" != typeof a) return null;
3291 "boolean" == typeof b && (c = b, b = !1), b = b || m;
3292 var d = v.exec(a),
3293 e = !c && [];
3294 return d ? [b.createElement(d[1])] : (d = o.buildFragment([a], b, e), e && e.length && o(e).remove(), o.merge([], d.childNodes))
3295 };
3296 var Ic = o.fn.load;
3297 o.fn.load = function(a, b, c) {
3298 if ("string" != typeof a && Ic) return Ic.apply(this, arguments);
3299 var d, e, f, g = this,
3300 h = a.indexOf(" ");
3301 return h >= 0 && (d = a.slice(h), a = a.slice(0, h)), o.isFunction(b) ? (c = b, b = void 0) : b && "object" == typeof b && (e = "POST"), g.length > 0 && o.ajax({
3302 url: a,
3303 type: e,
3304 dataType: "html",
3305 data: b
3306 }).done(function(a) {
3307 f = arguments, g.html(d ? o("<div>").append(o.parseHTML(a)).find(d) : a)
3308 }).complete(c && function(a, b) {
3309 g.each(c, f || [a.responseText, b, a])
3310 }), this
3311 }, o.expr.filters.animated = function(a) {
3312 return o.grep(o.timers, function(b) {
3313 return a === b.elem
3314 }).length
3315 };
3316 var Jc = a.document.documentElement;
3317
3318 function Kc(a) {
3319 return o.isWindow(a) ? a : 9 === a.nodeType && a.defaultView
3320 }
3321 o.offset = {
3322 setOffset: function(a, b, c) {
3323 var d, e, f, g, h, i, j, k = o.css(a, "position"),
3324 l = o(a),
3325 m = {};
3326 "static" === k && (a.style.position = "relative"), h = l.offset(), f = o.css(a, "top"), i = o.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), o.isFunction(b) && (b = b.call(a, c, 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)
3327 }
3328 }, o.fn.extend({
3329 offset: function(a) {
3330 if (arguments.length) return void 0 === a ? this : this.each(function(b) {
3331 o.offset.setOffset(this, a, b)
3332 });
3333 var b, c, d = this[0],
3334 e = {
3335 top: 0,
3336 left: 0
3337 },
3338 f = d && d.ownerDocument;
3339 if (f) return b = f.documentElement, o.contains(b, d) ? (typeof d.getBoundingClientRect !== U && (e = d.getBoundingClientRect()), c = Kc(f), {
3340 top: e.top + c.pageYOffset - b.clientTop,
3341 left: e.left + c.pageXOffset - b.clientLeft
3342 }) : e
3343 },
3344 position: function() {
3345 if (this[0]) {
3346 var a, b, c = this[0],
3347 d = {
3348 top: 0,
3349 left: 0
3350 };
3351 return "fixed" === o.css(c, "position") ? b = c.getBoundingClientRect() : (a = this.offsetParent(), b = this.offset(), o.nodeName(a[0], "html") || (d = a.offset()), d.top += o.css(a[0], "borderTopWidth", !0), d.left += o.css(a[0], "borderLeftWidth", !0)), {
3352 top: b.top - d.top - o.css(c, "marginTop", !0),
3353 left: b.left - d.left - o.css(c, "marginLeft", !0)
3354 }
3355 }
3356 },
3357 offsetParent: function() {
3358 return this.map(function() {
3359 var a = this.offsetParent || Jc;
3360 while (a && !o.nodeName(a, "html") && "static" === o.css(a, "position")) a = a.offsetParent;
3361 return a || Jc
3362 })
3363 }
3364 }), o.each({
3365 scrollLeft: "pageXOffset",
3366 scrollTop: "pageYOffset"
3367 }, function(b, c) {
3368 var d = "pageYOffset" === c;
3369 o.fn[b] = function(e) {
3370 return J(this, function(b, e, f) {
3371 var g = Kc(b);
3372 return void 0 === f ? g ? g[c] : b[e] : void(g ? g.scrollTo(d ? a.pageXOffset : f, d ? f : a.pageYOffset) : b[e] = f)
3373 }, b, e, arguments.length, null)
3374 }
3375 }), o.each(["top", "left"], function(a, b) {
3376 o.cssHooks[b] = yb(l.pixelPosition, function(a, c) {
3377 return c ? (c = xb(a, b), vb.test(c) ? o(a).position()[b] + "px" : c) : void 0
3378 })
3379 }), o.each({
3380 Height: "height",
3381 Width: "width"
3382 }, function(a, b) {
3383 o.each({
3384 padding: "inner" + a,
3385 content: b,
3386 "": "outer" + a
3387 }, function(c, d) {
3388 o.fn[d] = function(d, e) {
3389 var f = arguments.length && (c || "boolean" != typeof d),
3390 g = c || (d === !0 || e === !0 ? "margin" : "border");
3391 return J(this, function(b, c, d) {
3392 var e;
3393 return o.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 ? o.css(b, c, g) : o.style(b, c, d, g)
3394 }, b, f ? d : void 0, f, null)
3395 }
3396 })
3397 }), o.fn.size = function() {
3398 return this.length
3399 }, o.fn.andSelf = o.fn.addBack, "function" == typeof define && define.amd && define("jquery", [], function() {
3400 return o
3401 });
3402 var Lc = a.jQuery,
3403 Mc = a.$;
3404 return o.noConflict = function(b) {
3405 return a.$ === o && (a.$ = Mc), b && a.jQuery === o && (a.jQuery = Lc), o
3406 }, typeof b === U && (a.jQuery = a.$ = o), o
3407});
3408"use strict";
3409String.prototype.shorten = function(maxLength) {
3410 return this.length > maxLength ? (this.substr(0, maxLength - 2) + '\u2026') : this.valueOf();
3411};
3412String.prototype.shortenMid = function(maxLength) {
3413 return this.length > maxLength ? (this.substr(0, maxLength * 0.33) + '\u2026' + this.substr(-maxLength * 0.66)) : this.valueOf();
3414};
3415String.prototype.escape = function() {
3416 return this.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
3417};
3418String.prototype.possessive = function() {
3419 return this.match(/s$/i) ? this.valueOf() + "'" : this.valueOf() + "'s";
3420};
3421String.prototype.inflect = function(count, p, s) {
3422 var name = this;
3423 if (count != 1 && count != -1) {
3424 return count + ' ' + name + (p || 'e');
3425 }
3426 return count + ' ' + name + (s || '');
3427};
3428String.prototype.inflectNoCount = function(count, p) {
3429 var name = this;
3430 if (count != 1 && count != -1) {
3431 return name + (p || 'e');
3432 }
3433 return name;
3434};
3435String.prototype.hostName = function() {
3436 var m = this.match(/\/\/(www\.)?(.*?)\//);
3437 return m && m[2] ? m[2] : 'unknown';
3438};
3439String.prototype.newlineToHTML = function() {
3440 return this.replace(/\n\s+\n/g, '<br/><br/>').replace(/\n/g, '<br/>');
3441};
3442String.prototype.urlsToHTML = function(maxLength) {
3443 return this.replace(/\b(https?:\/\/(?:www\.)?|www\.)([^\s()<>]+(?:\([\w\d]+\)|([^,\.\(\)<>!?\s]|\/)))/g, function(url, httpwww, hostandpath) {
3444 if (httpwww === 'www.') {
3445 url = 'http://' + url;
3446 }
3447 url = url.replace(/@/g, '@');
3448 hostandpath = hostandpath.replace(/@/g, '@');
3449 var path = null;
3450 if (path = hostandpath.match(new RegExp('^' + CONFIG.HOST + '(/.*?)$'))) {
3451 return '<a href="' + path[1] + '">' + path[1] + '</a>';
3452 } else {
3453 return '<a href="' + url + '">' + hostandpath.shortenMid(maxLength) + '</a>';
3454 }
3455 });
3456};
3457String.prototype.setQueryParameter = function(key, value) {
3458 var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
3459 var separator = this.indexOf('?') !== -1 ? "&" : "?";
3460 if (this.match(re)) {
3461 return this.replace(re, '$1' + key + "=" + value + '$2');
3462 } else {
3463 return this + separator + key + "=" + value;
3464 }
3465};
3466String.prototype.userAtToHTML = function(maxLength) {
3467 return this.replace(/(?!\b)(@([a-zA-Z0-9]{2,}))/g, '<a href="/user/$2">$1</a>');
3468};
3469String.prototype.format = function() {
3470 return this.escape().newlineToHTML().urlsToHTML(80).userAtToHTML();
3471};
3472"use strict";
3473Date.RELATIVE_TIME_PERIODS = {
3474 Jahr: 31536000,
3475 Monat: 2628000,
3476 Woche: 604800,
3477 Tag: 86400,
3478 Stunde: 3600,
3479 Minute: 60,
3480 Moment: -1
3481};
3482Date.now = Date.now || function() {
3483 return (new Date()).getTime();
3484};
3485Date.secondsToString = function(rawSeconds) {
3486 var days = Math.floor(rawSeconds / (60 * 60 * 24));
3487 var hours = Math.floor((rawSeconds % (60 * 60 * 24)) / (60 * 60));
3488 var minutes = Math.floor((rawSeconds % (60 * 60)) / 60);
3489 var seconds = rawSeconds % 60;
3490 return days + " Tag(e), " + hours + " Stunde(n), " + minutes + " Minute(n), " + seconds + " Sekunde(n)";
3491};
3492Date.prototype.unix = function() {
3493 return Math.floor(this.getTime() / 1000);
3494};
3495Date.prototype.relativeTime = function(forcePast, noprefix) {
3496 var diff = (new Date()).getTime() / 1000 - this.getTime() / 1000;
3497 if (forcePast && diff < 0) {
3498 diff = 0;
3499 }
3500 var prefix = noprefix ? '' : (diff >= 0) ? "vor " : "in ";
3501 diff = Math.abs(diff);
3502 for (var period in Date.RELATIVE_TIME_PERIODS) {
3503 var length = Date.RELATIVE_TIME_PERIODS[period];
3504 if (diff > length) {
3505 if (length > 0) {
3506 diff = Math.round(diff / length);
3507 var plural = diff > 1 ? (period.substr(-1) == 'e' ? 'n' : 'en') : '';
3508 return prefix + diff + " " + period + plural;
3509 } else {
3510 return prefix + "einem Moment";
3511 }
3512 }
3513 }
3514 return false;
3515};
3516Date.MONTH_NAMES = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];
3517Date.prototype.readableTime = function() {
3518 var h = this.getHours();
3519 var m = this.getMinutes();
3520 return this.getDate() + ". " +
3521 Date.MONTH_NAMES[this.getMonth()] + " " +
3522 this.getFullYear() + " - " +
3523 (h > 9 ? h : '0' + h) + ":" + (m > 9 ? m : '0' + m);
3524};
3525Date.prototype.readableDate = function() {
3526 return this.getDate() + ". " +
3527 Date.MONTH_NAMES[this.getMonth()] + " " +
3528 this.getFullYear();
3529};
3530"use strict"
3531Number.prototype.map = function(istart, istop, ostart, ostop) {
3532 return ostart + (ostop - ostart) * ((this - istart) / (istop - istart));
3533};
3534Number.prototype.limit = function(min, max) {
3535 return Math.min(max, Math.max(min, this));
3536};
3537Number.prototype.round = function(precision) {
3538 precision = Math.pow(10, precision || 0);
3539 return Math.round(this * precision) / precision;
3540};
3541Number.prototype.floor = function() {
3542 return Math.floor(this);
3543};
3544Number.prototype.ceil = function() {
3545 return Math.ceil(this);
3546};
3547Number.prototype.toInt = function() {
3548 return (this | 0);
3549};
3550Number.zeroes = '000000000000';
3551Number.prototype.zeroFill = function(d) {
3552 var s = this.toString();
3553 return Number.zeroes.substr(0, d - s.length) + s;
3554};
3555"use strict";
3556Array.prototype.erase = function(item) {
3557 for (var i = this.length; i--;) {
3558 if (this[i] === item) {
3559 this.splice(i, 1);
3560 }
3561 }
3562 return this;
3563};
3564Array.prototype.random = function() {
3565 return this[Math.floor(Math.random() * this.length)];
3566};
3567Array.prototype.shuffle = function() {
3568 for (var j, x, i = this.length; i; j = Math.floor(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
3569 return this;
3570};
3571[].indexOf || (Array.prototype.indexOf = function(a, b, c) {
3572 for (c = this.length, b = (c + ~~b) % c; b < c && (!(b in this) || this[b] !== a); b++);
3573 return b ^ c ? b : -1;
3574});
3575Array.prototype.first = function() {
3576 return this.length ? this[0] : null;
3577};
3578Array.prototype.last = function() {
3579 return this.length ? this[this.length - 1] : null;
3580};
3581"use strict";
3582Function.prototype.bind = Function.prototype.bind || function(bind) {
3583 if (typeof this !== "function") {
3584 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
3585 }
3586 var aArgs = Array.prototype.slice.call(arguments, 1),
3587 fToBind = this,
3588 fNOP = function() {},
3589 fBound = function() {
3590 return fToBind.apply((this instanceof fNOP && oThis ? this : oThis), aArgs.concat(Array.prototype.slice.call(arguments)));
3591 };
3592 fNOP.prototype = this.prototype;
3593 fBound.prototype = new fNOP();
3594 return fBound;
3595};
3596"use strict";
3597p.isNormalClick = function(ev) {
3598 return (ev.type != 'click' || !(ev.which != 1 || ev.shiftKey || ev.altKey || ev.metaKey || ev.ctrlKey));
3599};
3600p.KEY = {
3601 'BACKSPACE': 8,
3602 'TAB': 9,
3603 'ENTER': 13,
3604 'PAUSE': 19,
3605 'CAPS': 20,
3606 'ESC': 27,
3607 'SPACE': 32,
3608 'PAGE_UP': 33,
3609 'PAGE_DOWN': 34,
3610 'END': 35,
3611 'HOME': 36,
3612 'LEFT_ARROW': 37,
3613 'UP_ARROW': 38,
3614 'RIGHT_ARROW': 39,
3615 'DOWN_ARROW': 40,
3616 'INSERT': 45,
3617 'DELETE': 46,
3618 '0': 48,
3619 '1': 49,
3620 '2': 50,
3621 '3': 51,
3622 '4': 52,
3623 '5': 53,
3624 '6': 54,
3625 '7': 55,
3626 '8': 56,
3627 '9': 57,
3628 'A': 65,
3629 'B': 66,
3630 'C': 67,
3631 'D': 68,
3632 'E': 69,
3633 'F': 70,
3634 'G': 71,
3635 'H': 72,
3636 'I': 73,
3637 'J': 74,
3638 'K': 75,
3639 'L': 76,
3640 'M': 77,
3641 'N': 78,
3642 'O': 79,
3643 'P': 80,
3644 'Q': 81,
3645 'R': 82,
3646 'S': 83,
3647 'T': 84,
3648 'U': 85,
3649 'V': 86,
3650 'W': 87,
3651 'X': 88,
3652 'Y': 89,
3653 'Z': 90,
3654 'NUMPAD_0': 96,
3655 'NUMPAD_1': 97,
3656 'NUMPAD_2': 98,
3657 'NUMPAD_3': 99,
3658 'NUMPAD_4': 100,
3659 'NUMPAD_5': 101,
3660 'NUMPAD_6': 102,
3661 'NUMPAD_7': 103,
3662 'NUMPAD_8': 104,
3663 'NUMPAD_9': 105,
3664 'MULTIPLY': 106,
3665 'ADD': 107,
3666 'SUBTRACT': 109,
3667 'DECIMAL': 110,
3668 'DIVIDE': 111,
3669 'F1': 112,
3670 'F2': 113,
3671 'F3': 114,
3672 'F4': 115,
3673 'F5': 116,
3674 'F6': 117,
3675 'F7': 118,
3676 'F8': 119,
3677 'F9': 120,
3678 'F10': 121,
3679 'F11': 122,
3680 'F12': 123,
3681 'SHIFT': 16,
3682 'CTRL': 17,
3683 'ALT': 18,
3684 'PLUS': 187,
3685 'COMMA': 188,
3686 'MINUS': 189,
3687 'PERIOD': 190
3688};
3689(function($) {
3690 var FastClick = function(el, callback) {
3691 this.element = el;
3692 this.callback = callback;
3693 this.sx = this.sy = 0;
3694 this.scroll = 0;
3695 this.element.addEventListener('touchstart', this, false);
3696 };
3697 var noClickUntil = 0;
3698 FastClick.prototype = {
3699 handleEvent: function(e) {
3700 switch (e.type) {
3701 case 'touchstart':
3702 this.onTouchStart(e);
3703 break;
3704 case 'touchend':
3705 this.onTouchEnd(e);
3706 break;
3707 }
3708 },
3709 onTouchStart: function(e) {
3710 this.start = Date.now();
3711 this.sx = e.touches[0].pageX - document.body.scrollTop;
3712 this.sy = e.touches[0].pageY - document.body.scrollLeft;
3713 this.scroll = document.body.scrollTop;
3714 this.element.addEventListener('touchend', this, false);
3715 noClickUntil = 0;
3716 },
3717 onTouchEnd: function(e) {
3718 this.element.removeEventListener('touchend', this, false);
3719 var cx = e.changedTouches[0].pageX - document.body.scrollTop,
3720 cy = e.changedTouches[0].pageY - document.body.scrollLeft;
3721 var dx = this.sx - cx,
3722 dy = this.sy - cy,
3723 scrolled = (this.scroll != document.body.scrollTop),
3724 maxMove = 32,
3725 maxTime = 300;
3726 if (!scrolled && Math.abs(dx) < maxMove && Math.abs(dy) < maxMove && (Date.now() - this.start) < maxTime) {
3727 e.preventDefault();
3728 e.stopPropagation();
3729 noClickUntil = Date.now() + 1000;
3730 return this.callback(e);
3731 }
3732 }
3733 };
3734 $.fn.fastclick = function(callback) {
3735 if (p.mobile && window.Touch) {
3736 for (var i = 0; i < this.length; i++) {
3737 new FastClick(this[i], callback);
3738 }
3739 this.click(function(e) {
3740 if (noClickUntil < Date.now()) {
3741 return callback(e);
3742 } else {
3743 return false;
3744 }
3745 });
3746 } else {
3747 this.click(callback);
3748 }
3749 return this;
3750 };
3751})(jQuery);
3752(function(window) {
3753 var host = 'pr0gramm.com';
3754 var useSubdomains = true;
3755 window.CONFIG = {
3756 READ_ONLY: false,
3757 HOST: host,
3758 ABSOLUTE_PATH: '/',
3759 HEADER_HEIGHT: 52,
3760 COOKIE: {
3761 NAME: 'me',
3762 EXPIRE: 3650
3763 },
3764 PATH: {
3765 IMAGES: (useSubdomains ? '//img.' + host + '/' : '/data/images/'),
3766 VIDS: (useSubdomains ? '//vid.' + host + '/' : '/data/images/'),
3767 FULLSIZE: (useSubdomains ? '//full.' + host + '/' : '/data/fullsize/'),
3768 THUMBS: (useSubdomains ? '//thumb.' + host + '/' : '/data/thumbs/')
3769 },
3770 LAYOUT: {
3771 THUMBS_PER_ROW: {
3772 MIN: 3,
3773 MAX: 8
3774 },
3775 THUMB: {
3776 WIDTH: 128,
3777 HEIGHT: 128,
3778 PADDING: 4
3779 },
3780 WIDTH_CLASS: {
3781 TWO_SIDEBARS: {
3782 MAX_WIDTH: Infinity,
3783 SIDEBARS_WIDTH: 400,
3784 MARGIN: 24,
3785 CLASS_NAME: 'two-sidebars'
3786 },
3787 ONE_SIDEBAR: {
3788 MAX_WIDTH: 1440,
3789 SIDEBARS_WIDTH: 200,
3790 MARGIN: 20,
3791 CLASS_NAME: 'one-sidebar'
3792 },
3793 NO_SIDEBAR: {
3794 MAX_WIDTH: 780,
3795 SIDEBARS_WIDTH: 0,
3796 MARGIN: 0,
3797 CLASS_NAME: 'no-sidebar'
3798 }
3799 },
3800 WIDTH_CLASS_FORCE_NO_SIDEBAR: {
3801 MAX_WIDTH: Infinity,
3802 SIDEBARS_WIDTH: 0,
3803 MARGIN: 24,
3804 CLASS_NAME: 'wide-no-sidebar'
3805 }
3806 },
3807 THEMES: [{
3808 id: 0,
3809 name: 'bewährtes Orange'
3810 }, {
3811 id: 1,
3812 name: 'angenehmes Grün'
3813 }, {
3814 id: 2,
3815 name: 'Olivgrün des Friedens'
3816 }, {
3817 id: 3,
3818 name: 'episches Blau'
3819 }, {
3820 id: 4,
3821 name: 'altes Pink'
3822 }],
3823 ANALYTICS: {
3824 ENABLED: true,
3825 ACCOUNT: 'UA-66268030-1'
3826 },
3827 COMMENTS_MAX_LEVELS: 15,
3828 SHOW_SCORE_MIN_AGE: 3600,
3829 AUTO_SYNC: {
3830 ENABLED: true,
3831 INTERVAL: 60
3832 },
3833 SFW_FLAG: {
3834 SFW: {
3835 flag: 1,
3836 name: 'sfw'
3837 },
3838 NSFW: {
3839 flag: 2,
3840 name: 'nsfw'
3841 },
3842 NSFL: {
3843 flag: 4,
3844 name: 'nsfl'
3845 },
3846 NSFP: {
3847 flag: 8,
3848 name: 'nsfp'
3849 }
3850 },
3851 INBOX_EXPANDED_COUNT: 5,
3852 TAGS_MIN_CONFIDENCE: 0.2,
3853 TAGS_MAX_DISPLAY: 4,
3854 LAST_LINEAR_COMMENTS_ITEM: 128926,
3855 API: {
3856 ENDPOINT: '/api/',
3857 ALLOWED_UPLOAD_TYPES: ['image/png', 'image/jpeg', 'image/gif', 'video/webm', 'video/mp4']
3858 },
3859 TAGS_INPUT_SETTINGS: {
3860 'defaultText': 'Tags hinzufügen, mit Komma trennen',
3861 'removeWithBackspace': true,
3862 'minChars': 2,
3863 'maxChars': 32
3864 },
3865 BOOKMARKLET: "javascript:" + "void((function(){" + "var%20e=document.createElement('script');" + "e.src='https://" + host + "/media/bookmarklet.min.js';" + "document.body.appendChild(e);" + "})());",
3866 ADS: {
3867 AMAZON_REF: null,
3868 HUBTRAFFIC: {
3869 ENABLED: true,
3870 SEARCH_REGEXP: /(pornhub|redtube|tube8|youporn|xtube|spankwire)\.com/,
3871 QUERY_PARAMS: {
3872 utm_source: 'paid',
3873 utm_medium: 'hubtraffic',
3874 utm_campaign: 'hubtraffic_pr0gramm'
3875 }
3876 },
3877 ACCOUNT: '61585078',
3878 REFRESH_INTERVAL: (120 * 1000)
3879 }
3880 };
3881})(window);
3882p.ads = {
3883 UNIT: {},
3884 _escLoaded: false,
3885 _refreshInterval: 0,
3886 requireEscobar: function() {
3887 if (p.ads._escLoaded) {
3888 return;
3889 }
3890 (function(opts) {
3891 window.esc = {
3892 fill: function() {
3893 this.q.push(arguments);
3894 },
3895 q: [],
3896 opts: opts
3897 };
3898 esc.refresh = esc.fill;
3899 var s = document.createElement('script');
3900 s.async = true;
3901 s.src = (opts.path || '') + 'data/escobar.js?' + (new Date().getTime() / (1000 * 60) | 0);
3902 document.getElementsByTagName('head')[0].appendChild(s);
3903 })({
3904 path: '/escobar/',
3905 debug: false,
3906 autoFill: false
3907 });
3908 p.ads._refreshInterval = setInterval(p.ads.refresh.bind(p.ads), CONFIG.ADS.REFRESH_INTERVAL);
3909 p.ads._escLoaded = true;
3910 },
3911 refresh: function() {
3912 if (!p.ads._escLoaded) {
3913 return;
3914 }
3915 esc.refresh();
3916 },
3917 fill: function(elements) {
3918 if (!elements.length) {
3919 return;
3920 }
3921 p.ads.requireEscobar();
3922 esc.fill(elements);
3923 },
3924 category: function() {
3925 if (p.user.flags == 1 || p.user.flags == 9 || p.user.flags == 8) return 'sfw';
3926 else return 'nsfw';
3927 }
3928};
3929(function(factory) {
3930 if (typeof define === 'function' && define.amd) {
3931 define(['jquery'], factory);
3932 } else {
3933 factory(jQuery);
3934 }
3935}(function($) {
3936 var pluses = /\+/g;
3937
3938 function raw(s) {
3939 return s;
3940 }
3941
3942 function decoded(s) {
3943 return decodeURIComponent(s.replace(pluses, ' '));
3944 }
3945
3946 function converted(s) {
3947 if (s.indexOf('"') === 0) {
3948 s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
3949 }
3950 try {
3951 return config.json ? JSON.parse(s) : s;
3952 } catch (er) {}
3953 }
3954 var config = $.cookie = function(key, value, options) {
3955 if (value !== undefined) {
3956 options = $.extend({}, config.defaults, options);
3957 if (typeof options.expires === 'number') {
3958 var days = options.expires,
3959 t = options.expires = new Date();
3960 t.setDate(t.getDate() + days);
3961 }
3962 value = config.json ? JSON.stringify(value) : String(value);
3963 return (document.cookie = [config.raw ? key : encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : ''].join(''));
3964 }
3965 var decode = config.raw ? raw : decoded;
3966 var cookies = document.cookie.split('; ');
3967 var result = key ? undefined : {};
3968 for (var i = 0, l = cookies.length; i < l; i++) {
3969 var parts = cookies[i].split('=');
3970 var name = decode(parts.shift());
3971 var cookie = decode(parts.join('='));
3972 if (key && key === name) {
3973 result = converted(cookie);
3974 break;
3975 }
3976 if (!key) {
3977 result[name] = converted(cookie);
3978 }
3979 }
3980 return result;
3981 };
3982 config.defaults = {};
3983 $.removeCookie = function(key, options) {
3984 if ($.cookie(key) !== undefined) {
3985 $.cookie(key, '', $.extend(options, {
3986 expires: -1
3987 }));
3988 return true;
3989 }
3990 return false;
3991 };
3992}));
3993p.LocalStore = p.Class.extend({
3994 storeName: 'keyvalues',
3995 prefix: 'default_',
3996 status: 0,
3997 _db: null,
3998 _queue: [],
3999 init: function(name, version) {
4000 this.prefix = name ? (name + '_') : this.prefix;
4001 var that = this;
4002 var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
4003 if (!indexedDB) {
4004 that.status = p.LocalStore.STATUS.FAILED;
4005 that._execQueue();
4006 return;
4007 }
4008 version = version || 1;
4009 try {
4010 var request = indexedDB.open('LocalStore', version || 1);
4011 request.onupgradeneeded = function() {
4012 try {
4013 request.result.deleteObjectStore(that.storeName);
4014 } catch (e) {}
4015 try {
4016 request.result.createObjectStore(that.storeName);
4017 } catch (e) {}
4018 };
4019 request.onsuccess = function() {
4020 that.status = p.LocalStore.STATUS.OPEN;
4021 that._db = request.result;
4022 that._execQueue();
4023 };
4024 request.onerror = function() {
4025 that.status = p.LocalStore.STATUS.FAILED;
4026 that._execQueue();
4027 };
4028 } catch (err) {
4029 that.status = p.LocalStore.STATUS.FAILED;
4030 that._execQueue();
4031 }
4032 },
4033 _execQueue: function() {
4034 var queue = this._queue;
4035 this._queue = [];
4036 for (var i = 0; i < queue.length; i++) {
4037 var q = queue[i];
4038 this._execRequest(q.mode, q.action, q.callback, q.params);
4039 }
4040 },
4041 _execRequest: function(mode, action, callback, params) {
4042 if (this.status === p.LocalStore.STATUS.OPEN) {
4043 try {
4044 var store = this._db.transaction(this.storeName, mode).objectStore(this.storeName);
4045 var req = store[action].apply(store, params);
4046 if (callback) {
4047 req.onsuccess = function() {
4048 callback(null, req.result);
4049 };
4050 req.onerror = function() {
4051 callback(req.error, null);
4052 };
4053 }
4054 } catch (err) {}
4055 } else if (this.status === p.LocalStore.STATUS.NOT_OPEN) {
4056 this._queue.push({
4057 mode: mode,
4058 action: action,
4059 callback: callback,
4060 params: params
4061 });
4062 } else if (this.status === p.LocalStore.STATUS.FAILED && callback) {
4063 callback(this.status);
4064 }
4065 },
4066 getItem: function(key, callback) {
4067 this._execRequest('readonly', 'get', callback, [this.prefix + key]);
4068 },
4069 setItem: function(key, value, callback) {
4070 this._execRequest('readwrite', 'put', callback, [value, this.prefix + key]);
4071 },
4072 removeItem: function(key, callback) {
4073 this._execRequest('readwrite', 'delete', callback, [this.prefix + key]);
4074 },
4075 clear: function(callback) {
4076 this._execRequest('readwrite', 'clear', callback, []);
4077 }
4078});
4079p.LocalStore.deleteDatabase = function(name) {
4080 name = name || 'LocalStore';
4081 var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
4082 if (indexedDB) {
4083 try {
4084 indexedDB.deleteDatabase(name);
4085 } catch (err) {}
4086 }
4087};
4088p.LocalStore.STATUS = {
4089 NOT_OPEN: 0,
4090 FAILED: 1,
4091 OPEN: 2
4092};
4093p.VoteCache = p.Class.extend({
4094 votes: {
4095 items: {},
4096 tags: {},
4097 comments: {}
4098 },
4099 localStore: null,
4100 _storageRequestsRunning: 0,
4101 _updateFromLogWaiting: null,
4102 _cachedLastOffset: -1,
4103 setDatabaseName: function(name) {
4104 name = (typeof name === 'string') ? name.replace(/[^\w]/, '') : 'default';
4105 this.localStore = new p.LocalStore(name, 4);
4106 },
4107 clear: function() {
4108 this.votes.items = {};
4109 this.votes.tags = {};
4110 this.votes.comments = {};
4111 this.localStore.clear();
4112 },
4113 getLastSyncData: function(callback) {
4114 if (!this.localStore) {
4115 return;
4116 }
4117 var that = this;
4118 this.localStore.getItem('last_offset', function(error, offset) {
4119 if (error) {
4120 return;
4121 }
4122 var lastOffset = (parseInt(offset) || 0);
4123 that.localStore.getItem('sync_token', function(error, token) {
4124 if (that._cachedLastOffset !== -1 && that._cachedLastOffset != lastOffset) {
4125 that.loadFromLocal(function() {
4126 callback(lastOffset, token);
4127 });
4128 } else {
4129 callback(lastOffset, token);
4130 }
4131 that._cachedLastOffset = lastOffset;
4132 });
4133 });
4134 },
4135 createNewSyncToken: function() {
4136 var token = Math.random().toString(36).substr(2);
4137 this.localStore.setItem('sync_token', token);
4138 return token;
4139 },
4140 loadFromLocal: function(callback) {
4141 if (!this.localStore) {
4142 return;
4143 }
4144 this._storageRequestsRunning++;
4145 this.localStore.getItem('votes', function(error, buffer) {
4146 if (buffer && buffer instanceof ArrayBuffer) {
4147 this.createVotesFromBuffer(buffer);
4148 }
4149 this._storageRequestsRunning--;
4150 if (this._updateFromLogWaiting) {
4151 var r = this._updateFromLogWaiting;
4152 this._updateFromLogInternal(r.base64, r.offset, r.callback);
4153 this._updateFromLogWaiting = null;
4154 }
4155 callback();
4156 }.bind(this));
4157 },
4158 storeToLocal: function() {
4159 var voteCount = 0;
4160 for (var thing in this.votes) {
4161 voteCount += Object.keys(this.votes[thing]).length;
4162 }
4163 var buffer = new ArrayBuffer(voteCount * 5);
4164 var view = new DataView(buffer);
4165 var offset = 0;
4166 for (var thing in this.votes) {
4167 var votes = this.votes[thing];
4168 var VA = p.VoteCache.VOTE_TO_ACTION[thing];
4169 for (var thingId in votes) {
4170 var action = VA[votes[thingId] + 1];
4171 view.setUint32(offset, thingId, true);
4172 view.setInt8(offset + 4, action);
4173 offset += 5;
4174 }
4175 }
4176 this.localStore.setItem('votes', buffer);
4177 },
4178 updateFromLog: function(base64, offset, callback) {
4179 if (!this.localStore || (!base64 && offset === this._cachedLastOffset)) {
4180 return;
4181 }
4182 this._cachedLastOffset = offset;
4183 if (this._storageRequestsRunning != 0) {
4184 this._updateFromLogWaiting = {
4185 base64: base64,
4186 offset: offset,
4187 callback: callback
4188 };
4189 } else {
4190 this._updateFromLogInternal(base64, offset, callback);
4191 }
4192 },
4193 _updateFromLogInternal: function(base64, offset, callback) {
4194 this.localStore.setItem('last_offset', offset);
4195 var buffer = this.base64ToArrayBuffer(base64 || "");
4196 this.createVotesFromBuffer(buffer);
4197 this.storeToLocal();
4198 callback();
4199 },
4200 createVotesFromBuffer: function(buffer) {
4201 var view = new DataView(buffer);
4202 var AV = p.VoteCache.ACTION_TO_VOTE;
4203 for (var i = 0; i < view.byteLength; i += 5) {
4204 var thingId = view.getUint32(i, true);
4205 var action = AV[view.getInt8(i + 4)];
4206 if (action && action.vote === 0) {
4207 delete this.votes[action.thing][thingId];
4208 } else if (action) {
4209 this.votes[action.thing][thingId] = action.vote;
4210 }
4211 }
4212 },
4213 base64ToArrayBuffer: function(base64) {
4214 var bin = window.atob(base64);
4215 var bytes = new Uint8Array(bin.length);
4216 for (var i = 0; i < bin.length; i++) {
4217 bytes[i] = bin.charCodeAt(i);
4218 }
4219 return bytes.buffer;
4220 }
4221});
4222p.VoteCache.ACTION_TO_VOTE = [null, {
4223 thing: 'items',
4224 vote: -1
4225}, {
4226 thing: 'items',
4227 vote: 0
4228}, {
4229 thing: 'items',
4230 vote: +1
4231}, {
4232 thing: 'comments',
4233 vote: -1
4234}, {
4235 thing: 'comments',
4236 vote: 0
4237}, {
4238 thing: 'comments',
4239 vote: +1
4240}, {
4241 thing: 'tags',
4242 vote: -1
4243}, {
4244 thing: 'tags',
4245 vote: 0
4246}, {
4247 thing: 'tags',
4248 vote: +1
4249}, {
4250 thing: 'items',
4251 vote: +2
4252}];
4253p.VoteCache.VOTE_TO_ACTION = {
4254 items: [1, 2, 3, 10],
4255 comments: [4, 5, 6],
4256 tags: [7, 8, 9]
4257};
4258p.User = p.Class.extend({
4259 id: null,
4260 paid: false,
4261 cookie: {},
4262 flags: 1,
4263 flagsName: 'sfw',
4264 name: '',
4265 admin: false,
4266 syncTimeout: null,
4267 showAds: true,
4268 inboxCount: 0,
4269 syncToken: null,
4270 video: {
4271 volume: 1,
4272 muted: true
4273 },
4274 init: function() {
4275 this.voteCache = new p.VoteCache();
4276 this.loadCookie();
4277 if (this.id) {
4278 this.voteCache.setDatabaseName(this.name);
4279 this.voteCache.loadFromLocal(this.syncVotesOnCurrentView.bind(this));
4280 this.sync();
4281 }
4282 this.setLastVisit();
4283 },
4284 login: function(data, callback) {
4285 this.externalCallback = callback;
4286 p.api.post('user.login', data, this.loginCallback.bind(this));
4287 },
4288 logout: function() {
4289 p.api.post('user.logout', {
4290 id: this.id
4291 });
4292 this.softLogout();
4293 },
4294 softLogout: function() {
4295 this.flags = CONFIG.SFW_FLAG.SFW.flag;
4296 this.cookie = {};
4297 this.saveCookie();
4298 this.id = null;
4299 this.paid = 0;
4300 if (this.syncTimeout) {
4301 clearTimeout(this.syncTimeout);
4302 }
4303 },
4304 setFlags: function(flags) {
4305 if (flags < 1) {
4306 flags = CONFIG.SFW_FLAG.SFW.flag;
4307 }
4308 this.flags = flags;
4309 this.cookie.fl = flags;
4310 this.saveCookie();
4311 this.reloadFlagsName();
4312 return true;
4313 },
4314 setShowAds: function(forceOn) {
4315 if (this.paid && forceOn) {
4316 this.set('ads', 1);
4317 this.showAds = true;
4318 } else {
4319 this.unset('ads');
4320 if (this.paid) {
4321 this.showAds = false;
4322 }
4323 }
4324 },
4325 loginCallback: function(response) {
4326 if (response.success) {
4327 this.loadCookie();
4328 this.voteCache.setDatabaseName(this.name);
4329 this.voteCache.loadFromLocal(this.syncVotesOnCurrentView.bind(this));
4330 this.sync();
4331 }
4332 if (this.externalCallback) {
4333 this.externalCallback(response);
4334 }
4335 },
4336 get: function(key) {
4337 return this.cookie[key] || null;
4338 },
4339 set: function(key, value) {
4340 this.cookie[key] = value;
4341 this.saveCookie();
4342 },
4343 unset: function(key) {
4344 delete this.cookie[key];
4345 this.saveCookie();
4346 },
4347 getTheme: function() {
4348 return parseInt(this.get('t')) || 0;
4349 },
4350 setTheme: function(themeId) {
4351 this.set('t', themeId);
4352 },
4353 loadCookie: function() {
4354 var restored = JSON.parse($.cookie(CONFIG.COOKIE.NAME) || '{}');
4355 if (restored) {
4356 this.cookie = p.merge(this.cookie, restored);
4357 this.id = this.cookie.id;
4358 this.flags = parseInt(this.cookie.fl) || 1;
4359 if (this.flags < 1) {
4360 this.flags = CONFIG.SFW_FLAG.SFW.flag;
4361 }
4362 if (this.id) {
4363 this.name = this.cookie.n;
4364 this.admin = !!this.cookie.a;
4365 this.paid = !!this.cookie.paid;
4366 if (this.flags & CONFIG.SFW_FLAG.SFW.flag) {
4367 this.flags = this.flags | CONFIG.SFW_FLAG.NSFP.flag;
4368 }
4369 }
4370 this.video.volume = this.cookie.vv !== undefined ? (this.cookie.vv / 100) : 1;
4371 this.video.muted = this.cookie.vm !== false;
4372 if (this.cookie.lv + 3600 < Date.now() / 1000) {
4373 this.video.muted = true;
4374 this.saveAudioSettings();
4375 }
4376 } else {
4377 this.id = null;
4378 }
4379 if (!this.id) {
4380 this.flags = CONFIG.SFW_FLAG.SFW.flag;
4381 this.admin = false;
4382 this.paid = false;
4383 }
4384 if (!this.paid && this.cookie.t !== 0) {
4385 this.setTheme(0);
4386 }
4387 this.showAds = !!(!this.paid || this.cookie.ads);
4388 this.reloadFlagsName();
4389 },
4390 reloadFlagsName: function() {
4391 if (this.flags == (CONFIG.SFW_FLAG.SFW.flag | CONFIG.SFW_FLAG.NSFW.flag | CONFIG.SFW_FLAG.NSFL.flag | CONFIG.SFW_FLAG.NSFP.flag)) {
4392 this.flagsName = 'all';
4393 } else {
4394 var names = [];
4395 for (var f in CONFIG.SFW_FLAG) {
4396 if (this.flags & CONFIG.SFW_FLAG[f].flag && CONFIG.SFW_FLAG[f].flag != CONFIG.SFW_FLAG.NSFP.flag) {
4397 names.push(CONFIG.SFW_FLAG[f].name);
4398 }
4399 }
4400 this.flagsName = names.length ? names.join('+') : CONFIG.SFW_FLAG.SFW.name;
4401 }
4402 },
4403 saveAudioSettings: function() {
4404 this.set('vv', (this.video.volume * 100) | 0);
4405 this.set('vm', this.video.muted);
4406 },
4407 setLastVisit: function() {
4408 this.set('lv', (Date.now() / 1000) | 0);
4409 setTimeout(this.setLastVisit.bind(this), 60 * 1000);
4410 },
4411 saveCookie: function() {
4412 var cs = JSON.stringify(this.cookie);
4413 $.cookie(CONFIG.COOKIE.NAME, cs, {
4414 expires: CONFIG.COOKIE.EXPIRE,
4415 path: '/'
4416 });
4417 },
4418 sync: function() {
4419 this.voteCache.getLastSyncData((function(lastOffset, globalSyncToken) {
4420 if (!globalSyncToken || !this.syncToken || this.syncToken === globalSyncToken) {
4421 this.syncToken = this.voteCache.createNewSyncToken();
4422 p.api.get('user.sync', {
4423 offset: lastOffset
4424 }, this.syncCallback.bind(this), p.ServerAPI.SILENT);
4425 } else {
4426 this.syncToken = globalSyncToken;
4427 this.voteCache.localStore.getItem('inbox_count', (function(error, count) {
4428 this.setInboxLink(count || 0);
4429 this.scheduleSync();
4430 }).bind(this));
4431 }
4432 }).bind(this));
4433 },
4434 syncCallback: function(response) {
4435 this.voteCache.localStore.setItem('inbox_count', response.inboxCount);
4436 this.setInboxLink(response.inboxCount);
4437 this.loadCookie();
4438 this.voteCache.updateFromLog(response.log, response.logLength, this.syncVotesOnCurrentView.bind(this));
4439 this.scheduleSync();
4440 },
4441 scheduleSync: function() {
4442 if (this.id && CONFIG.AUTO_SYNC.ENABLED) {
4443 this.syncTimeout = setTimeout(this.sync.bind(this), CONFIG.AUTO_SYNC.INTERVAL * 1000);
4444 }
4445 },
4446 restoreVotes: function() {
4447 this.voteCache.clear();
4448 p.api.get('user.sync', {
4449 lastId: 0
4450 }, this.syncCallback.bind(this), p.ServerAPI.SILENT);
4451 },
4452 setInboxLink: function(count) {
4453 this.inboxCount = count;
4454 var empty = (this.inboxCount == 0);
4455 document.title = (empty ? '' : '[' + count + '] ') + document.title.replace(/^\[\d+\]\s*/, '');
4456 $('#inbox-link').toggleClass('empty', empty);
4457 $('#inbox-link').attr('href', empty ? '/inbox/all' : '/inbox/unread');
4458 $('#inbox-count').text(this.inboxCount);
4459 },
4460 syncVotesOnCurrentView: function() {
4461 if (p.currentView && p.currentView.syncVotes) {
4462 p.currentView.syncVotes(this.voteCache.votes);
4463 }
4464 }
4465});
4466p.User.MARK = {
4467 '0': 'Schwuchtel',
4468 '1': 'Neuschwuchtel',
4469 '2': 'Altschwuchtel',
4470 '3': 'Admin',
4471 '4': 'Gesperrt',
4472 '5': 'Moderator',
4473 '6': 'Fliesentischbesitzer',
4474 '7': 'Lebende Legende',
4475 '8': 'pr0wichtler',
4476 '9': 'Edler Spender',
4477};
4478p.ServerAPI = p.Class.extend({
4479 path: '/',
4480 init: function(path) {
4481 this.path = path || '/';
4482 },
4483 post: function(endpoint, data, callback, errback) {
4484 if (CONFIG.READ_ONLY) {
4485 if (errback) {
4486 errback();
4487 }
4488 return;
4489 }
4490 this._ajax('POST', endpoint, data, callback, errback);
4491 },
4492 get: function(endpoint, data, callback, errback) {
4493 this._ajax('GET', endpoint, data, callback, errback);
4494 },
4495 _ajax: function(method, endpoint, data, callback, errback) {
4496 if (data instanceof HTMLFormElement || ((data instanceof $) && data.is('form'))) {
4497 data = $(data).serialize();
4498 if (data.length > 0 && p.user.id && method == 'POST') {
4499 data = data + '&_nonce=' + p.user.id.substr(0, 16);
4500 }
4501 } else if (method == 'POST' && p.user && p.user.id) {
4502 if (typeof(data) == 'object') {
4503 data._nonce = p.user.id.substr(0, 16);
4504 } else if (typeof(data) == 'string') {
4505 data = data + '&_nonce=' + p.user.id.substr(0, 16);
4506 }
4507 }
4508 var url = this.path + endpoint.replace(/\./g, '/');
4509 if (this.onerror && errback !== p.ServerAPI.SILENT) {
4510 if (errback) {
4511 var onerror = this.onerror;
4512 var paramErrback = errback;
4513 errback = function(response) {
4514 onerror(response);
4515 paramErrback(response);
4516 }
4517 } else {
4518 errback = this.onerror;
4519 }
4520 }
4521 $.ajax({
4522 type: method,
4523 url: url,
4524 success: callback,
4525 error: errback,
4526 dataType: 'json',
4527 data: data
4528 });
4529 }
4530});
4531p.ServerAPI.SILENT = function() {};
4532p.Hotkeys = p.Class.extend({
4533 $indicator: null,
4534 init: function(element) {
4535 $(element).keydown(this.keydown.bind(this));
4536 },
4537 keydown: function(ev) {
4538 if (ev.altKey || ev.ctrlKey || ev.metaKey) {
4539 return;
4540 }
4541 if (ev.target.type == 'text' || ev.target.type == 'textarea' || ev.target.type == 'email' || ev.target.type == 'password' || ev.target.className == 'button') {
4542 if (ev.keyCode == p.KEY.ESC) {
4543 ev.target.blur();
4544 }
4545 return;
4546 }
4547 if (this.handleKey(ev.keyCode)) {
4548 ev.preventDefault();
4549 return false;
4550 }
4551 return true;
4552 },
4553 handleKey: function(code) {
4554 switch (code) {
4555 case p.KEY.LEFT_ARROW:
4556 case p.KEY.A:
4557 $('.stream-prev:visible').click();
4558 return true;
4559 case p.KEY.RIGHT_ARROW:
4560 case p.KEY.D:
4561 $('.stream-next:visible').click();
4562 return true;
4563 case p.KEY.ESC:
4564 $('.item-image:visible').click();
4565 return true;
4566 case p.KEY.K:
4567 $('#search-form-inline:visible input.q').focus();
4568 return true;
4569 case p.KEY.C:
4570 $('.comment:visible').focus();
4571 return true;
4572 case p.KEY.T:
4573 $('.add-tags-link:visible').click();
4574 return true;
4575 case p.KEY.F:
4576 case p.KEY.MULTIPLY:
4577 if ($('.vote-fav').click().length) {
4578 this.showKeyIndicator($('.vote-fav.faved').length ? '*' : '+', true);
4579 }
4580 return true;
4581 case p.KEY.W:
4582 case p.KEY.PLUS:
4583 case p.KEY.ADD:
4584 case p.KEY.G:
4585 if (!$('.item-vote').hasClass('voted-up') && $('.item-vote .vote-up:visible').click().length) {
4586 this.showKeyIndicator('+', true);
4587 }
4588 return true;
4589 case p.KEY.S:
4590 case p.KEY.MINUS:
4591 case p.KEY.SUBTRACT:
4592 case p.KEY.B:
4593 if (!$('.item-vote').hasClass('voted-down') && $('.item-vote .vote-down:visible').click().length) {
4594 this.showKeyIndicator('-', true);
4595 }
4596 return true;
4597 case p.KEY.Q:
4598 $('svg.audio-state').trigger('mousedown');
4599 return true;
4600 case p.KEY.N:
4601 if (p.user.admin) {
4602 var itemId = $('.tag-form input[name=itemId]').val();
4603 if (itemId) {
4604 this.showKeyIndicator('nsfw', false);
4605 p.api.post('tags.add', {
4606 tags: 'nsfw',
4607 itemId: itemId
4608 });
4609 }
4610 }
4611 return true;
4612 case p.KEY.M:
4613 if (p.user.admin) {
4614 var itemId = $('.tag-form input[name=itemId]').val();
4615 if (itemId) {
4616 this.showKeyIndicator('nsfl', false);
4617 p.api.post('tags.add', {
4618 tags: 'nsfl',
4619 itemId: itemId
4620 });
4621 }
4622 }
4623 return true;
4624 }
4625 return false;
4626 },
4627 showKeyIndicator: function(text, isPict) {
4628 if (!this.$indicator) {
4629 this.$indicator = $('<div/>').attr('id', 'key-indicator');
4630 $('body').append(this.$indicator);
4631 }
4632 this.$indicator.stop().css('opacity', 1).toggleClass('pict', isPict).text(text).show().delay(500).fadeOut('fast');
4633 }
4634});
4635"use strict";
4636p.voteClass = function(vote) {
4637 return vote ? (vote > 0 ? ' voted-up' : ' voted-down') : '';
4638};
4639p.favClass = function(vote) {
4640 return vote == 2 ? ' faved' : '';
4641};
4642p.adjustVote = function(thing, vote, cached) {
4643 if (!thing) {
4644 return;
4645 }
4646 if (thing.vote < 0) {
4647 thing.down--;
4648 } else if (thing.vote > 0) {
4649 thing.up--;
4650 }
4651 if (vote > 0) {
4652 thing.up++;
4653 } else if (vote < 0) {
4654 thing.down++;
4655 }
4656 thing.vote = vote;
4657 if (cached && thing.id) {
4658 cached[thing.id] = vote;
4659 }
4660};
4661p.shouldShowScore = function(thing) {
4662 return (p.user.admin || thing.user === p.user.name || (thing.created + CONFIG.SHOW_SCORE_MIN_AGE < Date.now() / 1000));
4663};
4664p.olderThanMinAge = function(thing) {
4665 return (thing.created + CONFIG.SHOW_SCORE_MIN_AGE < Date.now() / 1000)
4666};
4667p.View = {};
4668p.View.Base = p.Class.extend({
4669 visible: false,
4670 needsRendering: false,
4671 aborted: false,
4672 compiledTemplate: null,
4673 template: null,
4674 children: [],
4675 data: {},
4676 dataReady: true,
4677 parentView: null,
4678 requiresLogin: false,
4679 loginUrl: 'overlay',
4680 resetViewport: true,
4681 $container: null,
4682 init: function(container, parent) {
4683 if (this.requiresLogin && !p.user.id) {
4684 this.aborted = true;
4685 if (this.loginUrl == 'overlay') {
4686 p.mainView.showLogin();
4687 } else {
4688 p.navigateToPushStack(this.loginUrl);
4689 }
4690 return;
4691 }
4692 this.$container = container ? $(container) : null;
4693 if (parent) {
4694 this.parentView = parent;
4695 this.parentView.children.push(this);
4696 }
4697 this.compiledTemplate = p._compiledTemplates[this.classId];
4698 if (!this.compiledTemplate && this.template) {
4699 this.compiledTemplate = p.compileTemplate(this.template);
4700 p._compiledTemplates[this.classId] = this.compiledTemplate;
4701 }
4702 },
4703 remove: function() {
4704 this.visible = false;
4705 if (!this.parentView) {
4706 return;
4707 }
4708 this.parentView.children.erase(this);
4709 },
4710 resize: function() {
4711 for (var i = 0; i < this.children.length; i++) {
4712 this.children[i].resize();
4713 }
4714 },
4715 load: function() {
4716 return true;
4717 },
4718 showLoader: function() {
4719 if (!$('#loader').length) {
4720 $('#head-content').append(p.View.Base.LoadingAnimHTML);
4721 }
4722 },
4723 hideLoader: function() {
4724 $('#loader').remove();
4725 },
4726 render: function() {
4727 if (!this.visible) {
4728 return;
4729 }
4730 if (!this.parentView && this.resetViewport !== false) {
4731 $(document).scrollTop(0);
4732 }
4733 this.hideLoader();
4734 if (!this.$container) {
4735 this.$container = $(this.compiledTemplate(this.data));
4736 } else {
4737 this.$container.html(this.compiledTemplate(this.data));
4738 }
4739 var anchors = this.$container.find('a[href^="#"]');
4740 if (p._hasPushState) {
4741 anchors.each(function() {
4742 this.href = '/' + $(this).attr('href').substr(1);
4743 });
4744 }
4745 anchors.fastclick(this.handleHashLink.bind(this));
4746 this.needsRendering = false;
4747 },
4748 handleHashLink: function(ev) {
4749 if (!p.isNormalClick(ev)) {
4750 return true;
4751 }
4752 var target = $(ev.currentTarget);
4753 if (target.hasClass('action')) {
4754 return false;
4755 }
4756 var mode = target.hasClass('silent') ? p.NAVIGATE.SILENT : p.NAVIGATE.DEFAULT;
4757 p.navigateTo(target.attr('href').substr(1), mode);
4758 return false;
4759 },
4760 show: function(params) {
4761 if (this.aborted) {
4762 return;
4763 }
4764 this.needsRendering = true;
4765 this.data.params = params || {};
4766 this.visible = true;
4767 var loaded = this.load();
4768 if (this.needsRendering) {
4769 if (loaded) {
4770 this.hideLoader();
4771 this.render();
4772 } else {
4773 this.showLoader();
4774 }
4775 }
4776 for (var i = 0; i < this.children.length; i++) {
4777 this.children[i].show(params);
4778 }
4779 },
4780 hide: function() {
4781 this.visible = false;
4782 for (var i = 0; i < this.children.length; i++) {
4783 this.children[i].hide();
4784 }
4785 },
4786 focus: function(selector) {
4787 var f = this.$container.find(selector);
4788 setTimeout(function() {
4789 f.focus();
4790 }, 1);
4791 }
4792});
4793p.View.Base.LoadingAnimHTML = $('<div id="loader"><div></div></div>');
4794p._compiledTemplates = {};
4795p.View.Error404 = p.View.Base.extend({
4796 template: '<h2 class="main-message">ZOMFG, 404 ¯\\_(ツ)_/¯</h2>',
4797 init: function(container, parent) {
4798 this.parent(container, parent);
4799 p.mainView.setTab(null);
4800 }
4801});
4802p.View.Overlay = p.View.Overlay || {};
4803p.View.Overlay.Login = p.View.Base.extend({
4804 name: 'overlay-login',
4805 resetViewport: false,
4806 template: '<div class="overlay-content divide-2-1"> <h2>Anmelden</h2> <?js if(loginFailed) {?> <?js if(ban && ban.banned) { ?> <p class="warn"> Dein Account ist gesperrt. <?js if(ban.till) {?> Die Sperrung wird am {ban.till.readableTime()} ({ban.till.relativeTime()}) aufgehoben. <?js } else { ?> Die Sperrung ist dauerhaft. <?js } ?> <?js if(ban.reason) {?> <strong>Grund:</strong> {{ban.reason}} <?js } ?> </p> <?js } else { ?> <p class="warn">Falscher Benutzername oder Passwort</p> <?js } ?> <?js } ?> <form> <div class="form-row"> <p></p> <label>Name oder E-Mail Adresse:</label> <input type="text" name="name" placeholder="Name" tabindex="201" value="{{name}}"/> </div> <div class="form-row"> <label>Passwort:</label> <input type="password" name="password" placeholder="Passwort" tabindex="202"/> </div> <div class="form-row"> <input type="submit" value="Anmelden" id="login-button" tabindex="203"/> </div> <p> <span class="link" id="reset-password-link">Passwort vergessen?</span> </p> </form> </div> <div class="overlay-content divide-2-2"> <h2>Neu Registrieren</h2> <p> Wenn du noch keinen Account hast, kannst du dir jetzt einen pr0mium Account erstellen. </p> <div class="call-to-action"> <a href="#pr0mium" class="confirm-button">Jetzt pr0mium User werden</a> </div> </div> ',
4807 data: {
4808 ban: null,
4809 name: '',
4810 loginFailed: false
4811 },
4812 render: function() {
4813 this.parent();
4814 this.$container.find('form').submit(this.submit.bind(this));
4815 if (!p.mobile) {
4816 this.focus('input[name=name]');
4817 }
4818 $('#reset-password-link').click(p.mainView.showResetPassword.bind(p.mainView));
4819 },
4820 submit: function(ev) {
4821 p.user.login(ev.target, this.posted.bind(this));
4822 this.data.name = $(ev.target).find('input[name=name]').val();
4823 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
4824 this.showLoader();
4825 return false;
4826 },
4827 posted: function(response) {
4828 if (response.success) {
4829 p.reload();
4830 } else {
4831 this.data.loginFailed = true;
4832 this.data.ban = response.ban;
4833 if (this.data.ban && this.data.ban.till) {
4834 this.data.ban.till = new Date(this.data.ban.till * 1000);
4835 }
4836 this.render();
4837 }
4838 }
4839});
4840p.View.Overlay = p.View.Overlay || {};
4841p.View.Overlay.ResetPassword = p.View.Base.extend({
4842 name: 'overlay-reset-password',
4843 resetViewport: false,
4844 template: '<div class="overlay-content"> <h2>Passwort zurücksetzen</h2> </div> <div class="overlay-content"> <?js if(resetSuccess) { ?> <div class="notice"> Die E-Mail mit dem Link zum Zurücksetzen wurde versendet. </div> <?js } else { ?> <form method="post"> <div class="form-row"> <input type="email" name="email" placeholder="E-Mail Adresse" value=""/> </div> <?js if(resetFailed) {?> <p class="warn">E-Mail Adresse nicht bekannt, oder der Account ist gesperrt</p> <?js } ?> <div class="form-row"> <input type="submit" value="Abschicken"/> </div> </form> <?js } ?> </div> ',
4845 data: {
4846 resetFailed: false,
4847 resetSuccess: false
4848 },
4849 render: function() {
4850 this.parent();
4851 this.$container.find('form').submit(this.submit.bind(this));
4852 this.focus('input[name=email]');
4853 if (p.location === 'resetpassword') {
4854 $('#head').hide();
4855 }
4856 },
4857 submit: function(ev) {
4858 p.api.post('user.sendpasswordresetmail', ev.currentTarget, this.posted.bind(this));
4859 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
4860 this.showLoader();
4861 return false;
4862 },
4863 posted: function(response) {
4864 this.data.resetFailed = !response.success;
4865 this.data.resetSuccess = response.success;
4866 this.render();
4867 }
4868});
4869p.View.Overlay = p.View.Overlay || {};
4870p.View.Overlay.Error = p.View.Base.extend({
4871 name: 'overlay-error',
4872 resetViewport: false,
4873 template: '<div class="overlay-content"> <h2>ZOMG, Fehler!</h2> </div> <div class="overlay-content"> <?js if(error) {?> <h2 class="warn">{error.code} – {{error.msg}}</h2> <?js if(error.error == \'limitReached\' ) { ?> <p>Was immer du getan hast, es war zu viel. Probier\'s später nochmal.</p> <?js } ?> <?js } else {?> <h2 class="warn">Irgendwas Doofes ist passiert. Probier\'s später nochmal :/</h2> <?js } ?> </div> ',
4874 data: {
4875 error: null
4876 },
4877 init: function(container, parent, error) {
4878 this.data.error = error;
4879 this.parent(container, parent);
4880 },
4881 show: function(params) {
4882 if (params) {
4883 this.data.error = params;
4884 }
4885 this.parent();
4886 }
4887});
4888p.View.Layout = p.View.Base.extend({
4889 template: '<?js if(p.user.showAds) {?> <div class="side-wide-skyscraper gpt fixed-sidebar-left" id="gpt-skyscraper-left" data-escobar="skyscraper-left-{p.ads.category()}"> </div> <div class="side-wide-skyscraper gpt fixed-sidebar-right" id="gpt-skyscraper-right" data-escobar="skyscraper-right-{p.ads.category()}"> </div> <?js } ?> <div id="page"> <div id="head"> <div id="head-content"> <?js if( !p.mobile ) { ?> <a id="pr0-miner" href="http://miner.pr0gramm.com" target="_blank" title="pr0mium Schürfer"></a> <?js } ?> <div class="user-info guest-only"> <span class="head-link" id="login-link">anmelden</span> </div> <div class="user-info user-only"> <a href="#user/{user.name}" id="user-profile-name" class="head-link">{user.name}</a> <a href="#user/{user.name}" id="user-profile-icon" class="head-link pict">~</a> <a href="#inbox/unread" id="inbox-link" class="empty head-link" title="Nachrichten"> <span class="pict">m</span> <span id="inbox-count">0</span> </a> <a href="#settings/site" class="head-link pict" id="settings-link" title="Einstellungen">#</a> </div> <a href="#" id="pr0gramm-logo-link"><?js print(logo.src || logo); ?></a> <div id="head-menu"> <a id="tab-new" class="head-tab" href="#new">neu</a> <a id="tab-top" class="head-tab" href="#top">beliebt</a> <?js if(p.user.paid) {?> <a id="tab-stalk" class="head-tab" href="#stalk">stelz</a> <?js } else { ?> <a id="tab-stalk" class="head-tab" href="#pr0mium">stelz</a> <?js } ?> <?js if(user.admin) {?> <a id="tab-admin" class="head-tab" href="/backend/admin/">admin</a> <?js } ?> <span id="filter-link" class="user-only head-link"> <span id="filter-link-flag" class="pict">f</span> <span id="filter-link-name">{currentFilterName}</span> </span> <span class="guest-only" id="search-form-spacer"></span> <form action="" id="search-form-inline" class="search-form"> <input type="text" name="q" class="q" value="" title="Suche [k]"/> <input type="submit" id="search-submit-inline" class="pict" title="Suche [k]" value="q"/> </form> <span id="search-button" class="head-link pict">q</span> <a href="#upload" class="head-link pict user-only" id="upload-link" title="Bilder hochladen">u</a> </div> <div id="filter-menu"> <span class="filter-setting" data-flag="{CONFIG.SFW_FLAG.SFW.flag}"> <div class="filter-name"> <span class="filter-check"></span> sfw </div> <div class="filter-desc"> <em>Safe for work</em> </div> </span> <span class="filter-setting" data-flag="{CONFIG.SFW_FLAG.NSFW.flag}"> <div class="filter-name"> <span class="filter-check"></span> nsfw </div> <div class="filter-desc"> Beinhaltet nackte Haut, Pornos und leicht offensiven Kram. </div> </span> <span class="filter-setting" data-flag="{CONFIG.SFW_FLAG.NSFL.flag}"> <div class="filter-name"> <span class="filter-check"></span> nsfl </div> <div class="filter-desc"> Alles. Gewalt, zerplatzte Menschen, ekligen Scheiß. </div> </span> <span id="filter-save">Speichern</span> </div> <form action="" id="search-form-bar" class="search-form"> <input type="text" name="q" class="q" value="" title="Suche [k]"/> <input type="submit" class="search-submit" value="Suchen"/> </form> </div> <?js if (CONFIG.READ_ONLY) {?> <div class="terminal"> <span class="terminal-location"> root@pr0gramm:~# </span> <span class="terminal-command"> chmod a-w </span> <span class="terminal-comment"> # read only </span> </div> <?js } ?> </div> <div id="main-view"></div> </div> <div id="overlay"> <div id="overlay-box"></div> </div> <div id="footer-links" class="fixed-sidebar-left"> <div> <a href="#faq">FAQ</a> <a href="#contact">Kontakt</a> <a href="http://app.pr0gramm.com">Mobile App</a> <a href="https://twitter.com/pr0gramm" target="_blank">Status</a> </div> </div> ',
4890 widthClass: null,
4891 pagePadding: 0,
4892 currentAdPosision: 52,
4893 thumbsPerRow: -1,
4894 data: {
4895 currentFilterName: 'sfw',
4896 logo: '<svg id="pr0gramm-logo" width="156px" height="30px" viewBox="0 0 156 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <path id="pr0gramm-logo-type" fill="#FFFFFF" d="M31.3,22 L31.3,6.7 L38.8,6.7 C39.6,6.7 40.2,6.8 40.8,7.0 C41.3,7.2 41.8,7.6 42.1,8.0 C42.5,8.4 42.8,8.9 43.0,9.5 C43.2,10.1 43.3,10.7 43.3,11.4 C43.3,12.1 43.2,12.8 43.0,13.4 C42.8,14.0 42.5,14.5 42.2,15.0 C41.8,15.4 41.4,15.8 40.8,16.0 C40.2,16.3 39.6,16.4 38.8,16.4 L33.8,16.4 L33.8,22 L31.3,22 Z M33.8,8.9 L33.8,14.1 L38.0,14.1 C38.9,14.1 39.7,13.9 40.1,13.4 C40.6,13.0 40.8,12.3 40.8,11.4 C40.8,10.5 40.5,9.9 40.1,9.5 C39.6,9.1 38.9,8.9 38.0,8.9 L33.8,8.9 Z M50.0,16.3 C49.9,16.0 49.6,15.9 49.4,15.8 C49.1,15.7 48.9,15.7 48.7,15.7 L47.2,15.7 L47.2,22 L44.7,22 L44.7,6.7 L51.9,6.7 C52.6,6.7 53.2,6.8 53.7,7.0 C54.3,7.2 54.7,7.5 55.1,7.9 C55.5,8.2 55.8,8.7 56.0,9.2 C56.2,9.8 56.4,10.4 56.4,11.0 C56.4,12.4 56.0,13.4 55.3,14.3 C54.7,15.1 53.7,15.6 52.5,15.7 L55.4,19.4 C55.6,19.6 55.9,19.8 56.0,19.9 C56.2,20.0 56.5,20.1 56.9,20.1 L56.9,22 C56.7,22.0 56.6,22.1 56.4,22.1 C56.1,22.2 56.0,22.2 55.8,22.2 C55.3,22.2 54.9,22.1 54.6,21.8 C54.2,21.5 53.9,21.2 53.7,20.8 L50.0,16.3 Z M47.2,13.4 L51.3,13.4 C52.3,13.4 52.9,13.2 53.3,12.9 C53.7,12.5 53.9,11.9 53.9,11.0 C53.9,10.3 53.7,9.8 53.3,9.5 C53.0,9.1 52.4,8.9 51.6,8.9 L47.2,8.9 L47.2,13.4 Z M67.0,14.3 C67.0,13.8 67.0,13.3 66.9,12.6 C66.8,12.0 66.7,11.5 66.5,10.9 C66.3,10.4 66.1,9.9 65.7,9.6 C65.3,9.2 64.8,9.0 64.1,9.0 C63.4,9.0 62.9,9.2 62.5,9.6 C62.1,9.9 61.8,10.3 61.6,10.9 C61.4,11.4 61.3,12.0 61.3,12.6 C61.2,13.2 61.2,13.8 61.2,14.3 C61.2,14.9 61.2,15.5 61.2,16.1 C61.3,16.7 61.4,17.3 61.6,17.9 C61.8,18.4 62.1,18.9 62.5,19.3 C62.9,19.7 63.4,19.8 64.1,19.8 C64.7,19.8 65.3,19.7 65.7,19.3 C66.0,18.9 66.3,18.4 66.5,17.9 C66.7,17.3 66.8,16.7 66.9,16.1 C67.0,15.5 67.0,14.9 67.0,14.3 L67.0,14.3 Z M64.1,6.7 C64.8,6.7 65.5,6.8 66.0,7.0 C66.6,7.2 67.1,7.5 67.5,7.9 C67.9,8.3 68.2,8.7 68.4,9.3 C68.7,9.8 68.9,10.3 69.0,10.9 C69.2,11.4 69.2,12.0 69.3,12.6 C69.3,13.2 69.4,13.8 69.4,14.3 C69.4,15.2 69.3,16.1 69.2,17.0 C69.0,17.9 68.8,18.8 68.4,19.5 C68.0,20.3 67.5,20.9 66.8,21.5 C66.1,22.0 65.2,22.2 64.0,22.2 C62.9,22.2 62.0,22.0 61.3,21.4 C60.6,20.9 60.1,20.3 59.7,19.5 C59.3,18.7 59.1,17.9 58.9,17.0 C58.8,16.0 58.7,15.2 58.7,14.3 C58.7,13.5 58.8,12.6 58.9,11.7 C59.1,10.8 59.3,10.0 59.7,9.2 C60.1,8.5 60.6,7.9 61.3,7.4 C62.0,6.9 62.9,6.7 64.1,6.7 L64.1,6.7 Z M81.9,10.0 C81.4,9.5 80.9,9.2 80.3,9.0 C79.8,8.8 79.2,8.7 78.5,8.7 C77.6,8.7 76.8,8.8 76.2,9.1 C75.6,9.3 75.1,9.7 74.7,10.1 C74.3,10.6 74.0,11.2 73.8,11.8 C73.7,12.5 73.6,13.2 73.6,14.1 L73.6,14.6 C73.6,16.3 74.0,17.6 74.9,18.5 C75.7,19.4 77.1,19.9 78.9,19.9 C79.3,19.9 79.8,19.9 80.2,19.8 C80.6,19.6 81.0,19.5 81.3,19.4 L81.3,16.3 L78.5,16.3 L78.5,14.0 L83.7,14.0 L83.7,20.9 C83.0,21.3 82.2,21.6 81.4,21.8 C80.5,22.1 79.6,22.2 78.8,22.2 C77.6,22.2 76.5,22.0 75.6,21.7 C74.6,21.4 73.8,20.9 73.2,20.2 C72.5,19.6 72.0,18.8 71.6,17.8 C71.3,16.9 71.1,15.8 71.1,14.6 L71.1,14.1 C71.1,12.9 71.2,11.9 71.6,10.9 C71.9,10.0 72.4,9.2 73.0,8.5 C73.6,7.8 74.4,7.3 75.3,6.9 C76.2,6.6 77.3,6.4 78.5,6.4 C79.5,6.4 80.5,6.6 81.4,6.9 C82.3,7.2 83.1,7.7 83.7,8.5 L81.9,10.0 Z M91.4,16.3 C91.3,16.0 91.1,15.9 90.8,15.8 C90.6,15.7 90.3,15.7 90.1,15.7 L88.6,15.7 L88.6,22 L86.1,22 L86.1,6.7 L93.4,6.7 C94.0,6.7 94.6,6.8 95.1,7.0 C95.7,7.2 96.1,7.5 96.5,7.9 C96.9,8.2 97.2,8.7 97.4,9.2 C97.7,9.8 97.8,10.4 97.8,11.0 C97.8,12.4 97.4,13.4 96.8,14.3 C96.1,15.1 95.2,15.6 93.9,15.7 L96.8,19.4 C97.1,19.6 97.3,19.8 97.5,19.9 C97.7,20.0 97.9,20.1 98.3,20.1 L98.3,22 C98.2,22.0 98.0,22.1 97.8,22.1 C97.6,22.2 97.4,22.2 97.2,22.2 C96.8,22.2 96.4,22.1 96.0,21.8 C95.7,21.5 95.4,21.2 95.1,20.8 L91.4,16.3 Z M88.6,13.4 L92.7,13.4 C93.7,13.4 94.3,13.2 94.7,12.9 C95.1,12.5 95.3,11.9 95.3,11.0 C95.3,10.3 95.1,9.8 94.8,9.5 C94.4,9.1 93.8,8.9 93.0,8.9 L88.6,8.9 L88.6,13.4 Z M104.6,15.4 L109.2,15.4 L107.2,10.3 L106.9,8.6 L106.5,10.3 L104.6,15.4 Z M103.9,17.6 L102.3,22 L99.7,22 L105.4,6.7 L108.3,6.7 L114.3,22 L111.7,22 L110.1,17.6 L103.9,17.6 Z M116.0,22 L116.0,6.7 L119.4,6.7 L123.6,17.4 L127.9,6.7 L131.2,6.7 L131.2,22 L128.7,22 L128.7,10.4 L124.8,20.1 L122.4,20.1 L118.5,10.2 L118.5,22 L116.0,22 Z M133.9,22 L133.9,6.7 L137.2,6.7 L141.5,17.4 L145.8,6.7 L149.1,6.7 L149.1,22 L146.6,22 L146.6,10.4 L142.7,20.1 L140.3,20.1 L136.4,10.2 L136.4,22 L133.9,22 Z"></path> <rect id="pr0gramm-logo-background" fill="#D23C22" x="2" y="3" width="22" height="22" rx="2"></rect> <g id="pr0gramm-logo-sign" transform="translate(5.0, 7.0)" fill="#FFFFFF"> <rect x="8" y="10" width="7" height="2" rx="1"></rect> <path d="M2.0,9.7 C2.4,9.3 2.9,9.0 3.3,8.6 C3.8,8.2 4.2,7.8 4.7,7.5 C5.1,7.1 5.5,6.8 5.8,6.5 C5.5,6.3 5.2,6.0 4.7,5.6 C4.3,5.2 3.9,4.8 3.4,4.4 C2.9,4.0 2.5,3.7 2.0,3.3 C1.6,2.9 1.2,2.6 1.0,2.4 C0.7,2.1 0.6,1.8 0.6,1.5 C0.6,1.2 0.7,0.9 0.9,0.7 C1.1,0.5 1.3,0.4 1.6,0.4 C1.8,0.4 1.9,0.5 2.2,0.6 C2.2,0.6 2.4,0.8 2.7,1.0 C3.0,1.3 3.4,1.6 3.8,2.0 C4.2,2.3 4.6,2.7 5.1,3.1 C5.6,3.5 6.0,3.9 6.4,4.2 C6.8,4.5 7.2,4.8 7.5,5.1 C7.8,5.4 8.0,5.5 8.1,5.6 C8.4,5.9 8.5,6.2 8.5,6.6 C8.5,6.9 8.4,7.2 8.1,7.5 C7.7,7.8 7.2,8.2 6.7,8.6 C6.2,9.0 5.7,9.5 5.1,9.9 C4.6,10.3 4.1,10.8 3.5,11.2 C3.0,11.6 2.6,12.0 2.1,12.3 C1.9,12.4 1.7,12.5 1.5,12.5 C1.2,12.5 1.0,12.4 0.8,12.2 C0.6,12.0 0.5,11.8 0.5,11.5 C0.5,11.2 0.6,10.9 0.8,10.6 C1.1,10.3 1.5,10.0 2.0,9.7 Z"></path> </g> </svg> '
4897 },
4898 init: function(container, parent) {
4899 this.parent(container, parent);
4900 this.data.user = p.user;
4901 p.onsetview = this.onSetView.bind(this);
4902 p.api.onerror = this.onError.bind(this);
4903 if (p.mobile) {
4904 $.fx.off = true;
4905 }
4906 this.resize();
4907 $(window).resize(this.resize.bind(this)).scroll(this.scroll.bind(this));
4908 },
4909 resize: function() {
4910 var L = CONFIG.LAYOUT;
4911 var windowWidth = $(window).width();
4912 var forceSetCSS = false;
4913 var resizedWidthClass = this.widthClass;
4914 for (var NAME in L.WIDTH_CLASS) {
4915 var C = L.WIDTH_CLASS[NAME];
4916 if (windowWidth < C.MAX_WIDTH) {
4917 resizedWidthClass = C;
4918 }
4919 }
4920 if (!p.user.showAds && resizedWidthClass != L.WIDTH_CLASS.NO_SIDEBAR) {
4921 resizedWidthClass = L.WIDTH_CLASS_FORCE_NO_SIDEBAR;
4922 }
4923 var availableWidth = windowWidth - resizedWidthClass.SIDEBARS_WIDTH - resizedWidthClass.MARGIN;
4924 var resizedThumbsPerRow = ((availableWidth + L.THUMB.PADDING) / (L.THUMB.WIDTH + L.THUMB.PADDING) | 0).limit(L.THUMBS_PER_ROW.MIN, L.THUMBS_PER_ROW.MAX);
4925 if (this.thumbsPerRow === resizedThumbsPerRow && this.widthClass === resizedWidthClass) {
4926 return;
4927 }
4928 this.widthClass = resizedWidthClass;
4929 this.setPageCSS(resizedThumbsPerRow);
4930 if (p.currentView) {
4931 p.currentView.resize();
4932 }
4933 p.ads.fill(this.$container.find('.gpt:visible'));
4934 this.scroll();
4935 },
4936 scroll: function() {
4937 var L = CONFIG.LAYOUT;
4938 if (this.widthClass === L.WIDTH_CLASS.NO_SIDEBAR || this.widthClass === L.WIDTH_CLASS_FORCE_NO_SIDEBAR) {
4939 return;
4940 }
4941 var scroll = $(document).scrollTop();
4942 var windowHeight = Math.max(window.innerHeight, 800);
4943 var thumbHeight = L.THUMB.HEIGHT + L.THUMB.PADDING;
4944 var np = Math.ceil((Math.floor((scroll + windowHeight) / (windowHeight * 2)) * windowHeight * 2) / thumbHeight) * thumbHeight + 52;
4945 if (np !== this.currentAdPosision) {
4946 this.currentAdPosision = np;
4947 $('.side-wide-skyscraper').css('top', this.currentAdPosision);
4948 }
4949 },
4950 setPageCSS: function(thumbsPerRow) {
4951 var L = CONFIG.LAYOUT;
4952 this.thumbsPerRow = thumbsPerRow;
4953 var pageWidth = this.thumbsPerRow * (L.THUMB.WIDTH + L.THUMB.PADDING) - L.THUMB.PADDING + this.widthClass.SIDEBARS_WIDTH;
4954 $('body').removeClass().addClass(this.widthClass.CLASS_NAME);
4955 this.setThemeCSS();
4956 $('#head').css('width', pageWidth);
4957 $('#page').css('width', pageWidth).toggleClass('desktop', !p.mobile).toggleClass('lt7', thumbsPerRow < 7).toggleClass('lt6', thumbsPerRow < 6).toggleClass('lt5', thumbsPerRow < 5).toggleClass('lt4', thumbsPerRow < 4).toggleClass('noAds', !p.user.showAds);
4958 $('meta[name=viewport]').attr('content', 'minimal-ui, width=' + pageWidth);
4959 var sidebarOffset = (this.widthClass === L.WIDTH_CLASS.NO_SIDEBAR || this.widthClass === L.WIDTH_CLASS_FORCE_NO_SIDEBAR) ? 0 : -(pageWidth - 160);
4960 $('.fixed-sidebar-left').css('left', sidebarOffset);
4961 $('.fixed-sidebar-right').css('right', sidebarOffset);
4962 $('#search-form-bar').hide();
4963 },
4964 setThemeCSS: function() {
4965 $('body').removeClass(function(index, css) {
4966 return (css.match(/(^|\s)theme-\S+/g) || []).join(' ');
4967 }).addClass('theme-' + p.user.getTheme());
4968 },
4969 onSetView: function() {
4970 this.closeOverlay();
4971 $('#filter-menu').hide();
4972 },
4973 onError: function(response) {
4974 if (response.responseJSON && response.responseJSON.code == 404) {
4975 return p.setView(p.View.Error404);
4976 } else {
4977 if (response.responseJSON && response.responseJSON.code == 403 && response.responseJSON.error == 'forbidden') {
4978 p.user.softLogout();
4979 this.setUserStatus(false);
4980 return false;
4981 }
4982 return this.showOverlay(p.View.Overlay.Error, response.responseJSON);
4983 }
4984 },
4985 setUserStatus: function(isUser) {
4986 $('#page').toggleClass('status-user', isUser).toggleClass('status-guest', !isUser);
4987 },
4988 search: function(q) {
4989 var m = null;
4990 if (m = q.match(/(\w+):(likes|uploads)( (.+))?/)) {
4991 var tags = m[4] ? ('/' + encodeURIComponent(m[4])) : '';
4992 p.navigateTo('user/' + m[1] + '/' + m[2] + tags);
4993 } else {
4994 var tab = $('#tab-top').hasClass('active') ? 'top' : 'new';
4995 var path = q ? ('/' + encodeURIComponent(q)) : '';
4996 path = path.match(/^\/\d+$/) ? path.replace('/', '/+') : path;
4997 p.navigateTo(tab + path);
4998 }
4999 $('#search-form-bar').hide();
5000 },
5001 show: function(params) {
5002 this.data.currentFilterName = p.user.flagsName;
5003 this.parent(params);
5004 this.setPageCSS(this.thumbsPerRow);
5005 this.setUserStatus(!!p.user.id);
5006 $('#login-link').click(this.showLogin.bind(this));
5007 this.overlay = $('#overlay');
5008 this.overlay.click(this.hideOverlay.bind(this));
5009 $('#filter-link').fastclick(function() {
5010 $('.filter-setting').each(function() {
5011 var el = $(this);
5012 el.toggleClass('active', !!(p.user.flags & parseInt(el.data('flag'))));
5013 });
5014 $('#filter-menu').fadeToggle(100);
5015 return false;
5016 });
5017 $('.filter-setting').fastclick(function(ev) {
5018 $(ev.currentTarget).toggleClass('active').blur();
5019 return false;
5020 });
5021 $('#filter-save').fastclick(function() {
5022 var flags = 0;
5023 $('.filter-setting.active').each(function() {
5024 flags += parseInt($(this).data('flag'));
5025 });
5026 p.user.setFlags(flags);
5027 p.reload();
5028 $('#filter-menu').fadeOut(100);
5029 return false;
5030 });
5031 var that = this;
5032 $('form.search-form').submit(function(ev) {
5033 that.search($(ev.target).find('input.q').val());
5034 ev.preventDefault();
5035 return false;
5036 });
5037 $('#search-button').fastclick(function() {
5038 var searchBar = $('#search-form-bar');
5039 if (searchBar.is(':visible')) {
5040 searchBar.find('input.q').blur();
5041 searchBar.hide();
5042 } else {
5043 searchBar.show();
5044 searchBar.find('input.q').focus();
5045 }
5046 });
5047 p.ads.fill(this.$container.find('.gpt:visible'));
5048 },
5049 setTab: function(tab) {
5050 if (tab == 'new') {
5051 $('#tab-new').addClass('active');
5052 $('#tab-top').removeClass('active');
5053 $('input.q').attr('placeholder', 'Alles durchsuchen');
5054 $('#search-form-bar .search-submit').val('Alles durchsuchen');
5055 } else if (tab == 'top') {
5056 $('#tab-top').addClass('active');
5057 $('#tab-new').removeClass('active');
5058 $('input.q').attr('placeholder', 'Beliebt durchsuchen');
5059 $('#search-form-bar .search-submit').val('Beliebt durchsuchen');
5060 } else {
5061 $('#tab-new, #tab-top').removeClass('active');
5062 }
5063 $('.head-tab').removeClass('active');
5064 $('#tab-' + tab).addClass('active');
5065 var qs = tab == 'new' ? 'Alles durchsuchen' : 'Beliebt durchsuchen';
5066 $('input.q').attr('placeholder', qs);
5067 $('#search-form-bar .search-submit').val(qs);
5068 },
5069 requireLogin: function() {
5070 if (CONFIG.READ_ONLY) {
5071 this.showOverlay(p.View.Overlay.Error, {
5072 code: 'READ ONLY MODE',
5073 msg: 'Wartungsarbeiten'
5074 });
5075 return false;
5076 }
5077 if (!p.user.id) {
5078 this.showOverlay(p.View.Overlay.Login);
5079 return false;
5080 }
5081 return true;
5082 },
5083 showResetPassword: function() {
5084 return this.showOverlay(p.View.Overlay.ResetPassword);
5085 },
5086 showLogin: function() {
5087 return this.showOverlay(p.View.Overlay.Login);
5088 },
5089 showOverlay: function(overlayClass, param) {
5090 if (this.overlayView) {
5091 this.overlayView.remove();
5092 this.overlayView = null;
5093 }
5094 var overlayBox = $('#overlay-box');
5095 overlayBox.attr('class', overlayClass.prototype.name || 'overlay-generic');
5096 this.overlayView = new(overlayClass)(overlayBox, this, param);
5097 this.overlayView.show();
5098 if (p.mobile) {
5099 $(document).scrollTop(0);
5100 this.overlay.addClass('mobile');
5101 this.overlay.css('height', $('#main-view').height());
5102 }
5103 this.overlay.fadeIn('fast');
5104 return false;
5105 },
5106 hideOverlay: function(ev) {
5107 if (ev.target != this.overlay[0]) {
5108 return;
5109 }
5110 return this.closeOverlay();
5111 },
5112 closeOverlay: function() {
5113 if (!this.overlayView) {
5114 return false;
5115 }
5116 this.overlay.fadeOut('fast');
5117 this.overlayView.remove();
5118 this.overlayView = null;
5119 this.hideLoader();
5120 return false;
5121 }
5122});
5123"use strict";
5124p.Stream = p.Class.extend({
5125 reached: {
5126 start: false,
5127 end: false
5128 },
5129 _oldestId: Number.POSITIVE_INFINITY,
5130 _newestId: 0,
5131 items: {},
5132 init: function(options) {
5133 this.options = options || {};
5134 },
5135 loadInfo: function(id, callback) {
5136 var item = this.items[id];
5137 if (!item) {
5138 return;
5139 }
5140 if (item.infoTime) {
5141 if (callback) {
5142 callback(item);
5143 }
5144 return;
5145 }
5146 if (item.loadQueue) {
5147 if (callback) {
5148 item.loadQueue.push(callback);
5149 }
5150 return;
5151 }
5152 item.loadQueue = callback ? [callback] : [];
5153 var that = this;
5154 p.api.get('items.info', {
5155 itemId: id
5156 }, function(response) {
5157 that._processInfo(item, response);
5158 });
5159 },
5160 getLoadedItems: function() {
5161 var itemsArray = [];
5162 for (var id in this.items) {
5163 itemsArray.push(this.items[id]);
5164 }
5165 if (this.options.promoted) {
5166 itemsArray.sort(p.Stream.sortByPromoted);
5167 } else {
5168 itemsArray.sort(p.Stream.sortById);
5169 }
5170 return itemsArray;
5171 },
5172 _processInfo: function(item, response) {
5173 if (!item.infoTime || item.infoTime < response.ts) {
5174 item.comments = response.comments;
5175 item.tags = response.tags;
5176 item.infoTime = response.ts;
5177 }
5178 for (var i = 0; i < item.loadQueue.length; i++) {
5179 item.loadQueue[i](item);
5180 }
5181 item.loadQueue = null;
5182 },
5183 loadNewest: function(callback) {
5184 this._load({}, callback);
5185 },
5186 loadAround: function(id, callback) {
5187 this._load({
5188 id: id
5189 }, callback);
5190 },
5191 loadNewer: function(callback) {
5192 var id = this._newestId;
5193 if (id >= this._newestId && this.reached.start) {
5194 callback(null, p.Stream.POSITION.NONE);
5195 return;
5196 }
5197 this._load({
5198 newer: id
5199 }, callback);
5200 },
5201 loadOlder: function(callback) {
5202 var id = this._oldestId;
5203 if (id <= this._oldestId && this.reached.end) {
5204 callback(null, p.Stream.POSITION.NONE);
5205 return;
5206 }
5207 this._load({
5208 older: id
5209 }, callback);
5210 },
5211 syncVotes: function(votes) {
5212 var itemVotes = votes.items;
5213 for (var id in this.items) {
5214 if (itemVotes[id]) {
5215 this.items[id].vote = itemVotes[id];
5216 }
5217 }
5218 },
5219 _load: function(options, callback) {
5220 var stream = this;
5221 options.flags = p.user.flags;
5222 p.api.get('items.get', p.merge(options, this.options), function(data) {
5223 var position = stream._processResponse(data);
5224 callback(data.items, position, data.error);
5225 });
5226 },
5227 _processResponse: function(data) {
5228 if (!data.items || !data.items.length) {
5229 return null;
5230 }
5231 this.reached.start = data.atStart || this.reached.start;
5232 this.reached.end = data.atEnd || this.reached.end;
5233 var oldestId, newestId;
5234 if (this.options.promoted) {
5235 data.items.sort(p.Stream.sortByPromoted);
5236 oldestId = data.items[data.items.length - 1].promoted;
5237 newestId = data.items[0].promoted;
5238 } else {
5239 data.items.sort(p.Stream.sortById);
5240 oldestId = data.items[data.items.length - 1].id;
5241 newestId = data.items[0].id;
5242 }
5243 var position = (oldestId < this._oldestId) ? p.Stream.POSITION.APPEND : p.Stream.POSITION.PREPEND;
5244 this._oldestId = Math.min(this._oldestId, oldestId);
5245 this._newestId = Math.max(this._newestId, newestId);
5246 var prev = null;
5247 var itemVotes = p.user.voteCache.votes.items;
5248 for (var i = 0; i < data.items.length; i++) {
5249 var item = data.items[i];
5250 item.thumb = CONFIG.PATH.THUMBS + item.thumb;
5251 item.image = (item.image.match(/\.mp4$/) ? CONFIG.PATH.VIDS : CONFIG.PATH.IMAGES) + item.image;
5252 item.fullsize = item.fullsize ? CONFIG.PATH.FULLSIZE + item.fullsize : null;
5253 item.vote = itemVotes[item.id] || 0;
5254 this.items[item.id] = item;
5255 }
5256 return position;
5257 }
5258});
5259p.Stream.POSITION = {
5260 NONE: 0,
5261 APPEND: 1,
5262 PREPEND: 2
5263};
5264p.Stream.FLAG_NAME = {
5265 1: 'SFW',
5266 2: 'NSFW',
5267 4: 'NSFL',
5268 8: 'NSFP'
5269};
5270p.Stream.sortById = function(a, b) {
5271 return (b.id - a.id);
5272};
5273p.Stream.sortByPromoted = function(a, b) {
5274 return (b.promoted - a.promoted);
5275};
5276(function($) {
5277 var rgba = function(r, g, b, a) {
5278 return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
5279 };
5280 $.fn.highlight = function(r, g, b, a, wait, cb) {
5281 var that = this;
5282 if (that.data('_highlightTimeout')) {
5283 return;
5284 }
5285 r = r || 255;
5286 g = g || 255;
5287 b = b || 255;
5288 a = a || 1;
5289 that.css('background-color', rgba(r, g, b, a));
5290 var step = function() {
5291 a -= 0.05;
5292 if (a <= 0) {
5293 that.data('_highlightTimeout', null);
5294 that.css('background-color', 'transparent');
5295 if (cb) {
5296 cb(that);
5297 }
5298 } else {
5299 that.css('background-color', rgba(r, g, b, a));
5300 that.data('_highlightTimeout', setTimeout(step, 50));
5301 }
5302 }
5303 that.data('_highlightTimeout', setTimeout(step, wait || 200));
5304 };
5305})(jQuery);
5306p.View.Overlay = p.View.Overlay || {};
5307p.View.Overlay.DeleteComment = p.View.Base.extend({
5308 name: 'overlay-delete-comment',
5309 resetViewport: false,
5310 template: '<div class="overlay-content"> <h2>Kommentar löschen</h2> </div> <div class="overlay-content"> <form id="comment-delete-form"> <div class="form-row"> <input type="text" class="wide" name="reason" placeholder="Grund"/> </div> <div class="form-row"> <input type="hidden" name="id" value="{commentId}"/> <input type="submit" value="Durch [gelöscht] ersetzen" id="comment-delete-soft"/> <input type="submit" value="Hart Löschen (inkl. aller antworten)" id="comment-delete-hard"/> </div> </form> </div> ',
5311 data: {
5312 commentId: 0
5313 },
5314 init: function(container, parent, $div) {
5315 var $comment = $div.parent();
5316 this.data.commentId = $comment.find('.permalink').attr('href').split(':comment')[1];
5317 this.parent(container, parent);
5318 },
5319 render: function() {
5320 this.parent();
5321 this.$container.find('form').submit(this.submit.bind(this));
5322 this.focus('input[name=reason]');
5323 },
5324 submit: function(ev) {
5325 var $button = this.$container.find('input[type=submit]:focus');
5326 var action = ($button.attr('id') == 'comment-delete-hard') ? 'comments.delete' : 'comments.softDelete';
5327 p.api.post(action, ev.target, this.posted.bind(this));
5328 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
5329 this.showLoader();
5330 return false;
5331 },
5332 posted: function(response) {
5333 p.mainView.closeOverlay();
5334 }
5335});
5336p.View.Stream = p.View.Stream || {};
5337p.View.Stream.Comments = p.View.Base.extend({
5338 template: ' <div class="comments-head"> <span class="pict">c</span> {"Kommentar".inflect(commentCount)} </div> <?js if(p.user.showAds) {?> <div class="comments-large-rectangle gpt" id="gpt-rectangle-comments" data-escobar="comments-rectangle-{p.ads.category()}"> </div> <?js } ?> <form class="comment-form" method="post"> <textarea class="comment" name="comment" required placeholder="Kommentar schreiben…"></textarea> <input type="hidden" name="parentId" value="0"/> <input type="hidden" name="itemId" value="{params.id}"/> <div> <input type="submit" value="Abschicken"/> <input type="button" value="Abbrechen" class="cancel"/> </div> </form> <form class="comment-edit-form" method="post"> <textarea class="comment" required name="comment"></textarea> <input type="hidden" name="commentId" value="0"/> <div> <input type="submit" value="Abschicken"/> <input type="button" value="Abbrechen" class="cancel"/> </div> </form> <div class="comments"> <?js var recurseComments = function( comments, level ) { ?> <div class="comment-box"> <?js for( var i = 0; i < comments.length; i++ ) { var c = comments[i]; ?> <div class="comment-box-inner"> <div class="comment{p.voteClass(c.vote)}" id="comment{c.id}"> <div class="comment-vote"> <span class="pict vote-up">+</span> <span class="pict vote-down">-</span> </div> <div class="comment-content"> {c.content.format()} </div> <div class="comment-foot"> <?js if(c.name == itemUser){?> <span class="user-comment-op">OP</span><?js}?> <a href="#user/{c.name}" class="user um{c.mark}">{c.name}</a> <?js if( p.shouldShowScore(c) ) {?> <span class="score" title="{c.up} up, {c.down} down">{"Punkt".inflect(c.score)}</span> <?js } else { ?> <span class="score-hidden" title="Score noch unsichtbar">â—â—â—</span> <?js } ?> <a href="#{tab}/{itemId}:comment{c.id}" class="time permalink" title="{c.date.readableTime()}">{c.date.relativeTime(true)}</a> <?js if( level < CONFIG.COMMENTS_MAX_LEVELS ) {?> <a href="#{tab}/{itemId}:comment{c.id}" class="comment-reply-link action"><span class="pict">r</span> antworten</a> <?js } ?> <?js if (c.children.length > 0) {?> <span class="fold fold-in action" title="Kommentare einklappen">[–]</span> <span class="fold fold-out action" title="Kommentare ausklappen">[+]</span> <span class="folded-comments-message"> (<span class="folded-comments-count"></span> eingeklappt) </span> <?js } ?> <?js if( p.user.admin ) {?> [ <span class="comment-delete action">del</span> / <a href="#{tab}/{itemId}:comment{c.id}" class="comment-edit-link action">edit</a> ] <?js } ?> </div> </div> <?js if( c.children.length ) { recurseComments(c.children, level+1); } ?> </div> <?js } ?> </div> <?js }; ?> <?js recurseComments(comments, 1); ?> </div> ',
5339 init: function(container, parent) {
5340 this.stream = parent.stream;
5341 this.parent(container, parent);
5342 },
5343 load: function() {
5344 this.stream.loadInfo(this.data.params.id, this.loaded.bind(this));
5345 return false;
5346 },
5347 syncVotes: function(votes) {
5348 if (!this.data.comments) {
5349 return;
5350 }
5351 var commentVotes = votes.comments;
5352 for (var id in this.commentMap) {
5353 var newVote = commentVotes[id];
5354 var prevVote = this.commentMap[id].vote;
5355 if (newVote != prevVote) {
5356 var node = $('#comment' + id);
5357 this.commentMap[id].vote = newVote || 0;
5358 node.removeClass('voted-up voted-down');
5359 if (newVote) {
5360 node.addClass(newVote === 1 ? 'voted-up' : 'voted-down');
5361 }
5362 }
5363 }
5364 },
5365 loaded: function(item) {
5366 item.id = (item.id || this.data.itemId);
5367 this.data.linearComments = (item.id <= CONFIG.LAST_LINEAR_COMMENTS_ITEM);
5368 if (item.commentId) {
5369 p.user.voteCache.votes.comments[item.commentId] = 1;
5370 this.data.params.comment = 'comment' + item.commentId;
5371 }
5372 this.data.comments = this.prepareComments(item.comments);
5373 this.stream.items[this.data.params.id].comments = item.comments;
5374 this.data.commentCount = item.comments.length;
5375 this.data.tab = this.parentView.parentView.tab || 'new';
5376 this.data.itemId = item.id;
5377 this.data.itemUser = this.data.itemUser || item.user;
5378 this.render();
5379 },
5380 prepareComments: function(comments) {
5381 if (this.data.linearComments) {
5382 comments.sort(p.View.Stream.Comments.SortTime);
5383 } else {
5384 comments.sort(p.View.Stream.Comments.SortConfidenceTime);
5385 }
5386 var commentMap = {
5387 '0': {
5388 children: []
5389 }
5390 };
5391 var commentVotes = p.user.voteCache.votes.comments;
5392 for (var i = 0; i < comments.length; i++) {
5393 var comment = comments[i];
5394 comment.date = new Date(comment.created * 1000);
5395 comment.children = [];
5396 comment.vote = commentVotes[comment.id] || 0;
5397 comment.score = comment.up - comment.down;
5398 commentMap[comment.id] = comment;
5399 }
5400 for (var i = 0; i < comments.length; i++) {
5401 var comment = comments[i];
5402 var parent = commentMap[comment.parent];
5403 if (parent) {
5404 parent.children.push(comment);
5405 }
5406 }
5407 this.commentMap = commentMap;
5408 return commentMap['0'].children;
5409 },
5410 render: function() {
5411 this.parent();
5412 this.$commentForm = this.$container.find('.comment-form');
5413 this.$commentForm.submit(this.submitComment.bind(this));
5414 this.$commentForm.find('input.cancel').hide().click(this.cancelReply.bind(this));
5415 this.$commentEditForm = this.$container.find('.comment-edit-form');
5416 this.$commentEditForm.submit(this.submitCommentEdit.bind(this));
5417 this.$commentEditForm.find('input.cancel').click(this.cancelEdit.bind(this));
5418 this.$container.find('.comment-reply-link').fastclick(this.showReplyForm.bind(this));
5419 this.$container.find('.comment-edit-link').fastclick(this.showEditForm.bind(this));
5420 var that = this;
5421 this.$container.find('.vote-up').fastclick(function(ev) {
5422 return that.vote(ev, 1);
5423 });
5424 this.$container.find('.vote-down').fastclick(function(ev) {
5425 return that.vote(ev, -1);
5426 });
5427 this.$container.find('.comment-delete').fastclick(function() {
5428 p.mainView.showOverlay(p.View.Overlay.DeleteComment, $(this));
5429 });
5430 this.$container.find(".fold").fastclick(function(ev) {
5431 var box = $(ev.target).closest('.comment-box-inner').toggleClass('folded-in').children('.comment-box').slideToggle('fast');
5432 var count = box.find('.comment').length;
5433 $(ev.target).siblings('.folded-comments-message').fadeToggle('fast').children('.folded-comments-count').text(count);
5434 });
5435 if (this.data.params.comment) {
5436 this.focusComment(that.data.params.comment);
5437 this.data.params.comment = null;
5438 }
5439 p.ads.fill(this.$container.find('.gpt:visible'));
5440 if (CONFIG.ADS.AMAZON_REF) {
5441 this.insertAmazonRefId(CONFIG.ADS.AMAZON_REF, this.$container.find('a'));
5442 }
5443 if (CONFIG.ADS.HUBTRAFFIC.ENABLED) {
5444 this.insertRefParameters(CONFIG.ADS.HUBTRAFFIC.SEARCH_REGEXP, CONFIG.ADS.HUBTRAFFIC.QUERY_PARAMS, this.$container.find('a'));
5445 }
5446 },
5447 insertRefParameters: function(search, params, links) {
5448 for (var i = 0; i < links.length; i++) {
5449 var href = links[i].href;
5450 if (href.match(search)) {
5451 for (name in params) {
5452 href = href.setQueryParameter(name, params[name]);
5453 }
5454 links[i].href = href;
5455 }
5456 }
5457 },
5458 insertAmazonRefId: function(refId, links) {
5459 for (var i = 0; i < links.length; i++) {
5460 var link = links[i];
5461 if (link.href.match(/https?:\/\/[^\/]+amazon.(de|com)\/[^ !.]+/)) {
5462 link.href = link.href.replace(/\/tag=[\w\-_]+/, '/').setQueryParameter('tag', refId);
5463 }
5464 }
5465 },
5466 focusComment: function(comment) {
5467 var target = this.$container.find('#' + comment);
5468 if (target.length) {
5469 var jumpPos = target.offset().top - CONFIG.HEADER_HEIGHT - 80;
5470 target.highlight(180, 180, 180, 1);
5471 $(document).scrollTop(jumpPos);
5472 }
5473 },
5474 vote: function(ev, vote) {
5475 if (!p.mainView.requireLogin()) {
5476 return false;
5477 }
5478 var $comment = $(ev.currentTarget).parent().parent();
5479 var commentId = $comment.find('.permalink').attr('href').split(':comment')[1];
5480 var absoluteVote = vote;
5481 if (($comment.hasClass('voted-up') && vote === 1) || ($comment.hasClass('voted-down') && vote === -1)) {
5482 absoluteVote = 0;
5483 $comment.removeClass('voted-up voted-down');
5484 } else {
5485 $comment.removeClass('voted-up voted-down');
5486 $comment.addClass(vote === 1 ? 'voted-up' : 'voted-down');
5487 }
5488 var c = this.commentMap[commentId];
5489 p.adjustVote(c, absoluteVote, p.user.voteCache.votes.comments);
5490 p.api.post('comments.vote', {
5491 id: commentId,
5492 vote: absoluteVote
5493 });
5494 c.score = (c.up - c.down);
5495 var score = $comment.find('.score');
5496 score.text("Punkt".inflect(c.score));
5497 return false;
5498 },
5499 showReplyForm: function(ev) {
5500 if (!p.mainView.requireLogin()) {
5501 return false;
5502 }
5503 var $foot = $(ev.currentTarget.parentNode);
5504 if ($foot.has('.comment-form').length) {
5505 return;
5506 }
5507 var parentId = ev.currentTarget.href.split(':comment')[1];
5508 var $form = this.$commentForm.clone(true);
5509 $form.find('input.cancel').show();
5510 $form.find('input[name=parentId]').val(parentId);
5511 $foot.append($form);
5512 $form.find('textarea').val('').addClass('reply').focus();
5513 return false;
5514 },
5515 cancelReply: function(ev) {
5516 $(ev.currentTarget).parents('form').remove();
5517 },
5518 submitComment: function(ev) {
5519 if (!p.mainView.requireLogin()) {
5520 return false;
5521 }
5522 var $form = $(ev.currentTarget);
5523 var data = $form.serialize();
5524 $form.find('input,textarea,button,select').attr('disabled', 'disabled');
5525 p.api.post('comments.post', data, this.loaded.bind(this), function() {
5526 $form.find('input,textarea,button,select').removeAttr('disabled');
5527 });
5528 this.showLoader();
5529 return false;
5530 },
5531 showEditForm: function(ev) {
5532 var id = ev.currentTarget.href.split(':comment')[1];
5533 var $comment = $('#comment' + id);
5534 var $content = $('#comment' + id + ' .comment-content');
5535 if ($comment.has('.comment-edit-form').length) {
5536 return;
5537 }
5538 var $form = this.$commentEditForm.clone(true);
5539 $form.find('textarea').val(this.commentMap[id].content);
5540 $form.find('input[name=commentId]').val(id);
5541 $form.show();
5542 $content.after($form);
5543 $content.hide();
5544 $form.find('textarea').focus();
5545 return false;
5546 },
5547 cancelEdit: function(ev) {
5548 var id = $(ev.currentTarget).parents('form').find('input[name=commentId]').val();
5549 var $comment = $('#comment' + id);
5550 $comment.find('.comment-edit-form').remove();
5551 $comment.find('.comment-content').show();
5552 },
5553 submitCommentEdit: function(ev) {
5554 var $form = $(ev.currentTarget);
5555 var data = $form.serialize();
5556 $form.find('input,textarea,button,select').attr('disabled', 'disabled');
5557 p.api.post('comments.edit', data, this.loaded.bind(this), function() {
5558 $form.find('input,textarea,button,select').removeAttr('disabled');
5559 });
5560 this.showLoader();
5561 return false;
5562 }
5563});
5564p.View.Stream.Comments.SortConfidenceTime = function(a, b) {
5565 return (b.confidence === a.confidence ? a.created - b.created : b.confidence - a.confidence);
5566};
5567p.View.Stream.Comments.SortTime = function(a, b) {
5568 return (a.created - b.created);
5569};
5570p.View.Overlay = p.View.Overlay || {};
5571p.View.Overlay.EditTags = p.View.Base.extend({
5572 name: 'overlay-edit-tags',
5573 resetViewport: false,
5574 template: '<div class="overlay-content"> <h2>Tags Bearbeiten</h2> </div> <div class="overlay-content"> <form id="edit-tag-form"> <?js for( var i = 0; i < tags.length; i++ ) { var t = tags[i]; ?> <div class="form-row"> <label> <input class="tag-select" type="checkbox" name="tags[]" value="{t.id}"/> {{t.tag}} ~ <a href="/user/{t.user}">{t.user}</a>, score [<?js print(t.up-t.down);?>]: <?js for( var j = 0; j < t.votes.length; j++ ) { var v = t.votes[j]; ?> <?js print(v.vote > 0 ? \'+\' : \'-\'); ?><a href="/user/{v.user}">{v.user}</a> <?js } ?> </label> </div> <?js } ?> <p> <span class="action" id="edit-tags-invert">Auswahl invertieren</span> </p> <div class="form-row"> <input type="hidden" name="itemId" value="{itemId}"/> <input type="checkbox" name="banUsers" id="delete-ban-user"/> <label class="checkbox-label" for="delete-ban-user">Benutzer Sperren für</label> <input type="text" name="days" class="number" value="1"/> Tage <input type="hidden" name="mode" value="2"> <span class="field-details">(Permaban (0) hier nicht erlaubt; bestehende Bans werden nicht überschrieben)</span> </div> <div class="form-row"> <input type="submit" value="Ausgewählte Tags Löschen"/> </div> </form> </div> ',
5575 data: {
5576 itemId: 0
5577 },
5578 init: function(container, parent, $el) {
5579 this.data.itemId = $el.data('id');
5580 this.parent(container, parent);
5581 },
5582 load: function() {
5583 p.api.get('tags.details', {
5584 itemId: this.data.itemId
5585 }, this.loaded.bind(this));
5586 return false;
5587 },
5588 loaded: function(response) {
5589 response.tags.sort(p.View.Stream.Tags.SortConfidence);
5590 this.data.tags = response.tags;
5591 this.render();
5592 },
5593 render: function() {
5594 this.parent();
5595 this.$container.find('#edit-tags-invert').fastclick(this.invertSelection.bind(this));
5596 this.$container.find('#edit-tag-form').submit(this.submit.bind(this));
5597 },
5598 invertSelection: function() {
5599 this.$container.find('input.tag-select').each(function() {
5600 this.checked = !this.checked;
5601 });
5602 },
5603 submit: function(ev) {
5604 p.api.post('tags.delete', ev.target, this.posted.bind(this));
5605 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
5606 this.showLoader();
5607 return false;
5608 },
5609 posted: function(response) {
5610 p.mainView.closeOverlay();
5611 }
5612});
5613p.View.Overlay.EditTags.SortConfidence = function(a, b) {
5614 return b.confidence - a.confidence;
5615};
5616p.View.Stream = p.View.Stream || {};
5617p.View.Stream.Tags = p.View.Base.extend({
5618 template: '<div class="tags"> <?js for( var i = 0; i < tags.length; i++ ) { var t = tags[i]; ?> <span id="tag-{t.id}" class="tag{p.voteClass(t.vote)} {t.qualityClass}"> <a href="#{tab}/{{t.link}}" class="tag-link">{{t.tag}}</a> <span href="" class="vote-up">+</span> <span href="" class="vote-down">−</span> </span> <?js } ?> <?js if( p.user.admin ) { ?> [<span class="action" id="item-edit-tags" data-id="{params.id}">edit</span>] <?js } ?> <?js if( badTagsCount > 0 ) {?> <span class="action tags-expand">{"weiter".inflect(badTagsCount,"e","en")} anzeigen…</span> <?js } ?> <a href="" class="add-tags-link action">Tags hinzufügen…</a> </div> <form class="tag-form" method="post"> <input type="text" class="item-tagsinput" name="tags"/> <input type="hidden" name="itemId" value="{params.id}"/> <input type="submit" value="Tags speichern"/> <input type="button" value="Abbrechen" class="cancel"/> </form>',
5619 addedTagInput: false,
5620 init: function(container, parent) {
5621 this.stream = parent.stream;
5622 this.parent(container, parent);
5623 this.data.tab = (this.parentView.parentView.tab == 'top') ? 'top' : 'new';
5624 },
5625 syncVotes: function(votes) {
5626 if (!this.data.tags) {
5627 return;
5628 }
5629 var tagVotes = votes.tags;
5630 for (var i = 0; i < this.data.tags.length; i++) {
5631 var tag = this.data.tags[i];
5632 var newVote = tagVotes[tag.id];
5633 var oldVote = tag.vote;
5634 if (newVote != oldVote) {
5635 tag.vote = newVote || 0;
5636 var node = $('#tag-' + tag.id);
5637 node.removeClass('voted-up voted-down');
5638 if (newVote) {
5639 node.addClass(newVote === 1 ? 'voted-up' : 'voted-down');
5640 }
5641 }
5642 }
5643 },
5644 load: function() {
5645 this.stream.loadInfo(this.data.params.id, this.loaded.bind(this));
5646 return false;
5647 },
5648 loaded: function(item) {
5649 this.data.goodTagsCount = 0;
5650 this.data.badTagsCount = 0;
5651 if (item.tagIds && item.tagIds.length) {
5652 for (var i = 0; i < item.tagIds.length; i++) {
5653 p.user.voteCache.votes.tags[item.tagIds[i]] = 1;
5654 }
5655 }
5656 item.tags.sort(p.View.Stream.Tags.SortConfidence);
5657 var tagVotes = p.user.voteCache.votes.tags;
5658 var goodTagsCount = 0,
5659 badTagsCount = 0;
5660 for (var i = 0; i < item.tags.length; i++) {
5661 var tag = item.tags[i];
5662 var linkPrefix = tag.tag.match(/^\d+$/) ? '+' : '';
5663 tag.link = linkPrefix + encodeURIComponent(tag.tag);
5664 tag.vote = tagVotes[tag.id] || 0;
5665 if (tag.confidence > CONFIG.TAGS_MIN_CONFIDENCE && (goodTagsCount < CONFIG.TAGS_MAX_DISPLAY || tag.tag === 'nsfw' || tag.tag === 'nsfl' || tag.tag === 'nsfp')) {
5666 tag.qualityClass = 'tag-good';
5667 goodTagsCount++;
5668 } else {
5669 tag.qualityClass = 'tag-bad';
5670 badTagsCount++;
5671 }
5672 }
5673 this.data.goodTagsCount = goodTagsCount;
5674 this.data.badTagsCount = badTagsCount;
5675 this.stream.items[this.data.params.id].tags = item.tags;
5676 this.data.tags = item.tags;
5677 this.render();
5678 },
5679 render: function() {
5680 this.parent();
5681 this.addedTagInput = false;
5682 this.$container.find('.tag-form').submit(this.saveTags.bind(this));
5683 this.$container.find('.add-tags-link').fastclick(this.showTagForm.bind(this));
5684 this.$container.find('.tag-form .cancel').fastclick(this.hideTagForm.bind(this));
5685 var that = this;
5686 this.$container.find('span.vote-up').fastclick(function(ev) {
5687 return that.vote(ev, 1);
5688 });
5689 this.$container.find('span.vote-down').fastclick(function(ev) {
5690 return that.vote(ev, -1);
5691 });
5692 this.$container.find('.tags-expand').fastclick(function(ev) {
5693 $(ev.currentTarget).hide();
5694 $('.tag-bad').css('display', 'inline-block');
5695 })
5696 this.$container.find('#item-edit-tags').fastclick(function() {
5697 p.mainView.showOverlay(p.View.Overlay.EditTags, $(this));
5698 });
5699 },
5700 saveTags: function(ev) {
5701 if (!p.mainView.requireLogin()) {
5702 return false;
5703 }
5704 var $form = $(ev.currentTarget);
5705 var data = $form.serialize();
5706 $form.find('input,textarea,button,select').attr('disabled', 'disabled');
5707 p.api.post('tags.add', data, this.loaded.bind(this), function() {
5708 $form.find('input,textarea,button,select').removeAttr('disabled');
5709 });
5710 return false;
5711 },
5712 showTagForm: function(ev) {
5713 if (!p.mainView.requireLogin()) {
5714 return false;
5715 }
5716 this.$container.find('.add-tags-link').hide();
5717 this.$container.find('.tag-form').show();
5718 var input = this.$container.find('input.item-tagsinput');
5719 if (!this.addedTagInput) {
5720 input.tagsInput(CONFIG.TAGS_INPUT_SETTINGS);
5721 this.addedTagInput = true;
5722 this.focus('.tagsinput input');
5723 }
5724 return false;
5725 },
5726 hideTagForm: function(ev) {
5727 this.$container.find('.add-tags-link').show();
5728 this.$container.find('.tag-form').hide();
5729 return false;
5730 },
5731 vote: function(ev, vote) {
5732 if (!p.mainView.requireLogin()) {
5733 return false;
5734 }
5735 var $tag = $(ev.currentTarget).parent();
5736 var tagId = $tag.attr('id').split('-')[1];
5737 var absoluteVote = vote;
5738 if (($tag.hasClass('voted-up') && vote === 1) || ($tag.hasClass('voted-down') && vote === -1)) {
5739 absoluteVote = 0;
5740 $tag.removeClass('voted-up voted-down');
5741 } else {
5742 $tag.removeClass('voted-up voted-down');
5743 $tag.addClass(vote === 1 ? 'voted-up' : 'voted-down');
5744 }
5745 for (var i = 0; i < this.data.tags.length; i++) {
5746 if (this.data.tags[i].id == tagId) {
5747 p.adjustVote(this.data.tags[i], absoluteVote, p.user.voteCache.votes.tags);
5748 break;
5749 }
5750 }
5751 p.api.post('tags.vote', {
5752 id: tagId,
5753 vote: absoluteVote
5754 });
5755 return false;
5756 }
5757});
5758p.View.Stream.Tags.SortConfidence = function(a, b) {
5759 return b.confidence - a.confidence;
5760};
5761p.View.Overlay = p.View.Overlay || {};
5762p.View.Overlay.DeleteItem = p.View.Base.extend({
5763 name: 'overlay-delete-item',
5764 resetViewport: false,
5765 template: '<div class="overlay-content"> <h2>Bild löschen</h2> </div> <div class="overlay-content"> <form id="image-delete-form"> <div class="form-row"> <label class="checkbox-label"> <input name="reason" type="radio" value="custom" checked id="custom"/> </label> <input type="text" class="text-line" name="customReason" placeholder="Grund"/> <label> <input name="reason" type="radio" value="Regel #1 - Bild unzureichend getagged (nsfw/nsfl)"/> Regel #1 - Bild unzureichend getagged (nsfw/nsfl) </label> <label> <input name="reason" type="radio" value="Regel #1 - Falsche/Sinnlose Nutzung des NSFP Filters"/> Regel #1 - Falsche/Sinnlose Nutzung des NSFP Filters </label> <label> <input name="reason" type="radio" value="Regel #2 - Gore/Porn/Suggestive Bilder mit Minderjährigen"/> Regel #2 - Gore/Porn/Suggestive Bilder mit Minderjährigen </label> <label> <input name="reason" type="radio" value="Regel #3 - Tierporn"/> Regel #3 - Tierporn </label> <label> <input name="reason" type="radio" value="Regel #4 - Stumpfer Rassismus/Nazi-Nostalgie"/> Regel #4 - Stumpfer Rassismus/Nazi-Nostalgie </label> <label> <input name="reason" type="radio" value="Regel #5 - Werbung/Spam"/> Regel #5 - Werbung/Spam </label> <label> <input name="reason" type="radio" value="Regel #6 - Infos zu Privatpersonen"/> Regel #6 - Infos zu Privatpersonen </label> <label> <input name="reason" type="radio" value="Regel #7 - Bildqualität"/> Regel #7 - Bildqualität </label> <label> <input name="reason" type="radio" value="Regel #8 - Ähnliche Bilder in Reihe"/> Regel #8 - Ähnliche Bilder in Reihe </label> <label> <input name="reason" type="radio" value="Regel #11 - Multiaccount"/> Regel #11 - Multiaccount </label> <label> <input name="reason" type="radio" value="Regel #12 - Warez/Logins zu Pay Sites"/> Regel #12 - Warez/Logins zu Pay Sites </label> <label> <input name="reason" type="radio" value="Regel #14 - Screamer/Sound-getrolle"/> Regel #14 - Screamer/Sound-getrolle </label> <label> <input name="reason" type="radio" value="Regel #15 - reiner Musikupload"/> Regel #15 - reiner Musikupload </label> <label> <input name="reason" type="radio" value="Müllpost"/> Müllpost </label> <label> <input name="reason" type="radio" value="Repost"/> Repost </label> <label> <input name="reason" type="radio" value="Digital Millennium Copyright Act Anfrage"/> DMCA Anfrage </label> <label> <input name="reason" type="radio" value="Auf Anfrage"/> Auf Anfrage </label> </div> <div class="form-row divider"> <input type="checkbox" name="notifyUser" checked="checked" id="delete-comment-notify"/> <label class="checkbox-label" for="delete-comment-notify">Benutzer benachrichtigen</label> </div> <div class="form-row"> <input type="checkbox" name="banUser" id="delete-ban-user"/> <label class="checkbox-label" for="delete-ban-user">Benutzer Sperren für</label> <input type="text" name="days" class="number" value="1"/> Tage (0 = für immer) <input type="hidden" name="mode" value="2"/> </div> <div class="form-row"> </div> <div class="form-row"> <input type="hidden" name="id" value="{itemId}"/> <input type="submit" value="Löschen" id="image-delete"/> </div> </form> </div> ',
5766 data: {
5767 itemId: 0
5768 },
5769 init: function(container, parent, $el) {
5770 this.data.itemId = $el.data('id');
5771 this.parent(container, parent);
5772 },
5773 render: function() {
5774 this.parent();
5775 this.$container.find('form').submit(this.submit.bind(this));
5776 var customRadionButton = this.$container.find('input[name=reason][value=custom]');
5777 this.$container.find('input[name=customReason]').bind('focus onchange', function() {
5778 customRadionButton.prop('checked', true);
5779 });
5780 this.focus('input[name=customReason]');
5781 },
5782 submit: function(ev) {
5783 p.api.post('items.delete', ev.target, this.posted.bind(this));
5784 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
5785 this.showLoader();
5786 return false;
5787 },
5788 posted: function(response) {
5789 p.mainView.closeOverlay();
5790 }
5791});
5792p.View.Stream = p.View.Stream || {};
5793p.View.Stream.Item = p.View.Base.extend({
5794 template: '<div class="item-pointer"> </div> <div class="item-container-content"> <?js if( p.user.admin ) {?> <svg class="flags flags-{item.flags}" viewBox="0 0 10 10"> <polygon points="0,0 10,0 0,10"></polygon> </svg> <?js } ?> <div class="item-image-wrapper"> <?js if( item.video ) { ?> <?js if(supportsAutoplay) {?> <video class="item-image" src="{item.image}" type="video/mp4" loop autoplay preload="auto"></video> <?js } else { ?> <video class="item-image" webkit-playsinline playsinline poster="{item.thumb}" src="{item.image}" type="video/mp4" loop preload="metadata"></video> <svg class="video-play-button" viewBox="0 0 200 200"> <circle cx="100" cy="100" r="90" fill="none" stroke-width="15" stroke="#fff"></circle> <polygon points="70, 55 70, 145 145, 100" fill="#fff"></polygon> </svg> <?js } ?> <div class="video-controls<?js if(item.audio){?> has-audio<?js}?>"> <div class="video-position-bar-background"> <div class="video-position"></div> </div> <?js if(item.audio) {?> <div class="audio-controls"> <svg class="audio-state" viewBox="0 0 75 75"> <polygon class="audio-speaker" points="39.389,13.769 22.235,28.606 6,28.606 6,47.699 21.989,47.699 39.389,62.75 39.389,13.769"/> <g class="audio-x"> <path d="M 49,50 69,26"/> <path d="M 69,50 49,26"/> </g> <g class="audio-wave"> <path class="audio-wave-1" d="M 48,49 C 50,46 51,42 51,38 C 51,34 50,31 48,28"/> <path class="audio-wave-2" d="M 55,21 C 59,26 61,32 61,38 C 61,45 59,51 55,56"/> <path class="audio-wave-3" d="M 62,63 C 67,56 70,48 70,38 C 70,29 67,21 62,14"/> </g> </svg> <div class="audio-volume-controls"> <div class="audio-volume-bar"></div> <div class="audio-volume-slider"></div> </div> </div> <?js } ?> </div> <?js } else { ?> <img class="item-image" src="{item.image}"/> <?js if(item.fullsize) { ?> <a href="{item.fullsize}" target="_blank" class="item-fullsize-link">+</a> <?js } ?> <?js } ?> <?js if( p.user.showAds ) { ?> <div class="stream-prev" title="Neuer"><span class="stream-prev-icon"></span></div> <div class="stream-next" title="Älter"><span class="stream-next-icon"></span></div> <?js } else { ?> <div class="stream-prev arrow pict" title="Neuer"><</div> <div class="stream-next arrow pict" title="Älter">></div> <?js } ?> </div> <div class="item-info"> <div class="item-vote{p.voteClass(item.vote)}"> <span class="pict vote-up">+</span> <span class="pict vote-down">-</span> <?js if( p.shouldShowScore(item) ) {?> <span class="score<?js if(!p.olderThanMinAge(item)){?> score-young<?js}?>" title="{item.up} up, {item.down} down"><?js print(item.up - item.down)?></span> <?js } else { ?> <span class="score-hidden" title="Score noch unsichtbar">â—â—â—</span> <?js } ?> </div> <?js if( item.user != p.user.name ) {?> <span class="pict vote-fav{p.favClass(item.vote)}">*</span> <?js } ?> <div class="item-details"> <a class="time" title="{item.date.readableTime()}" href="/new/{item.id}">{item.date.relativeTime(true)}</a> <span class="time">von</span> <a href="#user/{item.user}" class="user um{item.mark}">{item.user}</a> <span class="item-source"> <?js if( item.source ) {?> <span class="pict">s</span> <a href="{{item.source}}" target="_blank">{{item.source.hostName()}}</a> <?js } else { ?> <span class="pict">s</span>upload</span> <?js } ?> </span> <?js if( !item.video ) {?> <span class="item-google-search"> <span class="pict">g</span> <a href="https://www.google.com/searchbyimage?hl=en&safe=off&site=search&image_url=http:{item.image}" target="_blank"> Bild googeln </a> </span> <?js } ?> <?js if( p.user.admin ) { ?> [<span class="action" id="item-delete" data-id="{item.id}">del</span>] [<a href="/new/phash.{item.id}.12">phash</a>] <?js } ?> </div> <div class="item-tags"></div> </div> <?js if(p.user.showAds) {?> <div class="divider-full-banner gpt" id="gpt-divider-banner" data-escobar="banner-{p.ads.category()}"> </div> <div class="divider-large-rectangle gpt" id="gpt-divider-rectangle" data-escobar="comments-rectangle-{p.ads.category()}"> </div> <?js } ?> <div class="item-comments"></div> </div> ',
5795 swipeDistance: 96,
5796 navTop: -1,
5797 mouseIsDown: false,
5798 init: function(container, parent) {
5799 this.stream = parent.stream;
5800 this.parent(container, parent);
5801 },
5802 show: function(rowIndex, itemData, defaultHeight, jumpToComment) {
5803 if (this.removed) {
5804 return;
5805 }
5806 this.data.supportsAutoplay = !p.mobile;
5807 this.data.item = itemData;
5808 this.data.item.video = !!this.data.item.image.match(/\.mp4$/);
5809 this.data.item.date = new Date(itemData.created * 1000);
5810 this.parent();
5811 this.$image = this.$container.find('.item-image');
5812 if (this.data.item.width && this.data.item.height) {
5813 var imageWidth = p.mobile ? this.$container.width() : Math.min(this.data.item.width, this.$container.width());
5814 var imageHeight = (this.data.item.height / this.data.item.width) * imageWidth;
5815 this.$image.css('width', imageWidth | 0);
5816 this.$image.css('height', imageHeight | 0);
5817 }
5818 var T = CONFIG.LAYOUT.THUMB;
5819 var offset = rowIndex * (T.WIDTH + T.PADDING) + T.WIDTH / 2 - T.PADDING - 4;
5820 this.$container.find('.item-pointer').css('left', offset);
5821 var that = this;
5822 this.$itemVote = this.$container.find('.item-vote');
5823 this.$itemVote.find('.vote-up').fastclick(function(ev) {
5824 return that.vote(ev, 1);
5825 });
5826 this.$itemVote.find('.vote-down').fastclick(function(ev) {
5827 return that.vote(ev, -1);
5828 });
5829 this.$itemFav = this.$container.find('.vote-fav')
5830 this.$itemFav.fastclick(function(ev) {
5831 return that.fav(ev);
5832 });
5833 this.$container.find('#item-delete').fastclick(function() {
5834 p.mainView.showOverlay(p.View.Overlay.DeleteItem, $(this));
5835 });
5836 this.tagView = new p.View.Stream.Tags(this.$container.find('.item-tags'), this);
5837 this.tagView.show({
5838 id: itemData.id
5839 });
5840 this.commentView = new p.View.Stream.Comments(this.$container.find('.item-comments'), this);
5841 this.commentView.show({
5842 id: itemData.id,
5843 comment: jumpToComment
5844 });
5845 if (this.data.item.video) {
5846 this.videoSetup(imageWidth);
5847 } else {
5848 this.$image.fastclick(this.parentView.hideItem.bind(this.parentView));
5849 }
5850 if (p.mobile) {
5851 this.setupSwipe();
5852 } else {
5853 this.$streamPrev = this.$container.find('.stream-prev');
5854 this.$streamNext = this.$container.find('.stream-next');
5855 this.$streamPrev.show().fastclick(this.parentView.prev.bind(this.parentView));
5856 this.$streamNext.show().fastclick(this.parentView.next.bind(this.parentView));
5857 this.onScrollBound = this.onScroll.bind(this);
5858 $(window).bind('scroll', this.onScrollBound);
5859 this.onScroll();
5860 }
5861 p.ads.fill(this.$container.find('.gpt:visible'));
5862 },
5863 onScroll: function() {
5864 var ih = this.$image.height();
5865 var h = ih / 2 - 32;
5866 var p = ($(window).scrollTop() - this.$container.offset().top).limit(32, ih - 32 - 96) + 96;
5867 if (p == this.navTop) {
5868 return;
5869 }
5870 this.navTop = p;
5871 this.$streamPrev.css('padding-top', p);
5872 this.$streamNext.css('padding-top', p);
5873 },
5874 remove: function() {
5875 if (this.video) {
5876 this.video.pause();
5877 }
5878 this.parent();
5879 this.removed = true;
5880 if (this.updateVideoPositionInterval) {
5881 clearInterval(this.updateVideoPositionInterval);
5882 }
5883 if (this.onScrollBound) {
5884 $(window).unbind('scroll', this.onScrollBound);
5885 }
5886 if (this.mouseUpBound) {
5887 $(window).unbind('mouseup', this.mouseUpBound);
5888 }
5889 },
5890 syncVotes: function(votes) {
5891 if (!this.data.item) {
5892 return;
5893 }
5894 var vote = votes.items[this.data.item.id];
5895 if (vote && this.$itemVote) {
5896 this.$itemVote.removeClass('voted-up voted-down');
5897 this.$itemVote.addClass(vote > 0 ? 'voted-up' : 'voted-down');
5898 this.$itemFav.toggleClass('faved', (vote == 2));
5899 }
5900 if (this.commentView) {
5901 this.commentView.syncVotes(votes);
5902 }
5903 if (this.tagView) {
5904 this.tagView.syncVotes(votes);
5905 }
5906 },
5907 fav: function(ev) {
5908 if (!p.mainView.requireLogin()) {
5909 return false;
5910 }
5911 var addFav = !this.$itemFav.hasClass('faved');
5912 var absoluteVote = addFav ? 2 : 1;
5913 this.$itemFav.toggleClass('faved', addFav);
5914 this.$itemVote.addClass('voted-up');
5915 this.$itemVote.removeClass('voted-down');
5916 var cachedItem = this.stream.items[this.data.item.id];
5917 p.adjustVote(cachedItem, absoluteVote, p.user.voteCache.votes.items);
5918 var $score = this.$itemVote.find('.score');
5919 $score.text(cachedItem.up - cachedItem.down);
5920 p.api.post('items.vote', {
5921 id: this.data.item.id,
5922 vote: absoluteVote
5923 });
5924 return false;
5925 },
5926 vote: function(ev, vote) {
5927 if (!p.mainView.requireLogin()) {
5928 return false;
5929 }
5930 var absoluteVote = vote;
5931 if ((this.$itemVote.hasClass('voted-up') && vote === 1) || (this.$itemVote.hasClass('voted-down') && vote === -1)) {
5932 absoluteVote = 0;
5933 this.$itemVote.removeClass('voted-up voted-down');
5934 } else {
5935 this.$itemVote.removeClass('voted-up voted-down');
5936 this.$itemVote.addClass(vote === 1 ? 'voted-up' : 'voted-down');
5937 }
5938 this.$itemFav.removeClass('faved');
5939 var cachedItem = this.stream.items[this.data.item.id];
5940 p.adjustVote(cachedItem, absoluteVote, p.user.voteCache.votes.items);
5941 var $score = this.$itemVote.find('.score');
5942 $score.text(cachedItem.up - cachedItem.down);
5943 p.api.post('items.vote', {
5944 id: this.data.item.id,
5945 vote: absoluteVote
5946 });
5947 return false;
5948 },
5949 videoSetup: function(imageWidth) {
5950 this.video = this.$image[0];
5951 this.$volumeControls = this.$container.find('.audio-volume-controls');
5952 this.$videoControls = this.$container.find('.video-controls');
5953 this.$videoControls.css({
5954 width: imageWidth
5955 }).show();
5956 this.$videoPosition = this.$container.find('.video-position');
5957 this.videoThrough = 0;
5958 this.updateVideoPositionInterval = setInterval(this.videoUpdatePosition.bind(this), 16);
5959 if (p.mobile) {
5960 this.$playButton = this.$container.find('.video-play-button');
5961 this.$image.fastclick(this.videoPausePlay.bind(this));
5962 this.$playButton.fastclick(this.videoPausePlay.bind(this));
5963 this.$container.find('svg.audio-state').fastclick(this.videoToggleMute.bind(this));
5964 } else {
5965 this.$image.fastclick(this.parentView.hideItem.bind(this.parentView));
5966 this.$videoControls.on('mousedown', this.videoPositionBarMouseDown.bind(this));
5967 this.mouseUpBound = this.videoControlsMouseUp.bind(this);
5968 $(window).on('mouseup', this.mouseUpBound);
5969 this.$videoControls.on('mousemove', this.videoControlsMouseMove.bind(this));
5970 this.$volumeControls.on('mousedown', this.audioVolumeMouseDown.bind(this));
5971 this.$container.find('svg.audio-state').on('mousedown', this.videoToggleMute.bind(this));
5972 }
5973 if (this.data.item.audio) {
5974 this.videoSetVolume(p.user.video.muted ? 0 : p.user.video.volume);
5975 }
5976 },
5977 videoPausePlay: function(play) {
5978 if ((this.video.paused || play === true) && play !== false) {
5979 this.$container.find('.video-play-button').hide();
5980 this.video.play();
5981 } else {
5982 this.$container.find('.video-play-button').show();
5983 this.video.pause();
5984 }
5985 },
5986 videoUpdatePosition: function() {
5987 if (!this.video || !this.video.duration) {
5988 return;
5989 }
5990 var through = (this.video.currentTime / this.video.duration);
5991 if (through < this.videoThrough) {
5992 this.videoThrough = through;
5993 }
5994 this.videoThrough = 0.9 * this.videoThrough + 0.1 * through;
5995 this.$videoPosition.css('width', (this.videoThrough * 100).round(3) + '%')
5996 },
5997 videoPositionBarMouseDown: function(ev) {
5998 this.mouseDownOn = p.View.Stream.Item.TARGET.SEEK_CONTROLS;
5999 this.videoControlsMouseMove(ev)
6000 ev.preventDefault();
6001 ev.stopPropagation();
6002 },
6003 audioVolumeMouseDown: function(ev) {
6004 this.mouseDownOn = p.View.Stream.Item.TARGET.VOLUME_CONTROLS;
6005 this.videoControlsMouseMove(ev)
6006 ev.preventDefault();
6007 ev.stopPropagation();
6008 },
6009 videoControlsMouseUp: function(ev) {
6010 this.mouseDownOn = p.View.Stream.Item.TARGET.NOTHING;
6011 },
6012 videoControlsMouseMove: function(ev) {
6013 if (!this.video || !this.video.duration) {
6014 return;
6015 }
6016 if (this.mouseDownOn === p.View.Stream.Item.TARGET.SEEK_CONTROLS) {
6017 this.videoThrough = (ev.pageX - this.$videoControls.offset().left) / this.$videoControls.width();
6018 this.video.currentTime = this.video.duration * this.videoThrough;
6019 } else if (this.mouseDownOn === p.View.Stream.Item.TARGET.VOLUME_CONTROLS) {
6020 var volume = (ev.pageX - this.$volumeControls.offset().left) / this.$volumeControls.width();
6021 this.videoSetVolume(volume);
6022 }
6023 },
6024 videoSetVolume: function(volume) {
6025 if (!this.video) {
6026 return;
6027 }
6028 volume = volume.limit(0, 1);
6029 p.user.video.muted = volume === 0;
6030 if (volume !== 0) {
6031 p.user.video.volume = volume;
6032 }
6033 p.user.saveAudioSettings();
6034 this.video.volume = volume;
6035 this.video.muted = volume === 0;
6036 this.$volumeControls.find('.audio-volume-slider').css('left', (volume * 100) + '%');
6037 var svg = this.$container.find('.audio-state')[0];
6038 if (!svg) {
6039 return;
6040 }
6041 var volumeClass = 'audio-volume-' + ['0', '33', '66', '99'][Math.ceil(volume * 3)];
6042 svg.setAttribute('class', 'audio-state ' + volumeClass);
6043 },
6044 videoToggleMute: function(ev) {
6045 ev.preventDefault();
6046 ev.stopPropagation();
6047 if (!this.video) {
6048 return;
6049 }
6050 var isMuted = this.video.volume === 0 || this.video.muted;
6051 this.videoSetVolume(isMuted ? p.user.video.volume : 0);
6052 },
6053 lastTouch: {
6054 x: 0,
6055 y: 0
6056 },
6057 avgTouchDelta: {
6058 x: 0,
6059 y: 0
6060 },
6061 touchOffset: {
6062 x: 0,
6063 y: 0
6064 },
6065 setupSwipe: function() {
6066 this.$image.bind('touchstart', this.initSwipeImage.bind(this)).bind('touchmove', this.swipeImage.bind(this)).bind('touchend', this.endSwipeImage.bind(this));
6067 this.$container.find('.video-play-button').bind('touchstart', this.initSwipeImage.bind(this)).bind('touchmove', this.swipeImage.bind(this)).bind('touchend', this.endSwipeImage.bind(this));
6068 },
6069 initSwipeImage: function(ev) {
6070 var touch = ev.originalEvent.touches[0];
6071 this.lastTouch.x = touch.clientX;
6072 this.lastTouch.y = touch.clientY;
6073 this.avgTouchDelta.x = 0;
6074 this.avgTouchDelta.y = 0;
6075 this.touchOffset.x = 0;
6076 this.touchOffset.y = 0;
6077 },
6078 endSwipeImage: function(ev) {
6079 if (this.touchOffset.x > this.swipeDistance) {
6080 this.parentView.prev();
6081 } else if (this.touchOffset.x < -this.swipeDistance) {
6082 this.parentView.next();
6083 } else {
6084 this.touchOffset.x = 0;
6085 this.touchOffset.y = 0;
6086 this.$image.css('margin-left', this.touchOffset.x);
6087 if (this.$playButton) {
6088 this.$playButton.css('margin-left', this.touchOffset.x);
6089 }
6090 }
6091 },
6092 swipeImage: function(ev) {
6093 if (ev.originalEvent.touches.length > 1) {
6094 return;
6095 }
6096 var touch = ev.originalEvent.touches[0];
6097 var deltaX = this.lastTouch.x - touch.clientX;
6098 var deltaY = this.lastTouch.y - touch.clientY;
6099 this.lastTouch.x = touch.clientX;
6100 this.lastTouch.y = touch.clientY;
6101 this.avgTouchDelta.x = Math.abs(this.avgTouchDelta.x) * 0.8 + Math.abs(deltaX) * 0.2;
6102 this.avgTouchDelta.y = Math.abs(this.avgTouchDelta.y) * 0.8 + Math.abs(deltaY) * 0.2;
6103 if (Math.abs(this.avgTouchDelta.x) > Math.abs(this.avgTouchDelta.y)) {
6104 ev.preventDefault();
6105 this.touchOffset.x -= deltaX;
6106 this.touchOffset.y -= deltaY;
6107 } else {
6108 this.touchOffset.x = 0;
6109 this.touchOffset.y = 0;
6110 }
6111 this.$image.css('margin-left', this.touchOffset.x);
6112 if (this.$playButton) {
6113 this.$playButton.css('margin-left', this.touchOffset.x);
6114 }
6115 }
6116});
6117p.View.Stream.Item.TARGET = {
6118 NOTHING: 0,
6119 SEEK_CONTROLS: 1,
6120 VOLUME_CONTROLS: 2
6121};
6122p.View.Stream = p.View.Stream || {};
6123p.View.Stream.Main = p.View.Base.extend({
6124 baseURL: '',
6125 template: ' <div id="stream"></div> <div class="clear"></div> ',
6126 SCROLL: {
6127 NONE: 1,
6128 THUMB: 2,
6129 FULL: 4
6130 },
6131 scrollPosition: 0,
6132 loadInProgress: false,
6133 loadingTargetDistance: 512,
6134 checkScrollPositionInterval: null,
6135 hasItems: false,
6136 prependNextSection: false,
6137 jumpToItem: null,
6138 jumpToComment: null,
6139 currentItemId: null,
6140 _scrolledToFullView: false,
6141 itemsPerRow: 6,
6142 rowMargin: 4,
6143 prefetched: [],
6144 init: function(container, parent) {
6145 this.handleThumbLinkBound = this.handleThumbLink.bind(this);
6146 this.parent(container, parent);
6147 this.loadedBound = this.loaded.bind(this);
6148 this.scrollBound = this.onscroll.bind(this);
6149 $(window).scroll(this.scrollBound);
6150 this.checkScrollPositionInterval = setInterval(this.scrollBound, 1000);
6151 this.$itemContainerTemplate = $('<div class="item-container"/>');
6152 },
6153 fragmentChange: function(fragment) {
6154 if (this.currentItemSubview && this.currentItemSubview.commentView && fragment) {
6155 this.currentItemSubview.commentView.focusComment(fragment);
6156 }
6157 },
6158 show: function(params) {
6159 if (!params.userName) {
6160 this.tab = params.tab || 'top';
6161 } else {
6162 this.tab = null;
6163 }
6164 if (params.tab === 'stalk' && !p.user.paid) {
6165 p.navigateTo('pr0mium');
6166 return;
6167 }
6168 p.mainView.setTab(this.tab);
6169 var q = params.userName ? params.userName + ':' + params.userTab + (params.tags ? ' ' + params.tags : '') : params.tags || '';
6170 $('input.q').val(q.replace(/^\+(\d)/, '$1'));
6171 var newBaseURL = (p._hasPushState ? '/' : '#') +
6172 (params.userName ? ('user/' + params.userName + '/' + params.userTab + '/' + (params.tags ? encodeURIComponent(params.tags) + '/' : '')) : (this.tab + '/' + (params.tags ? encodeURIComponent(params.tags) + '/' : '')));
6173 if (newBaseURL == this.baseURL) {
6174 this.data.params = params;
6175 if (this.data.params.itemId) {
6176 var $target = $('#item-' + this.data.params.itemId);
6177 if ($target.length) {
6178 $(document).scrollTop($target.offset().top - CONFIG.HEADER_HEIGHT);
6179 this.showItem($target, this.SCROLL.THUMB);
6180 return;
6181 }
6182 } else if (p.dispatchFromHistory) {
6183 if (this.$currentItem) {
6184 this.$itemContainer.remove();
6185 this.currentItemSubview.remove();
6186 this.$itemContainer = null;
6187 this.$currentItem = null;
6188 this.currentItemId = null;
6189 $(document).scrollTop(this.scrollPosition);
6190 }
6191 return;
6192 }
6193 }
6194 this.children = [];
6195 var options = {};
6196 if (params.tab === 'top' || (!params.tab && !params.userName)) {
6197 options.promoted = 1;
6198 } else if (params.tab === 'stalk') {
6199 options.following = 1;
6200 }
6201 if (params.tags) {
6202 options.tags = params.tags;
6203 }
6204 if (params.userName && params.userTab === 'uploads') {
6205 options.user = params.userName;
6206 } else if (params.userName && params.userTab === 'likes') {
6207 options.likes = params.userName;
6208 if (params.userName === p.user.name) {
6209 options.self = true;
6210 }
6211 }
6212 this.stream = new p.Stream(options);
6213 this.baseURL = newBaseURL;
6214 this.hasItems = false;
6215 this.needsFirstRendering = true;
6216 this.parent(params);
6217 },
6218 resize: function() {
6219 this.jumpToItem = this.currentItemId;
6220 this.jumpToComment = p.getFragment();
6221 this.$streamContainer.html('');
6222 this.loaded(this.stream.getLoadedItems(), p.Stream.POSITION.APPEND);
6223 this.parent();
6224 },
6225 hide: function() {
6226 $(window).unbind('scroll', this.scrollBound);
6227 clearInterval(this.checkScrollPositionInterval);
6228 this.parent();
6229 },
6230 syncVotes: function(votes) {
6231 if (this.stream) {
6232 this.stream.syncVotes(votes);
6233 }
6234 if (this.currentItemSubview) {
6235 this.currentItemSubview.syncVotes(votes);
6236 }
6237 },
6238 load: function() {
6239 this.loadInProgress = true;
6240 if (this.data.params.itemId) {
6241 this.jumpToItem = this.data.params.itemId;
6242 this.jumpToComment = p.getFragment();
6243 this.stream.loadAround(this.data.params.itemId, this.loadedBound);
6244 } else {
6245 this.stream.loadNewest(this.loadedBound);
6246 }
6247 this.showLoader();
6248 return false;
6249 },
6250 prepareThumbsForInsertion: function(html) {
6251 var thumbs = $(html);
6252 thumbs.find('a').fastclick(this.handleThumbLinkBound);
6253 return thumbs;
6254 },
6255 handleThumbLink: function(ev) {
6256 if (!p.isNormalClick(ev)) {
6257 return true;
6258 }
6259 ev.preventDefault();
6260 this.showItem($(ev.currentTarget), this.SCROLL.NONE);
6261 if (!this._wasHidden) {
6262 this.handleHashLink(ev);
6263 }
6264 this._wasHidden = false;
6265 return false;
6266 },
6267 loaded: function(items, position, error) {
6268 if (this.needsFirstRendering) {
6269 this.needsFirstRendering = false;
6270 this.render();
6271 this.$streamContainer = this.$container.find('#stream');
6272 this.$itemContainer = null;
6273 }
6274 this.hideLoader();
6275 this.itemsPerRow = p.mainView.thumbsPerRow;
6276 if (!items || !items.length) {
6277 var msg = null;
6278 var fm = null;
6279 if (error && (fm = error.match(/^(nsfw|nsfl|nsfp|sfw)Required$/))) {
6280 msg = 'Das Bild wurde als <em>' + fm[1].toUpperCase() + '</em> markiert.<br/>' +
6281 (p.user.id ? 'Ändere deine Filter-Einstellung,' : 'Melde dich an,') + ' wenn du es sehen willst.'
6282 } else if (!this.hasItems) {
6283 msg = this.tab === 'stalk' ? 'Du stelzt noch keine anderen Accounts ¯\\_(ツ)_/¯' : 'Nichts gefunden ¯\\_(ツ)_/¯';
6284 }
6285 if (msg) {
6286 this.$container.html('<h2 class="main-message">' + msg + '</h2>');
6287 }
6288 return;
6289 }
6290 if (position == p.Stream.POSITION.PREPEND) {
6291 var prevHeight = $('#main-view').height();
6292 var firstRow = this.$streamContainer.find('.stream-row:first');
6293 var placeholders = firstRow.find('.thumb-placeholder');
6294 var numPlaceholders = placeholders.length
6295 if (numPlaceholders) {
6296 var html = '';
6297 for (var i = 0; i < numPlaceholders; i++) {
6298 html += this.buildItem(items[items.length - numPlaceholders - 1 + i]);
6299 }
6300 placeholders.remove();
6301 firstRow.prepend(this.prepareThumbsForInsertion(html));
6302 }
6303 var html = this.buildItemRows(items, 0, items.length - numPlaceholders, position);
6304 this.$streamContainer.prepend(this.prepareThumbsForInsertion(html));
6305 var newHeight = $('#main-view').height();
6306 $(document).scrollTop($(document).scrollTop() + (newHeight - prevHeight));
6307 } else if (position == p.Stream.POSITION.APPEND) {
6308 var lastRow = this.$streamContainer.find('.stream-row:last');
6309 var itemCount = lastRow.find('.thumb').length;
6310 var fill = 0;
6311 if (itemCount % this.itemsPerRow != 0) {
6312 var html = '';
6313 fill = this.itemsPerRow - itemCount;
6314 for (var i = 0; i < fill; i++) {
6315 html += this.buildItem(items[i]);
6316 }
6317 lastRow.append(this.prepareThumbsForInsertion(html));
6318 }
6319 var html = this.buildItemRows(items, fill, items.length, position);
6320 this.$streamContainer.append(this.prepareThumbsForInsertion(html));
6321 }
6322 if (this.jumpToItem) {
6323 var target = $('#item-' + this.jumpToItem);
6324 if (target.length) {
6325 $(document).scrollTop(target.offset().top - CONFIG.HEADER_HEIGHT);
6326 this.showItem(target, this.SCROLL.THUMB);
6327 }
6328 this.jumpToItem = null;
6329 }
6330 this.loadInProgress = false;
6331 this.hasItems = true;
6332 },
6333 buildItemRows: function(items, start, end, position) {
6334 var html = '';
6335 if (position == p.Stream.POSITION.PREPEND && (end - start) % this.itemsPerRow != 0) {
6336 html += '<div class="stream-row">';
6337 var fillItems = (end - start) % this.itemsPerRow;
6338 var fillPlaceholders = this.itemsPerRow - fillItems;
6339 for (var i = 0; i < fillPlaceholders; i++) {
6340 html += '<div class="thumb-placeholder"></div>';
6341 }
6342 for (var i = start; i < start + fillItems; i++) {
6343 html += this.buildItem(items[i]);
6344 }
6345 start += fillItems;
6346 html += '</div>'
6347 }
6348 var fullRows = ((end - start) / this.itemsPerRow) | 0;
6349 var itemIndex = start;
6350 for (var r = 0; r < fullRows; r++) {
6351 html += '<div class="stream-row">';
6352 for (var i = 0; i < this.itemsPerRow; i++, itemIndex++) {
6353 html += this.buildItem(items[itemIndex]);
6354 }
6355 html += '</div>'
6356 }
6357 if (position == p.Stream.POSITION.APPEND && itemIndex != end) {
6358 html += '<div class="stream-row">';
6359 for (itemIndex; itemIndex < end; itemIndex++) {
6360 html += this.buildItem(items[itemIndex]);
6361 }
6362 html += '</div>'
6363 }
6364 return html;
6365 },
6366 buildItem: function(item) {
6367 return ('<a class="silent thumb" id="item-' + item.id + '" href="' + this.baseURL + item.id + '">' + '<img src="' + item.thumb + '"/>' + '</a>');
6368 },
6369 onscroll: function(ev) {
6370 this.scrollPosition = $(document).scrollTop();
6371 if (this.loadInProgress || !this.hasItems) {
6372 return;
6373 }
6374 var loadingTargetNewer = this.loadingTargetDistance,
6375 loadingTargetOlder = $('#main-view').height() - this.loadingTargetDistance - window.innerHeight;
6376 if (this.scrollPosition > loadingTargetOlder && !this.stream.reached.end) {
6377 this.loadInProgress = true;
6378 this.stream.loadOlder(this.loadedBound);
6379 this.showLoader();
6380 } else if (this.scrollPosition < loadingTargetNewer && !this.stream.reached.start) {
6381 this.loadInProgress = true;
6382 this.stream.loadNewer(this.loadedBound);
6383 this.showLoader();
6384 }
6385 },
6386 showItem: function($item, scrollTo) {
6387 if (this.$currentItem && $item.is(this.$currentItem)) {
6388 this.hideItem();
6389 this._wasHidden = true;
6390 this.currentItemId = null;
6391 return;
6392 }
6393 this.$currentItem = $item;
6394 var $row = $item.parent();
6395 var scrollTarget = 0;
6396 if (scrollTo == this.SCROLL.FULL) {
6397 scrollTarget = $row.offset().top - CONFIG.HEADER_HEIGHT + $item.height();
6398 } else if (scrollTo == this.SCROLL.THUMB) {
6399 scrollTarget = $row.offset().top - CONFIG.HEADER_HEIGHT - this.rowMargin;
6400 } else {
6401 scrollTarget = $(document).scrollTop();
6402 }
6403 var animate = !(scrollTo == this.SCROLL.FULL && this._scrolledToFullView);
6404 this._scrolledToFullView = (scrollTo == this.SCROLL.FULL);
6405 if (this.$itemContainer) {
6406 var previousItemHeight = this.$itemContainer.find('.item-image').height() || 0;
6407 }
6408 if (!$row.next().hasClass('item-container')) {
6409 if (this.$itemContainer) {
6410 if (this.$itemContainer.offset().top < $item.offset().top) {
6411 scrollTarget -= this.$itemContainer.innerHeight() + this.rowMargin * 2;
6412 }
6413 if (animate) {
6414 this.$itemContainer.find('.gpt').remove();
6415 this.$itemContainer.slideUp('fast', function() {
6416 $(this).remove();
6417 });
6418 } else {
6419 this.$itemContainer.remove();
6420 }
6421 }
6422 this.$itemContainer = this.$itemContainerTemplate.clone(true);
6423 this.$itemContainer.insertAfter($row);
6424 if (animate && !this.jumpToItem) {
6425 this.$itemContainer.slideDown('fast');
6426 } else {
6427 this.$itemContainer.show();
6428 }
6429 }
6430 var id = $item[0].id.replace('item-', '');
6431 var itemData = this.stream.items[id];
6432 var rowIndex = $item.prevAll().length;
6433 if (this.currentItemSubview) {
6434 this.currentItemSubview.remove();
6435 }
6436 this.currentItemSubview = new p.View.Stream.Item(this.$itemContainer, this);
6437 this.currentItemSubview.show(rowIndex, itemData, previousItemHeight, this.jumpToComment);
6438 this.jumpToComment = null;
6439 this.stream.loadInfo(itemData.id, this.prefetch.bind(this, $item));
6440 if (!this.jumpToItem) {
6441 if (animate) {
6442 $('body, html').stop(true, true).animate({
6443 scrollTop: scrollTarget
6444 }, 'fast');
6445 } else {
6446 $('body, html').stop(true, true).scrollTop(scrollTarget);
6447 }
6448 }
6449 this.currentItemId = id;
6450 },
6451 hideItem: function(ev) {
6452 var c = this.$itemContainer;
6453 c.slideUp('fast', function() {
6454 c.remove();
6455 });
6456 p.navigateTo(this.baseURL.substr(1, this.baseURL.length - 2), p.NAVIGATE.SILENT);
6457 this.$itemContainer = null;
6458 this.$currentItem = null;
6459 this.currentItemSubview.remove();
6460 },
6461 prefetch: function($centerItem) {
6462 var $prev = this.getPrevItem($centerItem);
6463 var $next = this.getNextItem($centerItem);
6464 var queue = [];
6465 if ($prev.length) {
6466 queue.push($prev[0].id.replace('item-', ''));
6467 }
6468 if ($next.length) {
6469 queue.push($next[0].id.replace('item-', ''));
6470 }
6471 for (var i = 0; i < this.prefetched.length; i++) {
6472 this.prefetched[i].src = "";
6473 }
6474 this.prefetched = [];
6475 for (var i = 0; i < queue.length; i++) {
6476 this.stream.loadInfo(queue[i]);
6477 var source = this.stream.items[queue[i]].image;
6478 if (source.match(/\.mp4$/)) {
6479 var vid = $('<video autobuffer/>')[0];
6480 vid.src = source;
6481 this.prefetched.push(vid);
6482 } else {
6483 var img = new Image();
6484 img.src = source;
6485 this.prefetched.push(img);
6486 }
6487 }
6488 },
6489 getNextItem: function($item) {
6490 var $next = $item.next();
6491 if (!$next.length) {
6492 $next = $item.parent().nextAll('.stream-row:first').find('.thumb:first');
6493 }
6494 return $next.hasClass('thumb') ? $next : $();
6495 },
6496 getPrevItem: function($item) {
6497 var $prev = $item.prev();
6498 if (!$prev.length) {
6499 $prev = $item.parent().prevAll('.stream-row:first').find('.thumb:last');
6500 }
6501 return $prev.hasClass('thumb') ? $prev : $();
6502 },
6503 next: function(ev) {
6504 var $next = this.getNextItem(this.$currentItem);
6505 if (!$next.length) {
6506 return false;
6507 }
6508 this.showItem($next, this.SCROLL.FULL);
6509 p.navigateTo($next.attr('href').substr(1), p.NAVIGATE.SILENT);
6510 return false;
6511 },
6512 prev: function(ev) {
6513 var $prev = this.getPrevItem(this.$currentItem);
6514 if (!$prev.length) {
6515 return false;
6516 }
6517 this.showItem($prev, this.SCROLL.FULL);
6518 p.navigateTo($prev.attr('href').substr(1), p.NAVIGATE.SILENT);
6519 return false;
6520 }
6521});
6522p.View.FollowList = p.View.Base.extend({
6523 template: '<h1 class="pane-head user-head">Stelzliste</h1> <div class="tab-bar"> <a href="#stalk/list/stalk-date" <?js if(params.sort==\'stalk-date\') {?>class="active"<?js}?>>Nach Stelz-Datum</a> <a href="#stalk/list/post-date" <?js if(params.sort==\'post-date\') {?>class="active"<?js}?>>Nach letztem Post</a> </div> <div class="pane"> <?js for( var i = 0; i < list.length; i++ ) { var followed = list[i]; ?> <div class="followed-user"> <?js if( followed.itemId ) { ?> <a class="thumb" href="#user/{followed.name}/uploads/{followed.itemId}"><img src="{followed.thumb}"/></a> <?js } else { ?> <div class="thumb-placeholder"></div> <?js } ?> <div class="follow-details following"> <div> <a href="#user/{followed.name}" class="user um{followed.mark}">{followed.name}</a> </div> <div class="follow-times"> <div> Letzter Post <?js if( followed.lastPost ) {?> <span class="time" title="{followed.lastPost.readableTime()}"> {followed.lastPost.relativeTime()} </span> <?js } else { ?> <span class="time">–</span> <?js } ?> </div> <div> Gestelzt <span class="time" title="{followed.followCreated.readableTime()}"> {followed.followCreated.relativeTime()} </span> </div> </div> <span class="action user-unfollow" data-name="{followed.name}"> <span class="pict">@</span> unstelzen </span> <span class="action user-follow" data-name="{followed.name}"> <span class="pict">@</span> stelzen </span> </div> </div> <?js } ?> </div>',
6524 load: function() {
6525 p.api.get('user.followlist', {
6526 flags: p.user.flags
6527 }, this.loaded.bind(this));
6528 return false;
6529 },
6530 loaded: function(response) {
6531 if (this.data.params.sort == 'post-date') {
6532 response.list.sort(p.View.FollowList.SortFollowLastPost);
6533 } else {
6534 response.list.sort(p.View.FollowList.SortFollowCreated);
6535 }
6536 for (var i = 0; i < response.list.length; i++) {
6537 var l = response.list[i];
6538 l.followCreated = new Date(l.followCreated * 1000);
6539 l.lastPost = l.itemId ? new Date(l.lastPost * 1000) : null;
6540 l.thumb = CONFIG.PATH.THUMBS + l.thumb;
6541 }
6542 this.data.list = response.list;
6543 this.render();
6544 },
6545 render: function() {
6546 this.parent();
6547 this.$container.find('.user-follow').click(this.follow.bind(this));
6548 this.$container.find('.user-unfollow').click(this.unfollow.bind(this));
6549 },
6550 follow: function(ev) {
6551 var $button = $(ev.currentTarget);
6552 $button.closest('.follow-details').removeClass('not-following').addClass('following');
6553 p.api.post('profile.follow', {
6554 name: $button.data('name')
6555 });
6556 },
6557 unfollow: function(ev) {
6558 var $button = $(ev.currentTarget);
6559 $button.closest('.follow-details').removeClass('following').addClass('not-following');
6560 p.api.post('profile.unfollow', {
6561 name: $button.data('name')
6562 });
6563 }
6564});
6565p.View.FollowList.SortFollowCreated = function(a, b) {
6566 return (b.followCreated - a.followCreated);
6567};
6568p.View.FollowList.SortFollowLastPost = function(a, b) {
6569 return (b.lastPost - a.lastPost);
6570};
6571p.View.User = p.View.Base.extend({
6572 template: '<h1 class="pane-head user-head"> {user.name} <?js if(p.user.admin) {?> <a href="/backend/admin/?view=users&action=show&id={user.id}" id="user-admin">admin</a> <?js } ?> <?js if( p.user.name !== user.name ) { ?> <?js if(following) { ?> <span class="action user-unfollow"> <span class="pict">@</span> unstelzen </span> <?js } else { ?> <span class="action user-follow"> <span class="pict">@</span> stelzen </span> <?js } ?> <?js } ?> </h1> <p class="follow-non-paid warn"> Gespeichert. Um die Posts von Benutzern zu sehen die Du stelzt, benötigst Du einen <a href="#pr0mium">pr0mium-Account</a> </p> <div class="user-stats"> <div class="badges"> <?js for( var i = 0; i < dynamicBadges.length; i++ ) { var b = dynamicBadges[i]; ?> <a class="badge" href="{{b.link}}" title="{{b.description}}"> <img src="/media/badges/{b.image}" class="badge" alt=""/> <span class="badge-extra badge-{b.name}">{{b.extra}}</span> </a> <?js } ?> <?js for( var i = 0; i < badges.length; i++ ) { var b = badges[i]; ?> <a class="badge" href="{{b.link}}" title="{{b.description}} - {b.created.readableDate()}"> <img src="/media/badges/{b.image}" class="badge" alt=""/> </a> <?js } ?> </div> <div class="user-score-pane">BENIS <span class="user-score">{user.score}</span></div> <div> <?js if(user.score < 0 ) {?>Geschrumpft<?js } else {?>Gewachsen<?js } ?> seit {user.registered.readableDate()} ({user.registered.relativeTime(true,true)})<?js if(user.banned) { ?>, <?js if( user.bannedUntil ) { ?> gesperrt bis {user.bannedUntil.relativeTime()} <?js } else { ?> dauerhaft gesperrt <?js } ?> <?js } ?> </div> </div> <div class="tab-bar"> <span>Bilder</span> <em>{uploadCount}</em> <span>Favoriten</span> <em>{likeCount}</em> <span>Kommentare</span> <em>{commentCount}</em> <span>Tags</span> <em>{tagCount}</em> <?js if( user.name === p.user.name && p.user.paid ) { ?> <span>Stelzend</span> <em class="follow-count">{followCount}</em> <a href="#stalk/list/stalk-date" class="follow-list">Stelzliste anzeigen…</a> <?js } ?> <em class="user-mark user um{user.mark}">{p.User.MARK[user.mark]}</em> </div> <?js if( p.user.name !== user.name ) { ?> <div class="pane"> <h3><span>{user.name}</span> eine private Nachricht senden</h3> <form class="message-form" method="post"> <textarea class="comment" name="comment"></textarea> <input type="hidden" name="recipientId" value="{user.id}"/> <div> <input type="submit" value="Nachricht senden"/> </div> </form> </div> <?js } ?> <div class="pane"> <h2 class="section"> Neuste Bilder <?js if( uploads.length ) { ?> <a href="#user/{user.name}/uploads" class="user-show-all">Alle Bilder…</a> <?js } ?> </h2> <?js if( !uploads.length) {?> <span class="disabled">Bisher keine Bilder</span> <?js } ?> </div> <?js if( uploads.length) {?> <div class="stream-row in-pane"> <?js for( var i = 0; i < displayUploads; i++ ) { var u = uploads[i]; ?> <a class="thumb" href="#user/{user.name}/uploads/{u.id}"><img src="{u.thumb}"/></a> <?js } ?> <div class="clear"></div> </div> <?js } ?> <div class="pane"> <h2 class="section"> Neuste Favoriten <?js if( likesArePublic && likes.length ) { ?> <a href="#user/{user.name}/likes" class="user-show-all">Alle Favoriten…</a> <?js } ?> </h2> <?js if(!likesArePublic) { ?> <span class="disabled">Nicht öffentlich</span> <?js } else if( !likes.length) { ?> <span class="disabled">Bisher keine Favoriten</span> <?js } ?> </div> <?js if(likesArePublic && likes.length) {?> <div class="stream-row in-pane"> <?js for( var i = 0; i < displayLikes; i++ ) { var l = likes[i]; ?> <a class="thumb" href="#user/{user.name}/likes/{l.id}"><img src="{l.thumb}"/></a> <?js } ?> <div class="clear"></div> </div> <?js } ?> <div class="pane"> <h2 class="section"> Neuste Kommentare <?js if( comments.length ) { ?> <a href="#user/{user.name}/comments/before/{newestCommentTime}" class="user-show-all"> Alle Kommentare… </a> <?js } ?> </h2> <?js for( var i = 0; i < comments.length; i++ ) { var c = comments[i]; ?> <div class="comment"> <a href="#new/{c.itemId}:comment{c.id}"> <img src="{c.thumb}" class="comment-thumb"/> </a> <div class="comment-content with-thumb"> {c.content.format()} </div> <div class="comment-foot with-thumb"> <a href="#user/{user.name}" class="user um{user.mark}">{user.name}</a> <?js if(p.shouldShowScore(c)) {?> <span class="score">{"Punkt".inflect(c.score)}</span> <?js } else { ?> <span class="score-hidden" title="Score noch unsichtbar">â—â—â—</span> <?js } ?> <a href="#new/{c.itemId}:comment{c.id}" class="time permalink" title="{c.date.readableTime()}">{c.date.relativeTime(true)}</a> </div> </div> <?js } ?> <?js if( !comments.length) {?> <span class="disabled">Bisher keine Kommentare</span> <?js } ?> </div>',
6573 init: function(container, parent) {
6574 this.parent(container, parent);
6575 p.mainView.setTab(null);
6576 },
6577 load: function() {
6578 var opts = {
6579 name: this.data.params.name,
6580 flags: p.user.flags
6581 };
6582 p.api.get('profile.info', opts, this.loaded.bind(this));
6583 return false;
6584 },
6585 render: function() {
6586 var thumbsPerRow = p.mainView.thumbsPerRow;
6587 var rows = thumbsPerRow < 5 ? 3 : 2;
6588 var maxThumbs = (thumbsPerRow * rows).limit(9, 16);
6589 this.data.displayUploads = Math.min(this.data.uploads.length, maxThumbs);
6590 this.data.displayLikes = this.data.likesArePublic ? Math.min(this.data.likes.length, maxThumbs) : 0;
6591 this.parent();
6592 this.$container.find('.message-form').submit(this.submitPrivateMessage.bind(this));
6593 this.$container.find('.user-follow').fastclick(this.follow.bind(this));
6594 this.$container.find('.user-unfollow').fastclick(this.unfollow.bind(this));
6595 },
6596 resize: function() {
6597 if (this.data.user) {
6598 this.render();
6599 }
6600 this.parent()
6601 },
6602 follow: function() {
6603 if (!p.mainView.requireLogin()) {
6604 return false;
6605 }
6606 p.api.post('profile.follow', {
6607 name: this.data.user.name
6608 });
6609 this.data.following = true;
6610 this.render();
6611 if (!p.user.paid) {
6612 $('.follow-non-paid').show();
6613 }
6614 },
6615 unfollow: function() {
6616 if (!p.mainView.requireLogin()) {
6617 return false;
6618 }
6619 p.api.post('profile.unfollow', {
6620 name: this.data.user.name
6621 });
6622 this.data.following = false;
6623 this.render();
6624 },
6625 submitPrivateMessage: function() {
6626 if (!p.mainView.requireLogin()) {
6627 return false;
6628 }
6629 var $form = this.$container.find('.message-form');
6630 var data = $form.serialize();
6631 $form.find('input,textarea,button,select').attr('disabled', 'disabled');
6632 p.api.post('inbox.post', data, function(response) {
6633 if (response.success) {
6634 $form.html('<span>Gesendet!</span>');
6635 } else {
6636 $form.find('input,textarea,button,select').removeAttr('disabled');
6637 }
6638 }, function(response) {
6639 $form.find('input,textarea,button,select').removeAttr('disabled');
6640 });
6641 return false;
6642 },
6643 loaded: function(response) {
6644 this.data.user = response.user;
6645 this.data.user.registered = new Date(this.data.user.registered * 1000);
6646 if (this.data.user.bannedUntil) {
6647 this.data.user.bannedUntil = new Date(this.data.user.bannedUntil * 1000);
6648 }
6649 this.data.comments = response.comments;
6650 for (var i = 0; i < this.data.comments.length; i++) {
6651 var c = this.data.comments[i];
6652 c.date = new Date(c.created * 1000);
6653 c.thumb = CONFIG.PATH.THUMBS + c.thumb;
6654 c.score = c.up - c.down;
6655 }
6656 this.data.newestCommentTime = this.data.comments.length ? this.data.comments.first().created + 1 : 0;
6657 this.data.uploads = response.uploads;
6658 for (var i = 0; i < this.data.uploads.length; i++) {
6659 this.data.uploads[i].thumb = CONFIG.PATH.THUMBS + this.data.uploads[i].thumb;
6660 }
6661 this.data.likes = response.likes;
6662 for (var i = 0; i < this.data.likes.length; i++) {
6663 this.data.likes[i].thumb = CONFIG.PATH.THUMBS + this.data.likes[i].thumb;
6664 }
6665 this.data.badges = response.badges;
6666 for (var i = 0; i < this.data.badges.length; i++) {
6667 this.data.badges[i].created = new Date(this.data.badges[i].created * 1000);
6668 }
6669 this.data.followCount = response.followCount;
6670 this.data.dynamicBadges = [];
6671 for (var i = 0; i < p.View.User.BADGE.COMMENTS.COUNTS.length; i++) {
6672 var c = p.View.User.BADGE.COMMENTS.COUNTS[i];
6673 if (response.commentCount >= c.count) {
6674 var badge = p.copy(p.View.User.BADGE.COMMENTS.TEMPLATE);
6675 badge.description = badge.description.replace(/%c/g, c.count);
6676 badge.link = '#user/' + response.user.name + '/comments/before/' + this.data.newestCommentTime;
6677 badge.extra = c.name;
6678 this.data.dynamicBadges.push(badge);
6679 break;
6680 }
6681 }
6682 var years = Math.floor((Date.now() - this.data.user.registered.getTime()) / (365 * 24 * 60 * 60 * 1000));
6683 if (years > 0) {
6684 var badge = p.copy(p.View.User.BADGE.YEARS.TEMPLATE);
6685 badge.description = badge.description.replace(/%y/g, 'Jahr'.inflect(years));
6686 badge.link = '#user/' + response.user.name;
6687 badge.extra = years.toString();
6688 this.data.dynamicBadges.push(badge);
6689 }
6690 this.data.commentCount = response.commentCount;
6691 this.data.tagCount = response.tagCount;
6692 this.data.uploadCount = response.uploadCount;
6693 this.data.likesArePublic = response.likesArePublic;
6694 this.data.likeCount = response.likeCount;
6695 this.data.following = response.following;
6696 this.render();
6697 }
6698});
6699p.View.User.BADGE = {
6700 COMMENTS: {
6701 TEMPLATE: {
6702 name: 'comments',
6703 image: 'comments.png',
6704 link: '',
6705 description: 'Hat mehr als %c Kommentare verfasst',
6706 extra: '0'
6707 },
6708 COUNTS: [{
6709 count: 20000,
6710 name: '20k'
6711 }, {
6712 count: 10000,
6713 name: '10k'
6714 }, {
6715 count: 5000,
6716 name: '5k'
6717 }, {
6718 count: 1000,
6719 name: '1k'
6720 }]
6721 },
6722 YEARS: {
6723 TEMPLATE: {
6724 name: 'years',
6725 image: 'years.png',
6726 link: '',
6727 description: 'Hat %y auf pr0gramm verschwendet',
6728 extra: '1'
6729 },
6730 }
6731};
6732p.View.User.Comments = p.View.Base.extend({
6733 template: '<h1 class="pane-head user-head"> Kommentare von <a href="#user/{user.name}">{user.name}</a> </h1> <div class="pane"> <?js for( var i = 0; i < comments.length; i++ ) { var c = comments[i]; ?> <div class="comment"> <a href="#new/{c.itemId}:comment{c.id}"> <img src="{c.thumb}" class="comment-thumb"/> </a> <div class="comment-content with-thumb"> {c.content.format()} </div> <div class="comment-foot with-thumb"> <a href="#user/{user.name}" class="user um{user.mark}">{user.name}</a> <?js if( p.shouldShowScore(c) ) {?> <span class="score" title="{c.up} up, {c.down} down">{"Punkt".inflect(c.score)}</span> <?js } else { ?> <span class="score-hidden" title="Score noch unsichtbar">â—â—â—</span> <?js } ?> <a href="#new/{c.itemId}:comment{c.id}" class="time permalink" title="{c.date.readableTime()}">{c.date.relativeTime(true)}</a> </div> </div> <?js } ?> <div class="inbox-nav-bar"> <?js if( after ) { ?> <a href="#user/{user.name}/comments/after/{after}" class="inbox-nav newer">« Neuer</a> <?js } ?> <?js if( before ) { ?> <a href="#user/{user.name}/comments/before/{before}" class="inbox-nav older">Älter »</a> <?js } ?> </div> <?js if( !comments.length) {?> <span class="disabled">Keine Kommentare gefunden</span> <?js } ?> </div>',
6734 init: function(container, parent) {
6735 this.parent(container, parent);
6736 p.mainView.setTab(null);
6737 },
6738 load: function() {
6739 var opts = {
6740 name: this.data.params.name,
6741 flags: p.user.flags
6742 };
6743 opts[this.data.params.search] = this.data.params.timestamp;
6744 p.api.get('profile.comments', opts, this.loaded.bind(this));
6745 return false;
6746 },
6747 loaded: function(response) {
6748 this.data.user = response.user;
6749 this.data.comments = response.comments;
6750 this.data.comments.sort(function(a, b) {
6751 return (b.created - a.created);
6752 })
6753 this.data.after = response.hasNewer ? this.data.comments.first().created : null;
6754 this.data.before = response.hasOlder ? this.data.comments.last().created : null;
6755 for (var i = 0; i < this.data.comments.length; i++) {
6756 var c = this.data.comments[i];
6757 c.date = new Date(c.created * 1000);
6758 c.thumb = CONFIG.PATH.THUMBS + c.thumb;
6759 c.score = c.up - c.down;
6760 }
6761 this.render();
6762 }
6763});
6764p.View.Inbox = p.View.Base.extend({
6765 template: '<h1 class="pane-head">Nachrichten</h1> <div class="tab-bar"> <a href="#inbox/unread" <?js if(tab==\'unread\') {?>class="active"<?js}?>>Ungelesen</a> <a href="#inbox/all" <?js if(tab==\'all\') {?>class="active"<?js}?>>Alle</a> <a href="#inbox/messages" <?js if(tab==\'messages\') {?>class="active"<?js}?>>Private Nachrichten</a> </div> <div class="pane"> <form class="comment-form" method="post"> <textarea class="comment" name="comment"></textarea> <input type="hidden" name="parentId" value=""/> <input type="hidden" name="itemId" value=""/> <input type="hidden" name="recipientId" value=""/> <div> <input type="submit" value="Abschicken"/> <input type="button" value="Abbrechen" class="cancel"/> </div> </form> <?js if( messages.length === 0 ) { ?> <?js if( tab === \'unread\') { ?> <em>Keine ungelesenen Nachrichten</em> <?js } else { ?> <em>Keine Nachrichten :(</em> <?js } ?> <?js } else { ?> <div class="inbox-messages"></div> <?js } ?> </div>',
6766 data: {
6767 tab: 'unread',
6768 messages: []
6769 },
6770 init: function(container, parent) {
6771 this.parent(container, parent);
6772 this.scrollBound = this.onscroll.bind(this);
6773 $(window).scroll(this.scrollBound);
6774 p.mainView.setTab(null);
6775 },
6776 show: function(params) {
6777 if (!p.user.id) {
6778 p.navigateTo('');
6779 return false;
6780 }
6781 this.data.tab = params.tab || 'unread';
6782 this.endReached = false;
6783 this.loadInProgress = false;
6784 return this.parent(params);
6785 },
6786 hide: function() {
6787 $(window).unbind('scroll', this.scrollBound);
6788 this.parent();
6789 },
6790 onscroll: function() {
6791 if (this.loadInProgress || this.endReached || this.tab === 'unread') {
6792 return;
6793 }
6794 if ($(document).scrollTop() > this.loadingTargetPosition) {
6795 this.loadInProgress = true;
6796 this.showLoader();
6797 p.api.get('inbox.' + this.data.tab, {
6798 older: this.oldestTimestamp
6799 }, function(response) {
6800 var messages = this.processMessages(response.messages);
6801 if (messages.length) {
6802 this.appendMessages(messages);
6803 }
6804 this.hideLoader();
6805 }.bind(this));
6806 }
6807 },
6808 load: function() {
6809 p.api.get('inbox.' + this.data.tab, {}, function(response) {
6810 this.data.messages = this.processMessages(response.messages);
6811 if (this.data.tab == 'unread') {
6812 p.user.setInboxLink(0);
6813 }
6814 this.render();
6815 }.bind(this));
6816 return false;
6817 },
6818 render: function() {
6819 this.parent();
6820 this.$commentForm = this.$container.find('.comment-form');
6821 this.$commentForm.hide();
6822 this.$commentForm.submit(this.submitComment.bind(this));
6823 this.$commentForm.find('input.cancel').hide().click(this.cancelReply.bind(this));
6824 if (this.data.messages.length) {
6825 this.appendMessages(this.data.messages);
6826 }
6827 },
6828 processMessages: function(messages) {
6829 messages.sort(p.View.Inbox.sortByCreated);
6830 for (var i = 0; i < messages.length; i++) {
6831 var m = messages[i];
6832 m.date = new Date(m.created * 1000);
6833 if (m.itemId) {
6834 m.thumb = CONFIG.PATH.THUMBS + m.thumb;
6835 }
6836 }
6837 if (messages.length) {
6838 this.oldestTimestamp = messages.last().created;
6839 } else {
6840 this.endReached = true;
6841 }
6842 return messages;
6843 },
6844 appendMessages: function(messages) {
6845 var messagesContainer = $('<div/>');
6846 this.$container.find('.inbox-messages').append(messagesContainer);
6847 var view = this.data.tab === 'messages' ? new p.View.Inbox.Threads(messagesContainer, this, messages) : new p.View.Inbox.Messages(messagesContainer, this, messages);
6848 view.show();
6849 messagesContainer.find('.comment-reply-link').fastclick(this.showReplyForm.bind(this));
6850 messagesContainer.find('.expand-thread').fastclick(function() {
6851 $(this).hide();
6852 $('#thread-' + $(this).data('id')).show();
6853 });
6854 this.loadingTargetPosition = $('#main-view').height() - window.innerHeight - 500;
6855 this.loadInProgress = false;
6856 },
6857 showReplyForm: function(ev) {
6858 if (!p.mainView.requireLogin()) {
6859 return false;
6860 }
6861 var $foot = $(ev.currentTarget.parentNode);
6862 if ($foot.has('.comment-form').length) {
6863 return false;
6864 }
6865 var $form = this.$commentForm.clone(true).show();
6866 if ($foot.hasClass('private-message')) {
6867 var senderId = $foot.data('senderid');
6868 $form.find('input[name=recipientId]').val(senderId);
6869 } else {
6870 var parentId = ev.currentTarget.href.split(':comment')[1];
6871 var itemId = $foot.data('itemid');
6872 $form.find('input[name=parentId]').val(parentId);
6873 $form.find('input[name=itemId]').val(itemId);
6874 }
6875 $form.find('input.cancel').show();
6876 $foot.append($form);
6877 this.focus('textarea');
6878 return false;
6879 },
6880 cancelReply: function(ev) {
6881 $(ev.currentTarget).parents('form').remove();
6882 },
6883 submitComment: function(ev) {
6884 if (!p.mainView.requireLogin()) {
6885 return false;
6886 }
6887 var $form = $(ev.currentTarget);
6888 var data = $form.serialize();
6889 $form.find('input,textarea,button,select').attr('disabled', 'disabled');
6890 var onerror = function(response) {
6891 $form.find('input,textarea,button,select').removeAttr('disabled');
6892 };
6893 if ($form.find('input[name=recipientId]').val()) {
6894 p.api.post('inbox.post', data, function(response) {
6895 if (response.success) {
6896 $form.html('<span>Gesendet!</span>');
6897 } else {
6898 onerror(response);
6899 }
6900 }, onerror);
6901 } else {
6902 p.api.post('comments.post', data, function(item) {
6903 if (item.commentId) {
6904 p.user.voteCache.votes.comments[item.commentId] = 1;
6905 }
6906 $form.html('<span>Gesendet!</span>')
6907 }, onerror);
6908 }
6909 return false;
6910 }
6911});
6912p.View.Inbox.sortByCreated = function(a, b) {
6913 return (b.created - a.created);
6914};
6915p.View.Inbox.Messages = p.View.Base.extend({
6916 template: '<?js for( var i = 0; i < messages.length; i++ ) { var m = messages[i]; ?> <?js if( m.itemId ) { /* comment reply */ ?> <h3 class="section">Kommentar</h3> <div class="comment with-thumb" id="comment{m.id}"> <a href="#new/{m.itemId}:comment{m.id}"> <img src="{m.thumb}" class="comment-thumb"/> </a> <div class="comment-content with-thumb"> {m.message.format()} </div> <div class="comment-foot with-thumb" data-itemid="{m.itemId}"> <a href="#user/{m.name}" class="user um{m.mark}">{m.name}</a> <?js if( p.shouldShowScore(m) ) {?> <span class="score">{"Punkt".inflect(m.score)}</span> <?js } else { ?> <span class="score-hidden" title="Score noch unsichtbar">â—â—â—</span> <?js } ?> <a href="#new/{m.itemId}:comment{m.id}" class="time permalink" title="{m.date.readableTime()}">{m.date.relativeTime(true)}</a> <a href="#new/{m.itemId}:comment{m.id}" class="comment-reply-link action"><span class="pict">r</span> antworten</a> </div> </div> <?js } else { /* private message */ ?> <h3 class="section">Private Nachricht</h3> <div class="comment" id="message{m.id}"> <div class="comment-content with-thumb"> {m.message.format()} </div> <div class="comment-foot private-message with-thumb" data-senderid="{m.senderId}"> <a href="#user/{m.name}" class="user um{m.mark}">{m.name}</a> <span class="time permalink" title="{m.date.readableTime()}">{m.date.relativeTime(true)}</span> <a href="#inbox:message{m.id}" class="comment-reply-link action"><span class="pict">r</span> antworten</a> </div> </div> <?js } ?> <?js } ?>',
6917 data: {
6918 messages: []
6919 },
6920 init: function(container, parent, messages) {
6921 this.parent(container, parent);
6922 this.data.messages = messages;
6923 }
6924});
6925p.View.Inbox.Threads = p.View.Base.extend({
6926 template: '<?js for( var i = 0; i < threads.length; i++ ) { var t = threads[i]; ?> <h3 class="section"> <a href="#user/{t.partner.name}" class="user user-thread-head um{t.partner.mark}"> {t.partner.name} </a> – Private Nachrichten </h3> <?js for( var j = 0; j < t.messages.length; j++ ) { var m = t.messages[j]; var more = t.messages.length-CONFIG.INBOX_EXPANDED_COUNT; ?> <?js if( j == CONFIG.INBOX_EXPANDED_COUNT ) { ?> <span class="action expand-thread" data-id="{i}"> {more} weitere {"Nachricht".inflectNoCount(more,"en")} anzeigen… </span> <div class="thread-more" id="thread-{i}"> <?js } ?> <div class="comment<?js print(m.sent?\' voted-down\':\'\');?>" id="message{m.id}"> <div class="comment-content with-thumb"> {m.message.format()} </div> <div class="comment-foot private-message with-thumb" data-senderid="{m.senderId}"> <a href="#user/{m.senderName}" class="user um{m.senderMark}">{m.senderName}</a> <span class="time permalink" title="{m.date.readableTime()}">{m.date.relativeTime(true)}</span> <?js if( !m.sent ) {?> <a href="#inbox:message{m.id}" class="comment-reply-link action"><span class="pict">r</span> antworten</a> <?js } ?> </div> </div> <?js } ?> <?js if( j > CONFIG.INBOX_EXPANDED_COUNT ) { /* close expanded box again? */ ?> </div> <?js } ?> <?js } ?>',
6927 data: {
6928 threads: []
6929 },
6930 init: function(container, parent, messages) {
6931 this.parent(container, parent);
6932 this.data.messages = messages;
6933 var threads = [];
6934 var partners = {};
6935 for (var i = 0; i < messages.length; i++) {
6936 var m = messages[i];
6937 var partnerId = m.sent ? m.recipientId : m.senderId;
6938 if (!partners[partnerId]) {
6939 partners[partnerId] = {
6940 partner: {
6941 name: m.sent ? m.recipientName : m.senderName,
6942 mark: m.sent ? m.recipientMark : m.senderMark
6943 },
6944 messages: []
6945 };
6946 }
6947 partners[partnerId].messages.push(m);
6948 }
6949 for (var partner in partners) {
6950 threads.push(partners[partner]);
6951 }
6952 threads.sort(function(a, b) {
6953 return (b.messages[0].created - a.messages[0].created);
6954 });
6955 this.data.threads = threads;
6956 }
6957});
6958p.View.Validate = p.View.Base.extend({
6959 template: '<h2 class="main-message">Ungültiges Token</h2>',
6960 load: function() {
6961 p.api.post('user.validate', {
6962 token: this.data.params.token
6963 }, this.loaded.bind(this));
6964 return false;
6965 },
6966 loaded: function(response) {
6967 if (response.success) {
6968 p.navigateTo('');
6969 p.reload();
6970 } else {
6971 this.render();
6972 }
6973 }
6974});
6975p.View.ResetPassword = p.View.Base.extend({
6976 template: ' <?js if(submitted && !error ) {?> <h2 class="main-message">Passwort gespeichert!</h2> <?js } else { ?> <h1 class="pane-head">Passwort für {{params.name}} setzen</h1> <div class="pane"> <form id="reset-password"> <div class="form-row"> <input type="password" value="" placeholder="Neues Passwort" name="password"/> <?js if( error === \'invalidToken\' ) {?> <p class="warn">Ungültiger oder veralteter Token.</p> <?js } else if( error === \'passwordTooShort\' ) { ?> <p class="warn">Passwort zu kurz</p> <?js } ?> <p class="field-details">Mindestens 6 Zeichen</p> </div> <div class="form-row"> <input type="submit" value="Speichern"/> </div> <input type="hidden" name="token" value="{{params.token}}"/> <input type="hidden" name="name" value="{{params.name}}"/> </form> </div> <?js } ?>',
6977 data: {
6978 submitted: false,
6979 error: null
6980 },
6981 render: function() {
6982 this.parent();
6983 this.$container.find('#reset-password').submit(this.setPassword.bind(this));
6984 },
6985 setPassword: function(ev) {
6986 p.api.post('user.resetpassword', ev.target, this.posted.bind(this));
6987 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
6988 this.showLoader();
6989 return false;
6990 },
6991 posted: function(response) {
6992 this.data.submitted = true;
6993 this.data.error = response.error;
6994 this.render();
6995 }
6996});
6997p.View.RegisterInvite = p.View.Base.extend({
6998 template: '<h1 class="pane-head">Registrieren</h1> <?js if( inviter ) {?> <p> Eingeladen durch: <a class="user um{inviter.mark}" href="/user/{inviter.name}">{inviter.name}</a> </p> <?js } ?> <div class="pane form-page"> <?js if( error === \'invalidInvite\' ) { ?> <h3 class="warn">Das Invite Token ist ungültig</h3> <p> Das Token <em>"{{params.token}}"</em> ist ungültig. Vielleicht wurde es bereits benutzt? </p> <?js } else if( registered ) { ?> <h3>Danke!</h3> <p> Du solltest gleich eine E-Mail mit dem Aktivierungslink bekommen. <span class="warn">Bitte schau auch in den Spam-Ordner!</span> </p> <?js } else { ?> <form method="post" id="register-form"> <div class="form-row"> <label>Name <span class="field-details">(Mindestens 2 Zeichen, nur Buchstaben und Zahlen)</span>:</label> <input type="text" name="name" value="{{name}}" class="text-line" placeholder="Name"/> <?js if( error === \'nameInvalid\' ) { ?> <p class="warn">Ungültiger Name</p> <?js } ?> <?js if( error === \'nameInUse\' ) { ?> <p class="warn">Dieser Name wird bereits verwendet</p> <?js } ?> </div> <div class="form-row"> <label>Passwort <span class="field-details">(Mindestens 6 Zeichen)</span>:</label> <input type="password" name="password" class="text-line" placeholder="Passwort"/> <?js if( error === \'passwordTooShort\' ) { ?> <p class="warn">Passwort zu kurz</p> <?js } ?> </div> <div class="form-row"> <input type="hidden" name="token" value="{{params.token}}"/> <input type="submit" class="confirm" value="Registrieren"/> </div> </form> <?js } ?> </div>',
6999 data: {
7000 error: null,
7001 name: '',
7002 registered: false,
7003 inviter: null
7004 },
7005 load: function() {
7006 p.api.get('user.loadinvite', {
7007 token: this.data.params.token
7008 }, this.loaded.bind(this));
7009 return false;
7010 },
7011 loaded: function(response) {
7012 this.data.error = response.error;
7013 this.data.inviter = response.inviter;
7014 this.render();
7015 },
7016 render: function() {
7017 this.parent();
7018 this.$container.find('#register-form').submit(this.submit.bind(this));
7019 this.focus('input[name=name]');
7020 },
7021 submit: function(ev) {
7022 this.data.name = this.$container.find('input[name=name]').val();
7023 this.data.error = null;
7024 p.api.post('user.joinwithinvite', ev.target, this.posted.bind(this));
7025 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7026 this.showLoader();
7027 return false;
7028 },
7029 posted: function(response) {
7030 if (response.error) {
7031 this.data.error = response.error;
7032 this.render();
7033 return;
7034 }
7035 p.user.loadCookie();
7036 window.location = '/';
7037 }
7038});
7039p.View.RedeemCode = p.View.Base.extend({
7040 template: '<h1 class="pane-head">pr0mium Code Einlösen</h1> <?js if( tokenError ) { ?> <p class="warn"> <?js if( tokenError === \'invalid\' ) {?> Ungültiger Code. Überprüfe bitte, dass Du den vollständigen Link aus der E-Mail kopiert hast. <?js } else if( tokenError === \'used\' ) { ?> Dieser Code wurde bereits eingelöst. <?js } ?> </p> <?js } else if( p.user.id ) { ?> <form method="post" id="redeem-form"> <h2><span class="force-case">pr0mium</span> Code ({token.product.days} Tage) einlösen</h2> <p> Die pr0mium-Zeit wird deinem Account ({{p.user.name}}) gutgeschrieben. </p> <div class="form-row"> <input type="hidden" name="token" value="{{params.token}}"/> <input type="submit" class="confirm" value="Code jetzt einlösen"/> </div> </form> <?js } else { ?> <h2> Neuen <span class="force-case">pr0mium</span> Account ({token.product.days} Tage) registrieren </h2> <p class="field-details"> (Falls Du bereits einen pr0gramm Account besitzt und die pr0mium-Zeit diesem gutschreiben willst, logge Dich ein und besuche diese Seite erneut) </p> <form method="post" id="register-form"> <div class="form-row"> <label>Name <span class="field-details">(Mindestens 2 Zeichen, nur Buchstaben und Zahlen)</span>:</label> <input type="text" name="name" value="{{name}}" class="text-line" placeholder="Name"/> <?js if( error === \'nameInvalid\' ) { ?> <p class="warn">Ungültiger Name</p> <?js } ?> <?js if( error === \'nameInUse\' ) { ?> <p class="warn">Dieser Name wird bereits verwendet</p> <?js } ?> </div> <div class="form-row"> <label>E-Mail Adresse:</label> <input type="email" name="email" value="{{email}}" class="text-line" placeholder="E-Mail Adresse"/> <?js if( error === \'emailInUse\' ) { ?> <p class="warn">Diese E-Mail Adresse wird bereits verwendet</p> <?js } else if( error === \'emailInvalid\' ) { ?> <p class="warn">Diese E-Mail Adresse ist ungültig oder der E-Mail Provider ist bei uns nicht erlaubt.</p> <?js } ?> </div> <div class="form-row"> <label>Passwort <span class="field-details">(Mindestens 6 Zeichen)</span>:</label> <input type="password" name="password" class="text-line" placeholder="Passwort"/> <?js if( error === \'passwordTooShort\' ) { ?> <p class="warn">Passwort zu kurz</p> <?js } ?> </div> <div class="form-row"> <input type="hidden" name="token" value="{{params.token}}"/> <input type="submit" class="confirm" value="Code einlösen und registrieren"/> </div> </form> <?js } ?> ',
7041 data: {
7042 tokenError: null,
7043 error: null,
7044 name: '',
7045 email: '',
7046 registered: false,
7047 inviter: null
7048 },
7049 load: function() {
7050 p.api.post('user.loadpaymenttoken', {
7051 token: this.data.params.token
7052 }, this.loaded.bind(this));
7053 return false;
7054 },
7055 loaded: function(response) {
7056 this.data.tokenError = response.tokenError;
7057 this.data.token = response.token;
7058 this.render();
7059 },
7060 render: function() {
7061 this.parent();
7062 this.$container.find('#redeem-form').submit(this.redeem.bind(this));
7063 this.$container.find('#register-form').submit(this.register.bind(this));
7064 this.focus('input[name=name]');
7065 },
7066 redeem: function(ev) {
7067 this.data.error = null;
7068 p.api.post('user.redeemtoken', ev.target, this.posted.bind(this));
7069 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7070 this.showLoader();
7071 return false;
7072 },
7073 register: function(ev) {
7074 this.data.name = this.$container.find('input[name=name]').val();
7075 this.data.email = this.$container.find('input[name=email]').val();
7076 this.data.error = null;
7077 p.api.post('user.joinwithtoken', ev.target, this.posted.bind(this));
7078 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7079 this.showLoader();
7080 return false;
7081 },
7082 posted: function(response) {
7083 if (response.error || response.tokenError) {
7084 this.data.tokenError = response.tokenError;
7085 this.data.error = response.error;
7086 this.render();
7087 return;
7088 }
7089 p.user.loadCookie();
7090 p.user.set('paid', true);
7091 window.location = '/redeem/thanks';
7092 }
7093});
7094p.View.RedeemThanks = p.View.Base.extend({
7095 template: '<h1 class="pane-head">Danke <span class="pict">*</span></h1> <div class="pane form-page"> <p> Vielen Dank fürs Einlösen Deines pr0mium-Codes! </p> <p> In den <a href="#settings/site">Einstellungen</a> kannst Du Deinen Benutzerstatus auswählen. </p> </div>'
7096});
7097p.View.Settings = p.View.Base.extend({
7098 template: '<h1 class="pane-head">Einstellungen</h1> <div class="tab-bar"> <a href="#settings/site" <?js if(tab==\'site\') {?>class="active"<?js}?>>Seite</a> <a href="#settings/account" <?js if(tab==\'account\') {?>class="active"<?js}?>>Account</a> <a href="#settings/invites" <?js if(tab==\'invites\') {?>class="active"<?js}?>>Invites</a> <a href="#settings/bookmarklet" <?js if(tab==\'bookmarklet\') {?>class="active"<?js}?>>Bookmarklet</a> <span class="action" id="settings-logout-link">abmelden</span> </div> <div class="pane form-page"> <?js if( saved ) {?> <h2>Gespeichert!</h2> <?js if( emailChanged ) {?> <p>Du bekommst gleich eine E-Mail zur Bestätigung der neuen Adresse</p> <?js } ?> <?js } else { ?> <?js if(tab == \'bookmarklet\') { ?> <div class="bookmarklet-frame"> <p> Mit dem <em>+pr0g</em> Bookmarklet kannst du direkt von jeder Website Bilder auf pr0gramm hochladen. </p> <p> <a class="bookmarklet" title="Ziehe diesen Link in deine Bookmarks!" href="{CONFIG.BOOKMARKLET}"> <img src="/media/pr0gramm-favicon.png" class="bookmarklet-icon"/> +pr0g </a> « Ziehe diesen Link in deine Bookmarks! </p> <img src="/media/bookmarklet-instruction.gif" class="bookmarklet-instruction"/> </div> <?js } else if( tab == \'site\') { ?> <form method="post" id="settings-site-form"> <div class="form-section"> <h2>Allgemeine Einstellungen</h2> <h3>Meine Favoriten sind sichtbar für</h3> <input type="radio" class="box-from-label" name="likesArePublic" value="1" id="likesArePublicAll" <?js if(account.likesArePublic) {?>checked="checked"<?js } ?> /><label class="radio" for="likesArePublicAll">Jeden</label> <input type="radio" class="box-from-label" name="likesArePublic" value="0" id="likesArePublicMe" <?js if(!account.likesArePublic) {?>checked="checked"<?js } ?> /><label class="radio" for="likesArePublicMe">Nur für mich</label> </div> <div class="form-section"> <h2><span class="force-case">pr0mium</span> Funktionen</h2> <?js if( !p.user.paid || !account.paidUntil) {?> <p class="field-details"> Für diese Einstellungen ist ein <a href="#pr0mium">pr0mium Account</a> erforderlich. </p> <?js } else { ?> <p> Dein pr0mium Account läuft am <strong> {account.paidUntil.readableDate()} ({account.paidUntil.relativeTime()}) </strong> ab. <a href="#pr0mium">Jetzt verlängern.</a> </p> <?js } ?> <div class="disabled-wrap"> <?js if( !p.user.paid ) { ?> <div class="disabled-overlay"></div> <?js } ?> <h3>Werbung</h3> <input type="radio" class="box-from-label" name="showAds" value="1" id="showAdsOn" <?js if(p.user.showAds) {?>checked="checked"<?js } ?> /><label class="radio" for="showAdsOn">Werbung anzeigen</label> <input type="radio" class="box-from-label" name="showAds" value="0" id="showAdsOff" <?js if(!p.user.showAds) {?>checked="checked"<?js } ?> /><label class="radio" for="showAdsOff">Alle Werbebanner ausblenden</label> <p class="field-details">(Änderung wird nach einem Reload der Seite wirksam)</p> <h3>Mein Benutzer-Status</h3> <input type="radio" class="box-from-label" name="userStatus" value="paid" id="userStatusPaid" <?js if(account.mark == 9) {?>checked="checked"<?js } ?> /><label class="radio" for="userStatusPaid"> {{p.User.MARK[9]}}: <span class="user um9">{{p.user.name}}</span> </label> <input type="radio" class="box-from-label" name="userStatus" value="default" id="userStatusDefault" <?js if(account.mark == account.markDefault) {?>checked="checked"<?js } ?> /><label class="radio" for="userStatusDefault"> {{p.User.MARK[account.markDefault]}}: <span class="user um{account.markDefault}">{{p.user.name}}</span> </label> <h3>Themes</h3> <?js for(var i = 0; i < CONFIG.THEMES.length; i++ ) { var theme = CONFIG.THEMES[i]; ?> <input type="radio" class="box-from-label" name="theme" value="{theme.id}" id="setting-theme-{theme.id}" <?js if(account.theme === theme.id) {?>checked="checked"<?js } ?> /><label class="radio" for="setting-theme-{theme.id}"> <span class="theme-preview-{theme.id}">{{theme.name}}</span> </label> <?js } ?> </div> </div> <div class="form-row"> <input type="submit" value="Einstellungen speichern" class="confirm settings-save"/> </div> </form> <?js } else if( tab == \'account\') { ?> <form method="post" id="settings-email-form" class="form-section"> <h2>E-Mail Adresse ändern</h2> <div class="form-row"> <label>Derzeitiges Passwort:</label> <input type="password" name="currentPassword" class="text-line" placeholder="Passwort"/> <?js if( error === \'passwordInvalid\' && emailChanged ) { ?> <p class="warn">Passwort ungültig. Änderungen wurden nicht gespeichert.</p> <?js } ?> </div> <div class="form-row"> <label>E-Mail Adresse:</label> <input type="email" name="email" value="{{account.email}}" class="text-line" placeholder="E-Mail Adresse"/> <?js if( error === \'emailInUse\' ) { ?> <p class="warn">Diese E-Mail Adresse ist schon in Verwendung</p> <?js } else if( error === \'emailInvalid\' ) { ?> <p class="warn">Ungültige E-Mail Adresse</p> <?js } ?> </div> <div class="form-row"> <input type="submit" value="E-Mail Adresse ändern" class="confirm settings-save"/> </div> </form> <form method="post" id="settings-password-form" class="form-section"> <h2>Passwort ändern</h2> <div class="form-row"> <label>Derzeitiges Passwort:</label> <input type="password" name="currentPassword" class="text-line" placeholder="Passwort"/> <?js if( error === \'passwordInvalid\' && passwordChanged ) { ?> <p class="warn">Passwort ungültig. Änderungen wurden nicht gespeichert.</p> <?js } ?> </div> <div class="form-row"> <label>Neues Passwort <span class="field-details">(Mindestens 6 Zeichen)</span>:</label> <input type="password" name="password" class="text-line" placeholder="Neues Passwort"/> <?js if( error === \'passwordTooShort\' ) { ?> <p class="warn">Passwort zu kurz</p> <?js } ?> </div> <div class="form-row"> <input type="submit" value="Passwort ändern" class="confirm settings-save"/> </div> </form> <?js } else if( tab == \'invites\') { ?> <p> Wenn Du keine Neuschwuchtel oder Fliesentischbesitzer bist und ein paar Invites übrig hast, kannst du hier Deine Freunde zu pr0gramm einladen. Genauere Informationen findest Du in den FAQ: <a href="#faq:invites">Wie funktioniert das mit den Invites?</a> </p> <p class="warn"> Beachte, dass Du für jeden eingeladenen Benutzer bürgst und automatisch bei jedem Ban für die halbe Zeit mit gebannt wirst! </p> <?js if( account.invites == 0) {?> <p><em>Derzeit keine Invites vorhanden</em></p> <?js } else { ?> <h3>Vorhandene Invites: {account.invites}</h3> <form method="post" id="settings-invite-form"> <div class="form-row"> <input type="email" name="email" value="" placeholder="E-Mail Adresse" class="text-line"/> <input type="submit" value="Einladung verschicken" class="settings-save"/> <?js if( error === \'emailInUse\' ) { ?> <p class="warn">Diese E-Mail Adresse ist schon in Verwendung</p> <?js } else if( error === \'emailInvalid\' ) { ?> <p class="warn">Ungültige E-Mail Adresse</p> <?js } ?> </div> </form> <?js } ?> <?js if( inviteSent ) { ?> <p class="success"> Der Invite wurde verschickt. Wird der Invite innerhalb von 30 Tagen nicht eingelöst, wird er deaktiviert und Dir wieder gut geschrieben. </p> <?js } ?> <?js if( invited.length ) { ?> <div class="pane"> <h2>Bisher versendete Invites</h2> <?js for( var i =0; i < invited.length; i++ ) { var inv = invited[i]; ?> <div> <?js if(inv.name) {?> <a href="#user/{inv.name}" class="user um{inv.mark}">{inv.name}</a> <?js } else { ?> <span class="unimportant">{inv.email} (noch nicht eingelöst)</span> <?js } ?> <span class="time" title="{inv.created.readableTime()}">{inv.created.relativeTime()}</span> </div> <?js } ?> </div> <?js } ?> <?js } ?> <?js } ?> </div> ',
7099 data: {
7100 error: null,
7101 saved: false,
7102 tab: 'bookmarklet',
7103 emailChanged: false,
7104 passwordChanged: false,
7105 account: {
7106 email: '',
7107 likesArePublic: false,
7108 invites: 0
7109 },
7110 inviteSent: false,
7111 },
7112 init: function(container, parent) {
7113 this.parent(container, parent);
7114 p.mainView.setTab(null);
7115 },
7116 show: function(params) {
7117 if (!p.mainView.requireLogin()) {
7118 return false;
7119 }
7120 if (params.token) {
7121 this.showLoader();
7122 this.data.tab = 'account';
7123 p.api.post('user.changeemail', {
7124 token: params.token
7125 }, this.changedEmail.bind(this));
7126 return;
7127 }
7128 this.data.tab = params.tab || 'site';
7129 return this.parent(params);
7130 },
7131 load: function() {
7132 p.api.get('user.info', {}, this.loaded.bind(this));
7133 return false;
7134 },
7135 loaded: function(response) {
7136 this.data.account = response.account;
7137 this.data.invited = response.invited;
7138 this.data.account.theme = p.user.getTheme();
7139 if (this.data.account.paidUntil) {
7140 this.data.account.paidUntil = new Date(this.data.account.paidUntil * 1000);
7141 }
7142 for (var i = 0; i < this.data.invited.length; i++) {
7143 this.data.invited[i].created = new Date(this.data.invited[i].created * 1000);
7144 }
7145 this.render();
7146 },
7147 render: function() {
7148 this.parent();
7149 $('#settings-logout-link').fastclick(this.logout.bind(this));
7150 this.$container.find('.bookmarklet').fastclick(this.bookmarkClick.bind(this));
7151 var that = this;
7152 this.$container.find('#settings-site-form').submit(function(ev) {
7153 p.user.setTheme(that.$container.find('input[name=theme]:checked').val());
7154 p.mainView.setThemeCSS();
7155 p.user.setShowAds($('#showAdsOn').prop('checked'));
7156 p.api.post('user.sitesettings', ev.currentTarget, that.posted.bind(that));
7157 that.$container.find('input[type=submit]').attr('disabled', 'disabled');
7158 that.showLoader();
7159 return false;
7160 });
7161 this.$container.find('#settings-email-form').submit(function(ev) {
7162 that.data.emailChanged = true;
7163 p.api.post('user.requestemailchange', ev.currentTarget, that.posted.bind(that));
7164 that.$container.find('input[type=submit]').attr('disabled', 'disabled');
7165 that.showLoader();
7166 return false;
7167 });
7168 this.$container.find('#settings-password-form').submit(function(ev) {
7169 that.data.passwordChanged = true;
7170 p.api.post('user.changepassword', ev.currentTarget, that.posted.bind(that));
7171 that.$container.find('input[type=submit]').attr('disabled', 'disabled');
7172 that.showLoader();
7173 return false;
7174 });
7175 this.$container.find('#settings-invite-form').submit(function(ev) {
7176 p.api.post('user.invite', ev.currentTarget, that.invited.bind(that));
7177 that.$container.find('input[type=submit]').attr('disabled', 'disabled');
7178 that.showLoader();
7179 return false;
7180 });
7181 this.data.saved = false;
7182 },
7183 posted: function(response) {
7184 if (!response.error) {
7185 this.data.account = response.account;
7186 this.data.saved = true;
7187 }
7188 this.data.error = response.error;
7189 this.render();
7190 this.data.passwordChanged = false;
7191 this.data.emailChanged = false;
7192 },
7193 changedEmail: function(response) {
7194 if (!response.error) {
7195 this.data.account = response.account;
7196 this.data.saved = true;
7197 }
7198 this.data.error = response.error;
7199 this.show({
7200 tab: 'account'
7201 });
7202 },
7203 invited: function(response) {
7204 if (!response.error) {
7205 this.data.account = response.account;
7206 }
7207 this.data.error = response.error;
7208 this.data.inviteSent = !response.error;
7209 this.render();
7210 this.data.inviteSent = false;
7211 },
7212 bookmarkClick: function(ev) {
7213 alert('Ziehe den Link in deine Lesezeichenleiste!');
7214 return false;
7215 },
7216 logout: function(ev) {
7217 p.user.logout();
7218 p.mainView.setUserStatus(false);
7219 p.navigateTo('', p.NAVIGATE.FORCE);
7220 return false;
7221 }
7222});
7223p.View.Rules = p.View.Base.extend({
7224 template: '<h3>DAS KLEINGEDRUCKTE – LIES ES!</h3> <ol class="fine-print"> <li>nsfw/nsfl Inhalte müssen vor dem Upload entsprechend markiert werden.</li> <li>Keine suggestiven Bilder/Videos oder Gore von/mit Minderjährigen/Babys/Föten.</li> <li>Keine Tierpornos.</li> <li>Kein stumpfer Rassismus, kein rechtes Gedankengut, keine Nazi-Nostalgie. Das gilt auch für die Tags.</li> <li>Keine Werbung, keine Affiliate Links in den Bildern, kein Spam.</li> <li>Keine Informationen oder Bilder von Privatpersonen; keine Klarnamen in den Uploads, Tags oder Kommentaren.</li> <li>Ein Mindestmaß an Bildqualität wird erwartet. Bildmaterial mit starken Kompressionsartefakten, übermäßig großen Watermarks oder unsinnig beschnittene/skalierte Bilder werden gelöscht.</li> <li>Keine Bilder/Videos mit ähnlichem Inhalt kurz hintereinander posten. Zugehöriger Content kann in den Kommentaren verlinkt werden.</li> <li> Kommentare wie <em>“Tag deinen Scheißâ€</em> gehören nicht in die Tags. Mehr im FAQ: <a href="#faq:tags">Was gehört in die Tags?</a> </li> <li>Kein Downvote-Spam, Vote-Manipulation oder Tag-Vandalismus.</li> <li>Pro Benutzer ist nur ein Account erlaubt. Indizien für Multiaccounts sind gegenseitige Upvotes oder Spamaktionen.</li> <li>Keine Warez, gestohlene Logins zu Pay Sites o.Ä.</li> <li>Keine übermäßigen Beleidigungen anderer Benutzer, insbesondere Moderatoren.</li> <li>Keine “Screamer†oder sonstige Videos mit der Absicht Benutzer zu erschrecken.</li> <li>Keine reinen Musikuploads (außer bei OC).</li> <li>Kein unnötiges markieren von Moderatoren. Wenn Du Hilfe benötigst oder petzen willst, benutze das <a href="#contact">Kontaktformular</a>.</li> </ol> <p class="warn"> Unfähigkeit, diese Regeln zu befolgen, wird mit einer Sperrung Deines Accounts honoriert. Diskussionen um die Sperrung werden die Sperrung verlängern. Wiederholte Unfähigkeit führt zum permanenten Ausschluss. </p> '
7225});
7226p.View.Filter = p.View.Base.extend({
7227 template: '<h3>Filter</h3> <p> Vor dem Upload müssen Bilder/Videos mit dem passenden Filter versehen werden. </p> <ul class="fine-print"> <li> <strong>SFW (Safe for Work)</strong> - keine Gewalt, keine nackte Haut, kein ekliger Scheiß. </li> <li> <strong>NSFW (Not Safe for Work)</strong> – beinhaltet nackte Haut, Pornos und leicht offensiven Kram. Nur für registrierte Mitglieder. </li> <li> <strong>NSFL (Not Safe for Life)</strong> – alles. Gewalt, zerplatzte Menschen, ekligen Scheiß. Nur für registrierte Mitglieder. </li> </ul> '
7228});
7229p.View.UploadSimilar = p.View.Base.extend({
7230 template: '<p class="warn"> Wir haben ein paar Bilder mit ähnlichem Fingerprint gefunden. Bist Du sicher, dass es sich nicht um einen Repost handelt? </p> <div class="upload-similar-images"> <?js for( var i = 0; i < similar.length; i++ ) { var item = similar[i]; ?> <a href="/new/{item.id}" target="_blank" class="similar-thumb"><img src="{item.thumb}"/></a> <?js } ?> </div> ',
7231 show: function(similar) {
7232 for (var i = 0; i < similar.length; i++) {
7233 var item = similar[i];
7234 item.thumb = CONFIG.PATH.THUMBS + item.thumb;
7235 item.image = CONFIG.PATH.IMAGES + item.image;
7236 item.fullsize = item.fullsize ? CONFIG.PATH.FULLSIZE + item.fullsize : null;
7237 }
7238 this.data.similar = similar;
7239 this.parent();
7240 }
7241});
7242p.View.Upload = p.View.Base.extend({
7243 template: '<h1 class="pane-head">Bild hochladen</h1> <div class="pane form-page"> <?js if( error ) {?> <?js if( error === \'invalidType\' ) {?> <h2 class="warn">Ungültiger Dateityp</h2> <p>Nur JPEG, PNG, GIF, WebM oder MP4 erlaubt.</p> <?js } else if( error === \'invalid\' ) {?> <?js if(report) {?> <h2 class="warn">Ungültige Datei-Eigenschaften ◉︵◉</h2> <p> <?js if(report.error === \'dimensionsTooSmall\') {?> Die Auflösung ist zu klein – Mindestens 0,09 Megapixel (z.B. 300×300). <?js } else if(report.error === \'dimensionsTooLarge\') {?> Die Auflösung ist zu hoch – Maximal 16,7 Megapixel (z.B. 4096×4096). <?js } else if(report.error === \'durationTooLong\') {?> Das Video ist zu lang – Maximal 180 Sekunden. <?js } else if(report.error === \'invalidCodec\') {?> Ungültiges Codec gefunden – Nur VP8, VP9 oder H264 für Video bzw. AAC, Vorbis oder Opus für Audio erlaubt. <?js } else if(report.error === \'invalidStreams\') {?> Ungültige Stream-Konstellation (z.B zwei Video Streams). <?js } else if(report.error === \'invalidContainer\') {?> Ungültige Container/Codec-Konstellation. (z.B. VP8 in einem MP4 Container). <?js } ?> </p> <h2 class="section">Details zur Hochgeladenen Datei:</h2> <p> Format: {report.format}, {report.width}×{report.height} Pixel <?js if(report.duration) {?>, {report.duration} Sekunden<?js } ?> </p> <?js if(report.streams && report.streams.length) {?> <h3>Streams:</h3> <ol> <?js for(var i = 0; i < report.streams.length; i++) { var stream = report.streams[i]; ?> <li>Typ: {{stream.type}}, Codec: {{stream.codec}}</li> <?js } ?> </ol> <?js } ?> <?js } else {?> <p class="warn">Unbekanntes Dateiformat ¯\\_(ツ)_/¯</p> <?js }?> <?js } else if( error === \'blacklisted\' ) {?> <h2 class="warn">Bild oder Domain gesperrt</h2> <p class="warn">Gesperrte Bilder wurden meist schon einmal durch einen Moderator gelöscht.</p> <?js } else if( error === \'internal\' ) {?> <h2 class="warn">Interner Fehler bei der Verarbeitung</h2> <?js } else if( error === \'download\' ) {?> <h2 class="warn">Download fehlgeschlagen</h2> <p>Die Maximale Dateigröße ist 6MB bzw. 12MB für <a href="#pr0mium">pr0mium-Accounts</a>.</p> <?js } else if( error === \'upload\' ) {?> <h2 class="warn">Upload fehlgeschlagen</h2> <p>Die Maximale Dateigröße ist 6MB bzw. 12MB für <a href="#pr0mium">pr0mium-Accounts</a>.</p> <?js } else if( error === \'missingData\' ) {?> <h2 class="warn">Kein Bild oder URL angegeben</h2> <?js } else if( error === \'uploadNotSupported\' ) {?> <h2 class="warn">Datei-Upload wird nicht unterstüzt</h2> <p>Vielleicht solltest du mal darüber nachdenken, nicht so einen Unterschichten-Brauser zu benutzen.</p> <?js } ?> <p><span class="link" id="upload-link">Na gut…</span></p> <?js } else { ?> <form id="upload-form"> <div id="upload-source"> <div id="upload-droparea"> Bild auswählen <?js if(supportsDragDrop) { ?> oder per Drag & Drop reinziehen <?js } ?> </div> <div> <h3 class="upload-enter-url">oder URL angeben</h3> <input type="text" name="imageUrl" id="upload-url" placeholder="http://" class="wide"/> <input type="file" name="image" id="upload-file"/> </div> </div> <p> Erlaubte Dateitypen: JPEG, PNG, GIF mit min. 0,09 Megapixel (z.B. 300×300), max. 16,7 Megapixel (z.B. 4096×4096). Videos als WebM (VP8/Vorbis/Opus) oder MP4 (H264/AAC), max. 180sek. </p> <p> Die Maximale Dateigröße ist 6MB bzw. 12MB für <a href="#pr0mium">pr0mium-Accounts</a>. </p> <div id="upload-progress"> <div id="upload-preview"></div> <div class="progress-bar"> <div class="progress"></div> </div> </div> <div class="upload-tag-container"> <div class="sfw-status"> <input type="radio" class="box-from-label" name="sfwstatus" value="sfw" id="ratingSfw"> <label title="Safe for Work" for="ratingSfw">sfw</label> <input type="radio" class="box-from-label" name="sfwstatus" value="nsfw" id="ratingNsfw"> <label title="Not Safe for Work" for="ratingNsfw">nsfw</label> <input type="radio" class="box-from-label" name="sfwstatus" value="nsfl" id="ratingNsfl"> <label title="Not Safe for Life" for="ratingNsfl">nsfl</label> </div> <h3>SFW-Status und Tags</h3> <input type="text" class="upload-tagsinput" name="tags"/> </div> <div class="upload-similar"></div> <div> <input type="hidden" name="checkSimilar" value="1"/> <input type="submit" class="button" value="Bild Hochladen" disabled="disabled"/> </div> <input type="hidden" name="key" value=""/> </form> <div class="post-filter"></div> <div class="post-rules"></div> <?js } ?> </div> ',
7244 data: {
7245 error: null,
7246 report: null
7247 },
7248 uploadInProgress: false,
7249 postInProgress: false,
7250 hasUpload: false,
7251 currentFileType: null,
7252 init: function(container, parent) {
7253 this.parent(container, parent);
7254 p.mainView.setTab(null);
7255 },
7256 show: function(params) {
7257 if (!p.mainView.requireLogin()) {
7258 return false;
7259 }
7260 this.data.tab = params.tab || 'bookmarklet';
7261 return this.parent(params);
7262 },
7263 load: function() {
7264 p.api.post('items.ratelimited');
7265 return true;
7266 },
7267 render: function() {
7268 if (!this.supportsFileUpload()) {
7269 this.data.error = 'uploadNotSupported';
7270 }
7271 this.data.supportsDragDrop = this.supportsDragDrop();
7272 this.parent();
7273 var that = this;
7274 var tags = this.$container.find('.upload-tagsinput');
7275 tags.tagsInput(CONFIG.TAGS_INPUT_SETTINGS);
7276 this.$container.find('input[name=sfwstatus]').change(function() {
7277 that.setSFWTags($(this));
7278 });
7279 var $dropTargets = this.$container.find('#upload-droparea').add('body');
7280 var $dropArea = this.$container.find('#upload-droparea');
7281 $dropTargets.on('dragover', function() {
7282 $dropArea.addClass('active');
7283 return false;
7284 });
7285 $dropTargets.on('dragend dragout dragleave', function() {
7286 $dropArea.removeClass('active');
7287 return false;
7288 });
7289 $dropTargets.on('drop', function(ev) {
7290 $dropArea.removeClass('active');
7291 ev.preventDefault();
7292 that.readFiles(ev.originalEvent.dataTransfer.files);
7293 return false;
7294 });
7295 var $fileSelect = this.$container.find('#upload-file');
7296 $dropArea.on('click', function() {
7297 $fileSelect.click();
7298 });
7299 var fileUpload = this.$container.find('#upload-file');
7300 fileUpload.on('change', function(ev) {
7301 that.readFiles(this.files);
7302 });
7303 this.$container.find('#upload-url').on('change keypress paste', function(ev) {
7304 setTimeout(that.validateUrl.bind(that, ev), 1);
7305 });
7306 this.$container.find('#upload-form').submit(this.submit.bind(this));
7307 this.$container.find('#upload-link').fastclick(function() {
7308 this.data = {
7309 error: null,
7310 report: null
7311 };
7312 this.render();
7313 }.bind(this));
7314 this.rulesView = new p.View.Rules(this.$container.find('.post-rules'), this);
7315 this.rulesView.show();
7316 this.filterView = new p.View.Filter(this.$container.find('.post-filter'), this);
7317 this.filterView.show();
7318 this.currentFileType = null;
7319 },
7320 setSFWTags: function($radio) {
7321 var tags = this.$container.find('.upload-tagsinput');
7322 var status = $radio.val();
7323 tags.removeTag('nsfw');
7324 tags.removeTag('nsfl');
7325 if (status != 'sfw') {
7326 tags.addTag(status);
7327 }
7328 },
7329 validateUrl: function(ev) {
7330 var url = $(ev.target).val();
7331 if (this.hasUpload || url.match(/^https?:\/\/[^\s\/$.?#].[^\s]*$/i)) {
7332 this.$container.find('input[type=submit]').removeAttr('disabled');
7333 } else {
7334 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7335 }
7336 },
7337 remove: function() {
7338 $('body').off('dragover dragend dragout dragleave drop');
7339 },
7340 submit: function(ev) {
7341 var imageUrl = this.$container.find('input[name=imageUrl]').val();
7342 if (this.uploadInProgress || this.postInProgress || (!imageUrl && !this.hasUpload)) {
7343 return false;
7344 }
7345 if (!this.$container.find('input[name=sfwstatus]:checked').length) {
7346 this.$container.find('.sfw-status').highlight(252, 136, 52, 1);
7347 return false;
7348 }
7349 this.postInProgress = true;
7350 p.api.post('items.post', ev.target, this.posted.bind(this));
7351 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7352 this.showLoader();
7353 return false;
7354 },
7355 posted: function(response) {
7356 if (response.error) {
7357 this.postInProgress = false;
7358 if (response.error == 'similar') {
7359 this.similarView = new p.View.UploadSimilar(this.$container.find('.upload-similar'), this);
7360 this.similarView.show(response.similar);
7361 this.$container.find('input[type=submit]').removeAttr('disabled');
7362 this.$container.find('input[name=checkSimilar]').val(0);
7363 } else {
7364 this.data.error = response.error;
7365 this.data.report = response.report;
7366 this.render();
7367 }
7368 } else {
7369 p.mainView.closeOverlay();
7370 p.user.voteCache.votes.items[response.item.id] = 1;
7371 p.navigateTo('new/' + response.item.id);
7372 }
7373 },
7374 readFiles: function(files) {
7375 if (this.currentFileType !== null) {
7376 return;
7377 }
7378 var file = files[0];
7379 if (!file || CONFIG.API.ALLOWED_UPLOAD_TYPES.indexOf(file.type) === -1) {
7380 this.data.error = 'invalidType';
7381 this.render();
7382 return;
7383 }
7384 this.currentFileType = file.type;
7385 this.uploadInProgress = true;
7386 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7387 var reader = new FileReader();
7388 reader.onload = this.previewLoaded.bind(this);
7389 reader.readAsDataURL(file);
7390 var that = this;
7391 var formData = new FormData();
7392 formData.append('image', file);
7393 var req = new XMLHttpRequest();
7394 req.onload = function(ev) {
7395 that.uploadComplete(req);
7396 };
7397 req.onerror = function(ev) {
7398 that.uploadError(req);
7399 };
7400 if (req.upload) {
7401 req.upload.onprogress = this.uploadProgress.bind(this);
7402 }
7403 req.open('POST', CONFIG.API.ENDPOINT + 'items/upload');
7404 req.send(formData);
7405 },
7406 previewLoaded: function(ev) {
7407 this.$container.find('#upload-source').remove();
7408 this.$container.find('#upload-preview').show();
7409 if (this.currentFileType.match(/^video/)) {
7410 var video = $('<video autoplay loop muted/>').attr('src', ev.target.result);
7411 this.$container.find('#upload-preview').append(video);
7412 } else if (this.currentFileType.match(/^image/)) {
7413 var image = $('<img/>');
7414 image.attr('src', ev.target.result);
7415 this.$container.find('#upload-preview').append(image);
7416 }
7417 },
7418 uploadError: function(req) {
7419 this.data.error = 'upload';
7420 this.render();
7421 },
7422 uploadComplete: function(req) {
7423 if (req.status !== 200) {
7424 this.uploadError(req);
7425 return;
7426 }
7427 this.uploadInProgress = false;
7428 this.hasUpload = true;
7429 this.setProgress(1.0);
7430 var response = JSON.parse(req.responseText);
7431 this.$container.find('input[type=submit]').removeAttr('disabled');
7432 this.$container.find('input[name=key]').val(response.key);
7433 },
7434 uploadProgress: function(ev) {
7435 if (!ev.lengthComputable) {
7436 return;
7437 }
7438 var progress = (ev.loaded / ev.total);
7439 this.setProgress(progress);
7440 },
7441 setProgress: function(progress) {
7442 var progress = Math.round(progress * 100);
7443 this.$container.find('.progress').css('width', progress + '%');
7444 },
7445 supportsFileUpload: function() {
7446 return (typeof FileReader != 'undefined' && !!window.FormData && 'upload' in new XMLHttpRequest);
7447 },
7448 supportsDragDrop: function() {
7449 return ('draggable' in document.createElement('span'));
7450 }
7451});
7452p.View.Contact = p.View.Base.extend({
7453 template: '<h1 class="pane-head">Kontakt</h1> <div class="pane form-page"> <?js if(sent) { ?> <p>Deine Nachricht wurde verschickt!</p> <?js } else { ?> <form class="contact-form" method="post"> <p> Bevor Du uns schreibst, schau bitte ob deine Frage nicht bereits im <a href="#faq">FAQ</a> beantwortet wurde. </p> <div class="form-row"> <input type="text" class="text-line" name="subject" required placeholder="Betreff"/> </div> <div class="form-row"> <input type="email" name="email" required placeholder="E-Mail Adresse"/> </div> <textarea name="message" required placeholder="Nachricht"></textarea> <p> Für <span class="warn">Löschanfragen</span> bitte die <span class="warn">exakte Adresse (URL)</span>, sowie ausreichende Beweise angeben, dass Du der Urheber des Bildes bist oder in seinem Auftrag handelst. Als Uploader des Bildes musst Du keine Beweise vorlegen. </p> <p> Anfragen nach Invites werden nicht beantwortet. </p> <div> <input type="submit" value="Abschicken"/> </div> </form> <?js } ?> </div> <div class="pane form-page"> <h2>Advertisers</h2> <p><span class="warn">Please read carefully before contacting us!</span></p> <p> For advertisement inqueries contact us at <a href="mailto:affiliates@pr0gramm.com">affiliates@pr0gramm.com</a>. Please note that we respect our users and therefore refuse to show overly obtrusive or annoying ads (popups, popunders, layers, audio ads etc.). Standardized or computer generated mails will not be answered. </p> <p class="faint-footer"> <a href="#tos">AGB und Widerrufsbelehrung</a> / <a href="#imprint">Impressum</a> </p> </div>',
7454 data: {
7455 sent: false
7456 },
7457 render: function() {
7458 this.parent();
7459 this.$container.find('form').submit(this.submit.bind(this));
7460 this.focus('input[name=subject]');
7461 },
7462 submit: function(ev) {
7463 if ($('input[name=subject]').val().match(/^\s*$/)) {
7464 $('input[name=subject]').highlight(252, 136, 52, 1, 200, function(el) {
7465 el.css('background-color', '#1B1E1F');
7466 });
7467 return false;
7468 }
7469 if (!$('input[name=email]').val().match(/.+@.+\..+/)) {
7470 $('input[name=subject]').highlight(252, 136, 52, 1, 200, function(el) {
7471 el.css('background-color', '#1B1E1F');
7472 });
7473 return false;
7474 }
7475 p.api.post('contact.send', ev.target, this.posted.bind(this));
7476 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7477 this.showLoader();
7478 return false;
7479 },
7480 posted: function(response) {
7481 this.data.sent = true;
7482 this.render();
7483 }
7484});
7485p.View.FAQ = p.View.Base.extend({
7486 template: '<h1 class="pane-head">FAQ - Häufig gestellte Fragen</h1> <div class="pane form-page"> <h2>Regeln & Funktionen</h2> <ul> <li><a href="#faq:rules">Gibt es hier Regeln?</a></li> <li><a href="#faq:tags">Was gehört in die Tags?</a></li> <li><a href="#faq:benis">Wieso ist mein Benis so kurz?</a></li> <li><a href="#faq:rate-limit">Was ist <em>429 – Limit Reached</em>?</a></li> <li><a href="#faq:score">Warum sehe ich bei manchen Bildern oder Kommentaren keine Punktzahl?</a></li> <li><a href="#faq:user-status">Was bedeuten die farbigen Punkte hinter den Benutzernamen?</a></li> <li><a href="#faq:shortcuts">Welche Keyboard-Shortcuts gibt es?</a></li> </ul> <h2>Registrierung & Account</h2> <ul> <li><a href="#faq:register">Wie kann ich mich registrieren?</a></li> <li><a href="#faq:invites">Wie funktioniert das mit den Invites?</a></li> <li><a href="#faq:registration-mail">Wieso bekomme ich keine Registrierungsmail?</a></li> <li><a href="#faq:login">Warum kann ich mich nicht mehr einloggen?</a></li> <li><a href="#faq:ban">Warum bin ich gebannt?</a></li> <li><a href="#faq:password">Wie kann ich mein Passwort zurücksetzen?</a></li> <li><a href="#faq:session">Jemand hat unrechtmäßig meinen Account benutzt. Was kann ich tun?</a></li> <li><a href="#faq:rename">Wie kann ich meinen Benutzernamen ändern?</a></li> <li><a href="#faq:account-delete">Wie kann ich meinen Account löschen?</a></li> </ul> <h2>pr0mium</h2> <ul> <li><a href="#faq:pr0mium-account">Kann ich meinen Account auch ohne pr0mium noch nutzen?</a></li> <li><a href="#faq:pr0mium-gift">Darf ich pr0mium verschenken oder verkaufen?</a></li> <li><a href="#faq:pr0mium-ban">Kann ich mit einem pr0mium-Account gesperrt werden?</a></li> </ul> <h2>Löschanfragen & Copyright</h2> <ul> <li><a href="#faq:delete">Wie kann ich ein Bild von mir löschen?</a></li> <li><a href="#faq:copyright">Diese Seite verletzt mein Copyright!!11</a></li> </ul> <h2>Bugs & technische Probleme</h2> <ul> <li><a href="#faq:troubleshooting">Warum funktioniert pr0gramm bei mir nicht richtig?</a></li> <li><a href="#faq:video">Warum werden die Videos bei mir nicht abgespielt?</a></li> <li><a href="#faq:down">Wieso ist pr0gramm down?</a></li> <li><a href="#faq:security">Ich kann pr0gramm hacken. Soll ich?</a></li> </ul> </div> <div class="pane form-page"> <h1 class="pane-head">Regeln & Funktionen</h1> <h2 class="section" id="section-rules">Gibt es hier Regeln?</h2> <p>Ja.</p> <div class="faq-rules"></div> <div class="faq-filter"></div> <h2 class="section" id="section-tags">Was gehört in die Tags?</h2> <p> Die Tags sind primär dazu gedacht, Bilder über die Suchfunktion wieder finden zu können. Sie sollten hauptsächlich den Bildinhalt beschreiben. Stellt euch die Frage <em>"Wenn ich dieses Bild in 3 Monaten suche, wonach würde ich suchen?"</em> </p> <p> Generell bedeutet das, dass auch Tags die nicht direkt den Inhalt des Bildes beschreiben sondern das Bild anderweitig klassifizieren, bei der Suche hilfreich sein können. Beispiele für solche Tags sind <a href="#top/verdient">verdient</a>, <a href="#top/guter loop">guter loop</a>, <a href="#top/unerwartet">unerwartet</a> oder <a href="#top/kreiselficker">kreiselficker</a>. </p> <p> Kommentare haben in den Tags nichts verloren. Besonders unerwünscht sind Tags wie <em>"Tag Deinen Scheiß"</em> (wenn ihr ein ungetaggtes Bild seht, tagt es selbst und kassiert den Benis dafür), <em>"Da drückste plus/minus"</em> (erzähl mir nicht was ich zu drücken hab) oder <em>"für mehr XYZ auf pr0"</em>. Genauso sind Tags die das Bild abwerten unerwünscht, wie z.B. <em>"0815"</em>, <em>"ban pls"</em> oder <em>"alles ist beliebt"</em>. Alles was aus mehr als 3 oder 4 Wörtern besteht, ist generell bedenklich. </p> <p> Da es für die Moderatoren und Admins unmöglich ist, alle Tags zu überwachen, bitten wir Euch darum unnötige Tags und Sprüche downzuvoten. Falls Euch Spam auffällt (z.B. der gleiche, unnütze Tag bei vielen neuen Bildern), wendet Euch bitte an das <a href="#contact">Kontaktformular</a>. </p> <h2 class="section" id="section-benis">Wieso ist mein Benis so kurz?</h2> <p> Der Benis ist Summe aller Votes die Du erhalten hast. Dein Benis verlängert oder verkürzt sich mit jedem positiven oder negativen Vote, den Deine Kommentare, Tags oder Bilder erhalten. </p> <p> Wenn Dein Benis zu kurz ist, solltest Du aufhören so viel Scheiße zu posten. </p> <h2 class="section" id="section-rate-limit">Was ist <em>429 – Limit Reached</em>?</h2> <p> Alle Aktionen (Kommentare oder Tags schreiben, Bilder hochladen etc.) haben ein bestimmtes Limit. Wenn dieses Limit erreicht ist, musst Du eine Weile warten, bis Du die Aktion nochmal ausführen darfst. </p> <p> Kommentare, Private Nachrichten, Tags und Votes sind stündlich limitiert. </p> <p> Das Limit für Bilder gilt für einen halben Tag (12h) und ist von der Benislänge abhängig: Bei Microbenis 3 Bilder, ab 100 Benis 6 Bilder, ab 1000 Benis 12 Bilder. </p> <h2 class="section" id="section-score">Warum sehe ich bei manchen Bildern oder Kommentaren keine Punktzahl?</h2> <p> Die aktuelle Punktzahl wird bei neuen Posts und Kommentaren für die ersten 60 Minuten versteckt. Das dient dazu "Vote-Bias" und blinde Mitläufer-Votes zu verhindern. </p> <h2 class="section" id="section-user-status">Was bedeuten die farbigen Punkte hinter den Benutzernamen?</h2> <p> Die farbigen Punkte geben den Status an. Welcher das genau ist, steht auf der Profilseite des jeweiligen Benutzers. </p> <p> Neuschwuchteln, die eine Mindest-Benislänge von 500 haben und seit mehr als einem Monat dabei sind, wird der Neuschwuchtelstatus abgenommen. </p> <h2 class="section" id="section-shortcuts">Welche Keyboard-Shortcuts gibt es?</h2> <ul> <li><strong>Pfeiltasten</strong> – Nächstes/vorheriges Bild</li> <li><strong>K</strong> – Zur Suche springen</li> <li><strong>T</strong> – Zu den Tags springen</li> <li><strong>C</strong> – Zu den Kommentaren springen</li> <li><strong>W/S</strong> – Bild hoch-/runter-voten</li> <li><strong>F</strong> – Bild favorisieren</li> <li><strong>Q</strong> – Video stumm/laut stellen</li> </ul> </div> <div class="pane form-page"> <h1 class="pane-head">Registrierung & Account</h1> <h2 class="section" id="section-register">Wie kann ich mich registrieren?</h2> <p> Um einen Account zu erstellen, kannst Du entweder einen <a href="#pr0mium">pr0mium-Code kaufen</a> oder Dich von einem anderen Benutzer einladen lassen. </p> <h2 class="section" id="section-invites">Wie funktioniert das mit den Invites?</h2> <p> An jedem 1. eines Monats verteilt unser System 3 Invites an alle Benutzer die keine Neuschwuchtel oder Fliesentischbesitzer sind und mehr als 500 Benis haben. Diese Invites können bei <em>Einstellungen » Invites</em> per E-Mail verschickt werden. Nicht verwendete Invites verfallen nach einem Monat. </p> <p> Ihr bürgt für jeden von euch eingeladenen Benutzer mit der halben Ban-Zeit. D.h. wenn ein Benutzer, den Du eingeladen hast, für 10 Tage gebannt wird, wird Dein Account automatisch auch für 5 Tage gebannt. Bei einem Permaban von einem von dir eingeladenen Benutzer, wird Dein Account für 30 Tage gebannt. </p> <p> Die Bürgschaft läuft über alle Ebenen: Wenn Du <em>Hans</em> einlädst, der wiederum <em>Peter</em> einlädt, wird bei einem 10 tägigen Ban von <em>Peter</em> auch <em>Hans</em> für 5 Tage gebannt und Du selbst für 2,5 Tage. </p> <p> Der Verkauf von Invites, in welcher Form auch immer, führt zum sofortigen Ban aller beteiligten Accounts. Wer Invitehändler an uns meldet darf seinen Account behalten und/oder bekommt eine kleine Belohnung. </p> <p> Eine Erstattung von Invites die an falsche Adressen geschickt wurden oder schlicht nicht ankamen gibt es nicht. Versendete aber unbenutze Invites werden nach 30 Tagen gelöscht. </p> <p> Wenn Du Invites an Personen verschickst die schon mehrfach gesperrt wurden, musst Du mit dem Verlust Deines eigenen Accounts rechnen. </p> <h2 class="section" id="section-registration-mail">Wieso bekomme ich keine Registrierungsmail?</h2> <p> Generell machen alle Microsoft Dienste <strong>(Live, MSN, Hotmail, Outlook...)</strong>, <strong>Yahoo</strong> und auch GMX einige Mucken bei unseren Mails. Schau dort auf jeden Fall mal ob die Mail nicht im Spam-Filter hängen geblieben ist. Wenn Du keine Mail bekommen hast, probier <a href="https://mail.google.com">GMail</a>. </p> <h2 class="section" id="section-login">Warum kann ich mich nicht mehr einloggen?</h2> <p> Wenn Du uns kontaktierst, schicke bitte detaillierte Informationen über Dein System (Betriebssystem, Browser, etc.). Bevor Du das tust, prüfe bitte folgende Dinge: </p> <ul> <li>Gehe die Punkte bei <a href="#faq:troubleshooting">Warum funktioniert pr0gramm bei mir nicht richtig?</a> durch</li> <li>Lies nochmal ganz langsam die Meldung, die Dir beim Loginversuch angezeigt wird. Eventuell steht dort, dass Du gesperrt wurdest.</li> <li>Setze Dein Passwort über die "Passwort vergessen" zurück.</li> </ul> <p> Wenn Du immernoch kein Glück beim Login hast, schicke uns bitte Deinen Benutzernamen, die bei uns registrierte E-Mail Adresse sowie eine detaillierte Fehlerbeschreibung inklusive Informationen zu Deinem System (Betriebssystem, Browser, etc.) über das <a href="#contact">Kontaktformular</a>. </p> <h2 class="section" id="section-ban">Warum bin ich gebannt?</h2> <p> Den Bangrund und die Dauer bekommst Du angezeigt, wenn Du versuchst Dich erneut einzuloggen. </p> <h2 class="section" id="section-password">Wie kann ich mein Passwort zurücksetzen?</h2> <p> Falls Du noch eingeloggt bist, logge dich bitte aus. Im <em>"anmelden"</em> Fenster ist ein <em>"Passwort vergessen?"</em>-Link, über den Du Dein Passwort zurücksetzen kannst. </p> <h2 class="section" id="section-session">Jemand hat unrechtmäßig meinen Account benutzt. Was kann ich tun?</h2> <p> Beim Abmelden auf pr0gramm werden sämtliche Sitzungen auf allen Geräten abgemeldet. Beispiel: Du hast dich in der Uni angemeldet und vergessen dich abzumelden. Melde dich einfach zu Hause oder auf dem Handy ab und der Uni PC wird mit ausgeloggt. </p> <p> Falls jemand unrechtmäßig Deinen Account benutzt hat, solltest Du natürlich auch noch Dein Passwort ändern und in Deinem Profil prüfen ob Invites unrechtmässig verschickt wurden. Bei weiteren Problemen helfen wir über das <a href="#contact">Kontaktformular</a>. </p> <h2 class="section" id="section-rename">Wie kann ich meinen Benutzernamen ändern?</h2> <p> Den Benutzernamen ändern wir auf Anfrage nur unter besonderen Umständen. Ändern einzelner Buchstaben oder der Wechsel von einem Fantasienamen zu einem anderen gehören beispielsweise nicht dazu. Siehe auch <a href="#faq:account-delete">Wie kann ich meinen Account löschen?</a> </p> <h2 class="section" id="section-account-delete">Wie kann ich meinen Account löschen?</h2> <p> Wir löschen keine Accounts, da dadurch auch zwangsläufig Likes und Votes anderer Benutzer mit gerissen werden würden. In Extremfällen (stalking etc.) können wir Accounts umbenennen oder spezifische private Uploads löschen. Benutze das <a href="#contact">Kontaktformular</a> um Deinen Fall zu schildern. </p> </div> <div class="pane form-page"> <h1 class="pane-head">pr0mium</h1> <h2 class="section" id="section-pr0mium-account">Kann ich meinen Account auch ohne pr0mium noch nutzen?</h2> <p> Ja. Nach Ablauf der pr0mium Laufzeit bleibt Dein Account weiter aktiv. Du kannst lediglich die pr0mium Funktionen nicht mehr nutzen. </p> <h2 class="section" id="section-pr0mium-gift">Darf ich pr0mium verschenken oder verkaufen</h2> <p> Wenn Du pr0mium kaufst, erhältst Du einen Code um es einzulösen. Diesen Code darfst Du verschenken oder auch verkaufen. Der Verkauf von Invites hingegen ist ausdrücklich verboten - siehe <a href="#faq:invites">Wie funktioniert das mit den Invites?</a> </p> <h2 class="section" id="section-pr0mium-ban">Kann ich mit einem pr0mium-Account gesperrt werden?</h2> <p> Ja. An den Regeln ändert sich auch für pr0mium Benutzer nichts. Falls Du gebannt wirst, wird Dir allerdings die gebannte Zeit auf Deinem pr0mium-Account gutgeschrieben. Du zahlst nur für die Zeit, die Dein pr0mium-Account tatsächlich nutzbar ist. </p> </div> <div class="pane form-page"> <h1 class="pane-head">Löschanfragen & Copyright</h1> <h2 class="section" id="section-delete">Wie kann ich ein Bild von mir löschen?</h2> <p> Wenn es Deine Schulfreunde nicht so lustig fanden, auf pr0gramm gelandet zu sein wie Du dachtest, oder es sonstige triftige Gründe für eine Löschung gibt, kannst Du uns über das <a href="#contact">Kontaktformular</a> eine Löschanfrage schicken. </p> <p> Wenn Du ein Bild gelöscht haben möchtest, nur weil es viele Downvotes erhält, hast Du Pech gehabt. Vielleicht solltest Du aufhören so viel Scheiße zu posten. </p> <h2 class="section" id="section-copyright">Diese Seite verletzt mein Copyright!!11</h2> <p> Das ist keine Frage. </p> <p> Bevor Du uns garstige DMCA Takedown Notices schickst und uns mit Anwälten drohst, weil Dein unglaublich wertvolles Youtube Video mit 17 Views hier ohne Erlaubnis hochgeladen wurde, atme erstmal tief durch. Vielleicht ist es ja garnicht so schlecht hier aufzutauchen und von hunderttausenden Usern gesehen zu werden? Umgangssprachlich nennt man soetwas auch <em>"Werbung"</em>. </p> <p> Falls Du Dein Bild/Video dennoch gelöscht haben möchtest, schreibe uns über das <a href="#contact">Kontaktformular</a>. </p> </div> <div class="pane form-page"> <h1 class="pane-head">Bugs & technische Probleme</h1> <h2 class="section" id="section-troubleshooting">Warum funktioniert pr0gramm bei mir nicht richtig?</h2> <p> Bevor Du uns kontaktierst gehe folgende Punkte durch und prüfe ob der Fehler verschwindet: </p> <ul> <li>Browser neustarten</li> <li>Browsercache leeren</li> <li>Browserplugins testweise deaktivieren</li> <li>einen anderen Browser testen</li> </ul> <p> Falls sich der Fehler reproduzieren lässt, dann schick uns bitte eine detaillierte Fehlerbeschreibung inklusive Informationen zu Deinem System (Betriebssystem, Browser, etc.) über das <a href="#contact">Kontaktformular</a>: </p> <ol> <li>Was hast Du gemacht?</li> <li>Was hast Du erwartet was passiert?</li> <li>Was ist stattdessen passiert?</li> </ol> <h2 class="section" id="section-video">Warum werden die Videos bei mir nicht abgespielt?</h2> <p> pr0gramm benutzt die H264 Video und AAC Audio Codecs. Manche Browser liefern diese Codecs nicht mit. Für Chromium gibt es dazu ein paar <a href="http://chromium.woolyss.com/#html5-audio-video">Lösungen</a>. Ansonsten könnte auch <a href="/new/1372326">dieser Post</a> helfen. Für Windows 10 Nutzer die nach dem April 2017 Update Probleme haben gibt es ebenfalls <a href="/new/1898844">ein paar Tipps</a>. </p> <h2 class="section" id="section-down">Wieso ist pr0gramm down?</h2> <p> Ist es das? Frag erstmal <a href="http://www.downforeveryoneorjustme.com/">Down For Everyone Or Just Me?</a> ob das Problem nicht bei Dir liegt. Ansonsten findest Du aktuelle Status-Informationen immer auf <a href="https://twitter.com/pr0gramm">twitter.com/pr0gramm</a>. Außerdem solltest Du Dich fragen, wieso Du überhaupt dieses FAQ hier lesen kannst. </p> <h2 class="section" id="section-security">Ich kann pr0gramm hacken. Soll ich?</h2> <p> Nein. <p> <p> Wenn Du eine Sicherheitslücke oder Bugs gefunden hast, teile uns diese bitte über das <a href="#contact">Kontaktformular</a> mit. Je nach schwere des Problems verteilen wir als Dankeschön auch mal pr0mium. </p> </div> ',
7487 rulesView: null,
7488 filterView: null,
7489 render: function() {
7490 this.parent();
7491 this.rulesView = new p.View.Rules(this.$container.find('.faq-rules'), this);
7492 this.rulesView.show();
7493 this.filterView = new p.View.Filter(this.$container.find('.faq-filter'), this);
7494 this.filterView.show();
7495 this.fragmentChange(p.getFragment());
7496 },
7497 fragmentChange: function(fragment) {
7498 var target = fragment ? $('#section-' + fragment) : null;
7499 if (target && target.length) {
7500 var jumpPos = target.offset().top - CONFIG.HEADER_HEIGHT - 80;
7501 target.highlight(180, 180, 180, 1);
7502 $(document).scrollTop(jumpPos);
7503 }
7504 }
7505});
7506p.View.BuyCode = p.View.BuyCode || {};
7507p.View.BuyCode.BitcoinInfo = p.View.Base.extend({
7508 template: '<h1 class="pane-head">Bitcoin Zahlung</h1> <div class="pane form-page"> <p> Eine neue Bezahladresse wurde für Dich generiert: </p> <h2>Betrag: {params.amount} BTC</h2> <h2> Adresse: <a class="force-case" target="_blank" href="https://blockchain.info/address/{{params.address}}"> {{params.address}} </a> </h2> <p> Sobald wir auf diese Adresse Deine Zahlung erhalten haben, bekommst Du eine <?js if(p.user.id){?>Private Nachricht und eine<?js }?> E-Mail mit Deinem pr0mium-code von uns. <?js if( !p.user.id ){?> <span class="warn"> Schau bitte auch unbedingt in den Spam-Ordner deines Mail-Anbieters! </span> Hotmail und Yahoo verschlucken sowas gern. <?js } ?> </p> <p> Wenn Du Fragen hast, wende dich bitte über das <a href="#contact">Kontakt-Formular</a> an uns. </p> </div>'
7509});
7510p.View.BuyCode = p.View.BuyCode || {};
7511p.View.BuyCode.Products = p.View.Base.extend({
7512 data: {
7513 error: null,
7514 account: {
7515 email: '',
7516 paidUntil: null
7517 }
7518 },
7519 template: '<h1 class="pane-head">pr0mium Account</h1> <div class="pane form-page"> <div class="divide-3-1"> <h2 class="feature-head">Werbefrei</h2> <div class="feature-icon"> <img src="/media/pr0mium/star.png" alt=""/> </div> <p class="feature-description"> Das pr0gramm wie es sein sollte: ohne Werbebanner und drölf Prozent schneller. </p> </div> <div class="divide-3-2"> <h2 class="feature-head">Stelzen</h2> <div class="feature-icon"> <img src="/media/pr0mium/binoculars.png" alt=""/> </div> <p class="feature-description"> Folge Deinen Lieblings-Usern und verpasse nie wieder einen Upload. </p> </div> <div class="divide-3-3"> <h2 class="feature-head">admins füttern</h2> <div class="feature-icon"> <img src="/media/pr0mium/burger.png" alt=""/> </div> <p class="feature-description"> Unterstütze die Weiterentwicklung von pr0gramm. </p> </div> <div class="clear spacing"></div> <p> Als pr0mium-User darfst Du außerdem Dateien mit bis zu 12MB hochladen (statt nur 6MB). Zudem hast Du die Wahl, ob Du als “Edler Spender†oder mit Deinem normalen Status angezeigt wirst. </p> <p> Viele weitere Features werden folgen! </p> <div class="clear spacing"></div> <div class="divide-2-1"> <div class="product-description" id="product-pr0mium90"> <div class="product-text"> <h2><?js if( !p.user.id ) {?>Account +<br/><?js } ?>3 Monate pr0mium</h2> <p> <?js if( !p.user.id ) {?>Dein neuer pr0gramm-Account und<?js } ?> 3 Monate lang alle pr0mium Features. </p> <p> Nach Ablauf der 3 Monate ist dein Account weiterhin ohne die pr0mium Features nutzbar. </p> </div> <h1 class="price"><span class="price-detail">nur</span> 9<span class="price-symbol">€</span></h1> <span class="confirm-button product-select" data-name="pr0mium90">3 Monate auswählen</span> </div> </div> <div class="divide-2-2"> <div class="product-description" id="product-pr0mium365"> <div class="product-text"> <h2><?js if( !p.user.id ) {?>Account +<br/><?js } ?>12 Monate pr0mium</h2> <p> <?js if( !p.user.id ) {?>Dein neuer pr0gramm-Account und<?js } ?> 12 Monate lang alle pr0mium Features. </p> <p> Nach Ablauf der 12 Monate ist dein Account weiterhin ohne die pr0mium Features nutzbar. </p> </div> <h1 class="price"><span class="price-detail">nur</span> 29<span class="price-symbol">€</span></h1> <span class="confirm-button product-select" data-name="pr0mium365">12 Monate auswählen</span> </div> </div> <div class="clear" id="step-2"></div> <form method="post" id="payment-form"> <h2 id="head-pr0mium90"> <?js if( !p.user.id ) {?>Account + <?js } ?> 3 Monate pr0mium für 9€ kaufen </h2> <h2 id="head-pr0mium365"> <?js if( !p.user.id ) {?>Account + <?js } ?> 12 Monate pr0mium für 29€ kaufen </h2> <p> Sofort nach Bestätigung Deiner Zahlung bekommst Du von uns eine E-Mail mit deinem pr0mium-Code. </p> <div class="form-row"> <h3>Deine E-Mail Adresse:</h3> <input id="email" type="email" name="email" value="{{account.email}}" required class="text-line important" placeholder="E-Mail Adresse"/> <p class="warn" id="email-invalid">Ungültige E-Mail Adresse</p> <h3>Bitte bestätige Deine E-Mail Adresse:</h3> <input id="email_confirm" type="email" name="email_confirm" value="{{account.email}}" required class="text-line important" placeholder="E-Mail Adressen Bestätigung"/> <p class="warn" id="email-confirm-invalid">Ungültige E-Mail Adresse</p> <p class="warn" id="email-confirm-nomatch">Die beiden E-Mail Adressen stimmen nicht überein</p> </div> <div class="form-row" id="tos-row"> <input type="checkbox" class="box-from-label" id="tos" name="tos"/> <label for="tos">Ich habe die <a target="_blank" href="/tos">AGB und Widerrufsbelehrung</a> gelesen.</label> </div> <div class="form-row"> <input type="hidden" name="product" value="invalid"/> <input type="button" class="pay-with-paypal checkout confirm" value="Zahlen mit"/> <input type="button" class="pay-with-braintree checkout confirm" value="Zahlen mit Kreditkarte"/> <input type="button" class="pay-with-bitcoin checkout confirm" value="Zahlen mit Bitcoin"/> </div> </form> <div id="bt-overlay"> <div id="bt-window"> <form id="bt-checkout" method="post" action="/api/braintree/charge" > <a id="bt-logo" href="https://www.braintreegateway.com/merchants/yhmycp4cr95zss48/verified" target="_blank"> <img src="https://s3.amazonaws.com/braintree-badges/braintree-badge-wide-dark.png" width="280px" height ="44px" border="0"/> </a> <div id="bt-form"></div> <input type="submit" id="bt-complete-payment" value="Zahlung abschließen"> <input type="hidden" id="bt-token" name="token" value=""/> </form> </div> </div> <p class="faint-footer"> <a target="_blank" href="/tos">AGB und Widerrufsbelehrung</a> / <a target="_blank" href="/imprint">Impressum</a> </p> </div> ',
7520 braintreeJSLoaded: false,
7521 load: function() {
7522 if (window.location.protocol != "https:") {
7523 var domainAndPath = window.location.href.substring(window.location.protocol.length);
7524 window.location.href = "https:" + domainAndPath;
7525 return
7526 }
7527 if (this.data.params.iap) {
7528 $('#head').hide();
7529 }
7530 if (!p.user.id) {
7531 return true;
7532 }
7533 p.api.get('user.info', {}, this.loaded.bind(this));
7534 return false
7535 },
7536 loaded: function(response) {
7537 this.data.account = response.account;
7538 if (this.data.account.paidUntil) {
7539 this.data.account.paidUntil = new Date(this.data.account.paidUntil * 1000);
7540 }
7541 this.render();
7542 },
7543 render: function() {
7544 this.parent();
7545 this.$paymentForm = this.$container.find('#payment-form');
7546 this.$container.find('.confirm-button.product-select').click(this.selectProduct.bind(this));
7547 this.$container.find('.checkout').click(this.submit.bind(this));
7548 },
7549 selectProduct: function(ev) {
7550 var name = $(ev.currentTarget).data('name');
7551 var $selected = this.$container.find('#product-' + name);
7552 var $deselected = this.$container.find('.product-description').not($selected);
7553 $selected.removeClass('deselected').addClass('selected');
7554 $deselected.removeClass('selected').addClass('deselected');
7555 this.$container.find('#head-pr0mium90, #head-pr0mium365').hide();
7556 this.$container.find('#head-' + name).show();
7557 this.$paymentForm.find('#email-invalid').hide();
7558 this.$paymentForm.find('#email-confirm-invalid').hide();
7559 this.$paymentForm.find('#email-confirm-nomatch').hide();
7560 this.$paymentForm.find('#email-blacklisted').hide();
7561 this.$paymentForm.find('input[name=product]').val(name);
7562 if (!p.mobile && !this.$paymentForm.is(':visible')) {
7563 $('html, body').animate({
7564 scrollTop: this.$container.find('#step-2').offset().top
7565 });
7566 this.$paymentForm.slideDown(function() {
7567 $('input[name=email]').focus();
7568 });
7569 } else if (p.mobile) {
7570 this.$paymentForm.show();
7571 $('html, body').scrollTop(this.$container.find('#step-2').offset().top);
7572 }
7573 },
7574 submit: function(ev) {
7575 var email = $('input[name=email]').val();
7576 var email_confirm = $('input[name=email_confirm]').val();
7577 if (!email.match(/.+@.+\..+/)) {
7578 $('#email-invalid').show();
7579 return false;
7580 } else {
7581 $('#email-invalid').hide();
7582 }
7583 if (!email_confirm.match(/.+@.+\..+/)) {
7584 $('#email-confirm-invalid').show();
7585 return false;
7586 } else {
7587 $('#email-confirm-invalid').hide();
7588 }
7589 if (email != email_confirm) {
7590 $('#email-confirm-nomatch').show();
7591 return false;
7592 } else {
7593 $('#email-confirm-nomatch').hide();
7594 }
7595 if (!this.$container.find('input[name=tos]:checked').length) {
7596 this.$container.find('#tos-row').highlight(252, 136, 52, 1);
7597 return false;
7598 }
7599 $('#email-invalid').hide();
7600 this.$paymentForm.find('.checkout').hide();
7601 this.showLoader();
7602 if ($(ev.currentTarget).hasClass('pay-with-paypal')) {
7603 p.api.post('paypal.getcheckouturl', this.$paymentForm, this.paypalCheckoutResponse.bind(this));
7604 } else if ($(ev.currentTarget).hasClass('pay-with-braintree')) {
7605 this.loadBraintreeJS(function() {
7606 p.api.post('braintree.getcheckouttoken', this.$paymentForm, this.braintreeCheckoutResponse.bind(this));
7607 }.bind(this));
7608 } else if ($(ev.currentTarget).hasClass('pay-with-bitcoin')) {
7609 p.api.post('bitcoin.getpaymentaddress', this.$paymentForm, this.bitcoinCheckoutResponse.bind(this));
7610 }
7611 return false;
7612 },
7613 loadBraintreeJS: function(callback) {
7614 if (this.braintreeJSLoaded) {
7615 callback();
7616 } else {
7617 $.getScript("https://js.braintreegateway.com/js/braintree-2.26.0.min.js", function() {
7618 this.braintreeJSLoaded = true;
7619 callback();
7620 }.bind(this));
7621 }
7622 },
7623 braintreeCheckoutResponse: function(response) {
7624 if (response.error) {
7625 this.$paymentForm.find('.checkout').show();
7626 return;
7627 }
7628 this.hideLoader();
7629 $('#bt-overlay').show();
7630 $('#bt-token').val(response.internalToken);
7631 braintree.setup(response.checkoutToken, "dropin", {
7632 container: "bt-form",
7633 paypal: {
7634 button: {
7635 type: 'checkout'
7636 }
7637 }
7638 });
7639 },
7640 paypalCheckoutResponse: function(response) {
7641 if (response.error) {
7642 this.$paymentForm.find('.checkout').show();
7643 } else {
7644 window.location = response.checkoutUrl;
7645 }
7646 },
7647 bitcoinCheckoutResponse: function(response) {
7648 if (response.error) {
7649 this.$paymentForm.find('.checkout').show();
7650 } else {
7651 window.location = response.address;
7652 }
7653 }
7654});
7655p.View.BuyCode = p.View.BuyCode || {};
7656p.View.BuyCode.PaypalThanks = p.View.Base.extend({
7657 template: '<h1 class="pane-head">Danke <span class="pict">*</span></h1> <div class="pane form-page"> <p> Vielen Dank für den Kauf Deines pr0mium-Codes. Sobald Deine Zahlung bestätigt ist, bekommst Du eine <?js if(p.user.id){?>Private Nachricht und eine<?js }?> E-Mail mit Deinem pr0mium-code von uns. </p> <h2>Paypal</h2> <p> In den meisten Fällen kann die Zahlung sofort bestätigen werden. Bei neuen, nicht verifizierten PayPal-Accounts kann die Bestätigung 1-2 Tage dauern. Den Status deiner Zahlung siehst Du in deinem PayPal-Account. Beim Status "pending" ist die Zahlung noch nicht durchgeführt worden, bei "completed" solltest Du deinen Code bereits erhalten haben. </p> <h2>Kreditkarte</h2> <p> In der Regel kann eine Zahlung via Kredikarte sofort bestätigt werden. Sollte deine Zahlung nicht bestätigt werden können, ist vermutlich etwas mit deiner Karte nicht in Ordnung. Wende dich in dem Fall an deine Bank oder Kreditkartenunternehmen. </p> <?js if( !p.user.id ){ ?> <p> <span class="warn"> Schau bitte auch unbedingt in den Spam-Ordner deines Mail-Anbieters! Solltest Du trotzdem noch keine E-Mail erhalten haben, setze dich bitte mit uns in Kontakt. </span> Hotmail und Yahoo verschlucken sowas gern. </p> <?js } ?> <p> Wenn Du Fragen hast, wende dich bitte über das <a href="#contact">Kontakt-Formular</a> an uns. </p> </div>'
7658});
7659p.View.RedeemShopCoupon = p.View.Base.extend({
7660 template: '<h1 class="pane-head">Code Einlösen</h1> <div class="pane form-page"> <?js if(redeemed) { ?> <h2>Code eingelöst!</h2> <p> Danke! Dir wurden soeben 31 Tage pr0mium gutgeschrieben.<br/> Außerdem trägt Dein Profil nun mit Stolz das <em>Kommerzhure</em>-Badge! </p> <p> <img src="/media/badges/shopping-cart.png" alt="Kommerzhure"/> <strong> Kommerzhure</strong> </p> <p> Toll! </p> <?js } else if(p.user.id) { ?> <form method="post" id="redeem-form"> <p> Der Code gilt für Deinen Account ({{p.user.name}}). </p> <?js if(error) { ?> <p class="warn"> <?js if (error === \'codeInvalid\') {?> Ungültiger Code. Überprüfe bitte, dass Du den Code korrekt abgetippt hast. Groß/Klein-schreibung beachten! <?js } else if( error === \'codeUsed\' ) { ?> Dieser Code wurde bereits eingelöst. <?js } ?> </p> <?js } ?> <div class="form-row"> <label>Code:</label> <input type="text" name="code" value="{{code}}" class="text-line"/> </div> <div class="form-row"> <input type="submit" class="confirm" value="Code jetzt einlösen"/> </div> </form> <?js } else { ?> <h2>Nicht angemeldet</h2> <p> Entschuldigung, Du kannst einen Code nur einlösen, wenn du angemeldet bist. </p> <p> Wenn du noch keinen Account hast, kannst Du dich von einem anderen Benutzer einladen lassen, oder Dir jetzt einen pr0mium Account erstellen. </p> <div class="call-to-action"> <a href="#pr0mium" class="confirm-button">Jetzt pr0mium User werden</a> </div> <?js } ?> </div> ',
7661 data: {
7662 error: null,
7663 redeemed: false,
7664 code: ''
7665 },
7666 render: function() {
7667 this.parent();
7668 this.$container.find('#redeem-form').submit(this.redeem.bind(this));
7669 this.focus('input[name=code]');
7670 },
7671 redeem: function(ev) {
7672 this.data.error = null;
7673 this.data.code = this.$container.find('input[name=code]').val();
7674 p.api.post('user.redeemshopcoupon', ev.target, this.posted.bind(this));
7675 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7676 this.showLoader();
7677 return false;
7678 },
7679 posted: function(response) {
7680 if (response.error) {
7681 this.data.error = response.error;
7682 } else {
7683 this.data.error = null;
7684 this.data.redeemed = true;
7685 p.user.loadCookie();
7686 p.user.set('paid', true);
7687 }
7688 this.render();
7689 }
7690});
7691p.View.Imprint = p.View.Base.extend({
7692 template: '<h1 class="pane-head">Impressum</h1> <div class="pane form-page"> <p> Bei Fragen oder sonstigen Anliegen wenden Sie sich bitte über das <a href="#contact">Kontakformular</a> an uns. </p> <p> Suntainment S.L.<br/> Apartado de Correos, 6241<br/> 07157 Port de Andratx<br/> </p> </div> '
7693});
7694p.View.TOS = p.View.Base.extend({
7695 template: '<h1 class="pane-head">AGB / Widerrufsbelehrung</h1> <div class="pane form-page"> <h2>Widerrufsbelehrung</h2> <h3>Widerrufsrecht</h3> <p>Sie haben das Recht, binnen vierzehn Tagen ohne Angabe von Gründen diesen Vertrag zu widerrufen. Die Widerrufsfrist beträgt vierzehn Tage ab dem Tag des Vertragsabschlusses.</p> <p>Um Ihr Widerrufsrecht auszuüben, müssen Sie uns über das <a href="#contact">Kontaktformular</a> mittels einer eindeutigen Erklärung über Ihren Entschluss, diesen Vertrag zu widerrufen, informieren. Zur Wahrung der Widerrufsfrist reicht es aus, dass Sie die Mitteilung über die Ausübung des Widerrufsrechts vor Ablauf der Widerrufsfrist absenden.</p> <h3>Folgen des Widerrufs</h3> <p>Wenn Sie diesen Vertrag widerrufen, haben wir Ihnen alle Zahlungen, die wir von Ihnen erhalten haben unverzüglich und spätestens binnen vierzehn Tagen ab dem Tag zurückzuzahlen, an dem die Mitteilung über Ihren Widerruf dieses Vertrags bei uns eingegangen ist. Für diese Rückzahlung verwenden wir dasselbe Zahlungsmittel, das Sie bei der ursprünglichen Transaktion eingesetzt haben, es sei denn, mit Ihnen wurde ausdrücklich etwas anderes vereinbart; in keinem Fall werden Ihnen wegen dieser Rückzahlung Entgelte berechnet.</p> <h2 class="section">Allgemeine Nutzungsbedingungen für pr0gramm.com</h2> <h3>1. Definitionen und Geltungsbereich</h3> <p>1.1 Für die Nutzung der kostenpflichtigen Zusatzfunktionen von pr0gramm.com (nachfolgend: „Website“) und für die damit zusammenhängenden Leistungen des Betreibers gelten die nachfolgenden Allgemeinen Geschäftsbedingungen (nachfolgend: „AGB“).</p> <p>1.2 Im Sinne dieser AGB bezeichnet der Begriff „Kunde“ den Nutzer der kostenpflichtigen Version der Website.</p> <h3>2. Leistungen des Betreibers</h3> <p>2.1 Der Betreiber bietet eine kostenfreie Version der Website an. Diese kostenfreie Version der Website erfordert keine Anmeldung und ist für jedermann frei im Internet abrufbar. Sie finanziert sich im Wesentlichen über Werbeeinblendungen.</h3> <p>2.2 Daneben bietet der Betreiber dem Kunden aber auch die Nutzung einer kostenpflichtigen Version der Website an. Die Höhe des Entgelts hängt von der Laufzeit des Produkts ab. Diese kostenpflichtige Version der Website ist im Gegenzug – vorbehaltlich Ziff. 2.3 – frei von Werbung.</p> <p>2.3 Der Betreiber behält sich vor, auch in der kostenpflichtigen Version der Website (Ziff. 2.2) eine Fläche für bezahltes Sponsoring vorzusehen.</p> <p>2.4 Voraussetzung für die Nutzung der kostenpflichtigen Version der Website ist die Einrichtung eines Benutzeraccounts durch den Kunden und der Abschluss eines Vertrags zwischen dem Kunden und dem Betreiber.</p> <h3>3. Leistungen des Kunden und Vertragsschluss</h3> <p>3.1 Der Kunde, der die bezahlte, aber werbefreie Version der Website (Ziff. 2.2) in Anspruch nehmen möchte, muss einen Benutzeraccount einrichten und ein kostenpflichtiges Produkt buchen. Die Produkte mit Laufzeiten und Preisen können in ihrer jeweils aktuellen Fassung der auf der Website abrufbaren Preisliste entnommen werden.</p> <p>3.2 Der Vertrag kommt durch die Annahme des vom Kunden unterbreiteten Angebots durch den Betreiber zustande. Der Kunde gibt sein auf den Vertragsschluss gerichtetes Angebot an den Betreiber dadurch ab, dass er sich als Nutzer von pr0gramm.com registriert, das jeweilige Produkt auf pr0gramm.com auswählt, seine Anmeldedaten und Zahlungsinformationen eingibt und den Button mit der Beschriftung „Zahlen mit PayPal“ oder „Zahlen mit Bitcoin“ betätigt. Das Angebot wird von dem Betreiber dadurch angenommen, dass der Zugang des Kunden zur kostenpflichtigen Version von pr0gramm.com freigeschaltet wird. Über die Freischaltung erhält der Kunde eine gesonderte Nachricht per Email. <h3>4. Preise und Zahlungsbedingungen</h3> <p>4.1 Die angegebenen Preise verstehen sich sämtlich einschließlich der jeweils geltenden deutschen gesetzlichen Umsatzsteuer. Soweit nicht anders angegeben, handelt es sich bei den angegebenen Preisen um monatliche Beiträge.</p> <p>4.2 Der Preis für das vom Kunden gebuchte Produkt wird stets für die gesamte Laufzeit im Voraus sofort zur Zahlung fällig.</p> <p>4.3 Der Betreiber bietet gegebenenfalls verschiedene Zahlungsmöglichkeiten an (z.B. Kreditkarte oder Paypal), ohne hierzu jedoch verpflichtet zu sein. Der Betreiber ist berechtigt, sich zum Zweck der Zahlungsabwicklung und des Forderungseinzugs Dritter zu bedienen. Für die Zahlungsabwicklung über Zahlungssystemanbieter (z.B. PayPal) gelten die Nutzungs- und Geschäftsbedingungen des betreffenden Zahlungssystemanbieters; gegebenenfalls muss der Kunde zudem über ein Benutzerkonto bei dem Anbieter verfügen.</p> <h3>5. Zugangsdaten</h3> <p>5.1 Die Zugangsdaten (Benutzername/Email-Adresse und Passwort) sind ausschließlich für die Nutzung durch den Kunden persönlich bestimmt. Der Kunde darf die Zugangsdaten nicht an Dritte weitergeben oder sie anderweitig offenlegen. Erhält der Kunde Kenntnis von einem Missbrauch seiner Zugangsdaten oder hat er einen solchen Verdacht, muss er dies dem Betreiber umgehend mitteilen. Der Kunde haftet für alle Folgen der unberechtigten Nutzung seiner Zugangsdaten durch Dritte, sofern der Missbrauch der Zugangsdaten von ihm zu vertreten ist. Die Haftung des Kunden endet erst, wenn er den Betreiber über die unberechtigte Nutzung oder das Abhandenkommen der Zugangsdaten informiert und das Passwort geändert hat.</p> <p>5.2 Der Betreiber ist berechtigt, den Account des Kunden bei Verstößen gegen diese Allgemeinen Geschäftsbedingungen, insbesondere wegen falscher Angaben bei der Registrierung und/oder unbefugter Weitergabe der Zugangsdaten, zu sperren und das Produkt außerordentlich und fristlos zu kündigen. Nach einem solchen Fall darf sich der Kunden ohne die vorherige ausdrückliche Zustimmung des Betreibers nicht erneut registrieren.</p> <h3>6. Haftung</h3> <p>6.1 Die Nutzung der Website erfolgt auf eigenes Risiko der Nutzer. Der Betreiber übernimmt keine Haftung für das unterbrechungsfreie, sichere und fehlerfreie Funktionieren der Website, bzw. für verloren gegangene Daten des Nutzers. Die Haftungsbeschränkung gilt nicht für die Verletzung von Leben, Körper oder Gesundheit infolge eines fahrlässigen oder vorsätzlichen Handelns des Betreibers. Die Haftung nach gesetzlichen Vorschriften, deren Ausschluss verboten ist, bleibt unbenommen. Die Haftung ist begrenzt auf den typischerweise vorhersehbaren Schaden. Dies gilt nicht für die Verletzung vertragswesentlicher Pflichten und die Haftung nach dem Produkthaftungsgesetz.</p> <h3>7. Regeln für die Nutzung der Website</h3> <p>7.1 Der Kunde hat die Möglichkeit Text und Bilder auf der Website zu veröffentlichen. Der Kunde verpflichtet sich die <a href="#faq:rules">Regeln</a> der Website einzuhalten. Bei Verstößen gegen diese Regeln, hat der Betreiber das Recht den Account des Kunden ohne vorherige Warnung für eine begrenzte Zeit oder, in schweren Verstößen gegen die Regeln, auch unbegrenzt zu sperren.</p> <p>7.2 Im Fall von Verstößen gegen die <a href="#faq:rules">Regeln</a> bei pr0gramm.com oder den Allgemeinen Nutzungsbedingungen ist der Betreiber zur außerordentlichen Kündigung des Nutzungsvertrags berechtigt.</p> <h3>8. Anwendbares Recht und Gerichtsstand</h3> <p>8.1 Diese Allgemeinen Nutzungsbedingungen sowie die Nutzung der Dienste bestimmen sich nach deutschem Recht. Für Streitigkeiten außer im Zusammenhang mit der Nutzung der Website und/oder dieser Allgemeinen Nutzungsbedingungen sind die für den Sitz des Betreibers zuständigen Gerichte ausschließlich zuständig, soweit es sich bei dem Nutzer um einen Kaufmann handelt oder der Nutzer keinen dauerhaften Wohnsitz in Deutschland hat.</p> </div>'
7696});
7697p.View.Bookmarklet = p.View.Bookmarklet || {};
7698p.View.Bookmarklet.Layout = p.View.Base.extend({
7699 template: '<div id="main-view" class="bookmarklet"></div> ',
7700 init: function(container, parent) {
7701 $('html,body').css('background-color', 'transparent');
7702 this.parent(container, parent);
7703 }
7704});
7705p.View.Bookmarklet = p.View.Bookmarklet || {};
7706p.View.Bookmarklet.Login = p.View.Base.extend({
7707 template: '<div class="overlay-content"> <div class="bookmarklet-head" style="height:50px;"> <img src="/media/pr0gramm.png" class="bookmarklet-logo"/> </div> <?js if(loginFailed) {?> <?js if(ban && ban.banned) { ?> <p class="warn"> Dein Account ist gesperrt. <?js if(ban.till) {?> Die Sperrung wird am {ban.till.readableTime()} ({ban.till.relativeTime()}) aufgehoben. <?js } else { ?> Die Sperrung ist dauerhaft. <?js } ?> <?js if(ban.reason) {?> <strong>Grund:</strong> {{ban.reason}} <?js } ?> </p> <?js } else { ?> <p class="warn">Falscher Benutzername oder Passwort</p> <?js } ?> <?js } ?> <form> <div class="form-row"> <label>Name oder E-Mail Adresse:</label> <input type="text" class="text-line" name="name" placeholder="Name" tabindex="201" value="{{name}}"/> </div> <div class="form-row"> <label>Passwort:</label> <input type="password" class="text-line" name="password" placeholder="Passwort" tabindex="202"/> </div> <div class="form-row"> <input type="submit" value="Anmelden" id="login-button" tabindex="203"/> </div> </form> </div> ',
7708 data: {
7709 ban: null,
7710 name: '',
7711 loginFailed: false
7712 },
7713 render: function() {
7714 this.parent();
7715 this.$container.find('form').submit(this.submit.bind(this));
7716 this.focus('input[name=name]');
7717 },
7718 submit: function(ev) {
7719 p.user.login(ev.target, this.posted.bind(this));
7720 this.data.name = $(ev.target).find('input[name=name]').val();
7721 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
7722 this.showLoader();
7723 return false;
7724 },
7725 posted: function(response) {
7726 if (response.success) {
7727 p.navigateToPopStack();
7728 } else {
7729 this.data.loginFailed = true;
7730 this.data.ban = response.ban;
7731 if (this.data.ban && this.data.ban.till) {
7732 this.data.ban.till = new Date(this.data.ban.till * 1000);
7733 }
7734 this.render();
7735 }
7736 }
7737});
7738(function($) {
7739 var delimiter = new Array();
7740 var tags_callbacks = new Array();
7741 $.fn.doAutosize = function(o) {
7742 var minWidth = $(this).data('minwidth'),
7743 maxWidth = $(this).data('maxwidth'),
7744 val = '',
7745 input = $(this),
7746 testSubject = $('#' + $(this).data('tester_id'));
7747 if (val === (val = input.val())) {
7748 return;
7749 }
7750 var escaped = val.replace(/&/g, '&').replace(/\s/g, ' ').replace(/</g, '<').replace(/>/g, '>');
7751 testSubject.html(escaped);
7752 var testerWidth = testSubject.width(),
7753 newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
7754 currentWidth = input.width(),
7755 isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) || (newWidth > minWidth && newWidth < maxWidth);
7756 if (isValidWidthChange) {
7757 input.width(newWidth);
7758 }
7759 };
7760 $.fn.resetAutosize = function(options) {
7761 var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(),
7762 maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding),
7763 val = '',
7764 input = $(this),
7765 testSubject = $('<tester/>').css({
7766 position: 'absolute',
7767 top: -9999,
7768 left: -9999,
7769 width: 'auto',
7770 fontSize: input.css('fontSize'),
7771 fontFamily: input.css('fontFamily'),
7772 fontWeight: input.css('fontWeight'),
7773 letterSpacing: input.css('letterSpacing'),
7774 whiteSpace: 'nowrap'
7775 }),
7776 testerId = $(this).attr('id') + '_autosize_tester';
7777 if (!$('#' + testerId).length > 0) {
7778 testSubject.attr('id', testerId);
7779 testSubject.appendTo('body');
7780 }
7781 input.data('minwidth', minWidth);
7782 input.data('maxwidth', maxWidth);
7783 input.data('tester_id', testerId);
7784 input.css('width', minWidth);
7785 };
7786 $.fn.addTag = function(value, options) {
7787 options = jQuery.extend({
7788 focus: false,
7789 callback: true
7790 }, options);
7791 this.each(function() {
7792 var id = $(this).attr('id');
7793 var tagslist = $(this).val().split(delimiter[id]);
7794 if (tagslist[0] == '') {
7795 tagslist = new Array();
7796 }
7797 value = jQuery.trim(value);
7798 if (options.unique) {
7799 var skipTag = $(this).tagExist(value);
7800 if (skipTag == true) {
7801 $('#' + id + '_tag').addClass('not_valid');
7802 }
7803 } else {
7804 var skipTag = false;
7805 }
7806 if (value != '' && skipTag != true) {
7807 $('<span>').addClass('tag').append($('<span>').text(value).append(' '), $('<a>', {
7808 href: '#',
7809 title: 'Removing tag',
7810 text: 'x'
7811 }).click(function() {
7812 return $('#' + id).removeTag(escape(value));
7813 })).insertBefore('#' + id + '_addTag');
7814 tagslist.push(value);
7815 $('#' + id + '_tag').val('');
7816 if (options.focus) {
7817 $('#' + id + '_tag').focus();
7818 } else {
7819 $('#' + id + '_tag').blur();
7820 }
7821 $.fn.tagsInput.updateTagsField(this, tagslist);
7822 if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) {
7823 var f = tags_callbacks[id]['onAddTag'];
7824 f.call(this, value);
7825 }
7826 if (tags_callbacks[id] && tags_callbacks[id]['onChange']) {
7827 var i = tagslist.length;
7828 var f = tags_callbacks[id]['onChange'];
7829 f.call(this, $(this), tagslist[i - 1]);
7830 }
7831 }
7832 });
7833 return false;
7834 };
7835 $.fn.removeTag = function(value) {
7836 value = unescape(value);
7837 this.each(function() {
7838 var id = $(this).attr('id');
7839 var old = $(this).val().split(delimiter[id]);
7840 $('#' + id + '_tagsinput .tag').remove();
7841 var str = '';
7842 for (var i = 0; i < old.length; i++) {
7843 if (old[i] != value) {
7844 str = str + delimiter[id] + old[i];
7845 }
7846 }
7847 $.fn.tagsInput.importTags(this, str);
7848 if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) {
7849 var f = tags_callbacks[id]['onRemoveTag'];
7850 f.call(this, value);
7851 }
7852 });
7853 return false;
7854 };
7855 $.fn.tagExist = function(val) {
7856 var id = $(this).attr('id');
7857 var tagslist = $(this).val().split(delimiter[id]);
7858 return (jQuery.inArray(val, tagslist) >= 0);
7859 };
7860 $.fn.importTags = function(str) {
7861 id = $(this).attr('id');
7862 $('#' + id + '_tagsinput .tag').remove();
7863 $.fn.tagsInput.importTags(this, str);
7864 }
7865 $.fn.tagsInput = function(options) {
7866 var settings = jQuery.extend({
7867 interactive: true,
7868 defaultText: 'add a tag',
7869 minChars: 0,
7870 maxChars: 32,
7871 width: '300px',
7872 height: '100px',
7873 autocomplete: {
7874 selectFirst: false
7875 },
7876 hide: true,
7877 delimiter: ',',
7878 unique: true,
7879 removeWithBackspace: true,
7880 placeholderColor: '#666666',
7881 autosize: true,
7882 comfortZone: 20,
7883 inputPadding: 6 * 2
7884 }, options);
7885 this.each(function() {
7886 if (settings.hide) {
7887 $(this).hide();
7888 }
7889 var id = $(this).attr('id');
7890 if (!id || delimiter[$(this).attr('id')]) {
7891 id = $(this).attr('id', 'tags' + new Date().getTime()).attr('id');
7892 }
7893 var data = jQuery.extend({
7894 pid: id,
7895 real_input: '#' + id,
7896 holder: '#' + id + '_tagsinput',
7897 input_wrapper: '#' + id + '_addTag',
7898 fake_input: '#' + id + '_tag'
7899 }, settings);
7900 delimiter[id] = data.delimiter;
7901 if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
7902 tags_callbacks[id] = new Array();
7903 tags_callbacks[id]['onAddTag'] = settings.onAddTag;
7904 tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
7905 tags_callbacks[id]['onChange'] = settings.onChange;
7906 }
7907 var cc = $(this).attr('class');
7908 var markup = '<div id="' + id + '_tagsinput" class="tagsinput ' + cc + '"><div id="' + id + '_addTag">';
7909 if (settings.interactive) {
7910 markup = markup + '<input id="' + id + '_tag" value="" ' + 'class="tagsinput-writebox" maxlength="' + settings.maxChars + '" ' + 'data-default="' + settings.defaultText + '" />';
7911 }
7912 markup = markup + '</div><div class="tags_clear"></div></div>';
7913 $(markup).insertAfter(this);
7914 if ($(data.real_input).val() != '') {
7915 $.fn.tagsInput.importTags($(data.real_input), $(data.real_input).val());
7916 }
7917 if (settings.interactive) {
7918 $(data.fake_input).val($(data.fake_input).attr('data-default'));
7919 $(data.fake_input).addClass('tagsinput-placeholder');
7920 $(data.fake_input).resetAutosize(settings);
7921 $(data.holder).bind('click', data, function(event) {
7922 $(event.data.fake_input).focus();
7923 });
7924 $(data.fake_input).bind('focus', data, function(event) {
7925 if ($(event.data.fake_input).val() == $(event.data.fake_input).attr('data-default')) {
7926 $(event.data.fake_input).val('');
7927 }
7928 $(event.data.fake_input).addClass('active');
7929 });
7930 if (settings.autocomplete_url != undefined) {
7931 autocomplete_options = {
7932 source: settings.autocomplete_url
7933 };
7934 for (attrname in settings.autocomplete) {
7935 autocomplete_options[attrname] = settings.autocomplete[attrname];
7936 }
7937 if (jQuery.Autocompleter !== undefined) {
7938 $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete);
7939 $(data.fake_input).bind('result', data, function(event, data, formatted) {
7940 if (data) {
7941 $('#' + id).addTag(data[0] + "", {
7942 focus: true,
7943 unique: (settings.unique)
7944 });
7945 }
7946 });
7947 } else if (jQuery.ui.autocomplete !== undefined) {
7948 $(data.fake_input).autocomplete(autocomplete_options);
7949 $(data.fake_input).bind('autocompleteselect', data, function(event, ui) {
7950 $(event.data.real_input).addTag(ui.item.value, {
7951 focus: true,
7952 unique: (settings.unique)
7953 });
7954 return false;
7955 });
7956 }
7957 } else {
7958 $(data.fake_input).bind('blur', data, function(event) {
7959 var d = $(this).attr('data-default');
7960 if ($(event.data.fake_input).val() != '' && $(event.data.fake_input).val() != d) {
7961 if ((event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)))
7962 $(event.data.real_input).addTag($(event.data.fake_input).val(), {
7963 focus: true,
7964 unique: (settings.unique)
7965 });
7966 } else {
7967 $(event.data.fake_input).val($(event.data.fake_input).attr('data-default'));
7968 $(event.data.fake_input).removeClass('active');
7969 }
7970 return false;
7971 });
7972 }
7973 $(data.fake_input).bind('keypress', data, function(event) {
7974 if (event.which == event.data.delimiter.charCodeAt(0) || event.which == 13) {
7975 event.preventDefault();
7976 if ((event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)))
7977 $(event.data.real_input).addTag($(event.data.fake_input).val(), {
7978 focus: true,
7979 unique: (settings.unique)
7980 });
7981 $(event.data.fake_input).resetAutosize(settings);
7982 return false;
7983 } else if (event.data.autosize) {
7984 $(event.data.fake_input).doAutosize(settings);
7985 }
7986 });
7987 data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event) {
7988 if (event.keyCode == 8 && $(this).val() == '') {
7989 event.preventDefault();
7990 var last_tag = $(this).closest('.tagsinput').find('.tag:last').text();
7991 var id = $(this).attr('id').replace(/_tag$/, '');
7992 last_tag = last_tag.replace(/[\s]+x$/, '');
7993 $('#' + id).removeTag(escape(last_tag));
7994 $(this).trigger('focus');
7995 }
7996 });
7997 $(data.fake_input).blur();
7998 if (data.unique) {
7999 $(data.fake_input).keydown(function(event) {
8000 if (event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéÃóúÃÉÃÓÚñÑ,/]+/)) {
8001 $(this).removeClass('not_valid');
8002 }
8003 });
8004 }
8005 }
8006 });
8007 return this;
8008 };
8009 $.fn.tagsInput.updateTagsField = function(obj, tagslist) {
8010 var id = $(obj).attr('id');
8011 $(obj).val(tagslist.join(delimiter[id]));
8012 };
8013 $.fn.tagsInput.importTags = function(obj, val) {
8014 $(obj).val('');
8015 var id = $(obj).attr('id');
8016 var tags = val.split(delimiter[id]);
8017 for (var i = 0; i < tags.length; i++) {
8018 $(obj).addTag(tags[i], {
8019 focus: false,
8020 callback: false
8021 });
8022 }
8023 if (tags_callbacks[id] && tags_callbacks[id]['onChange']) {
8024 var f = tags_callbacks[id]['onChange'];
8025 f.call(obj, obj, tags[i]);
8026 }
8027 };
8028})(jQuery);
8029p.View.Bookmarklet = p.View.Bookmarklet || {};
8030p.View.Bookmarklet.Post = p.View.Base.extend({
8031 template: '<div class="overlay-content"> <div class="bookmarklet-head"> <img src="/media/pr0gramm.png" class="bookmarklet-logo"/> – Bild hochladen </div> <?js if( posted ) {?> <h2 class="main-message"> Fertig!<br/><br/> <a href="http://{CONFIG.HOST}/new/{item.id}" target="_blank">Gehe zum Post</a> </h2> <?js } else { ?> <?js if( error ) {?> <p class="warn"> <?js if( error === \'invalidType\' ) {?> Ungültiger Dateityp. Nur JPEG, PNG, GIF WebM erlaubt. <?js } else if( error === \'invalid\' ) {?> Bild ist ungültig, zu groß oder zu klein (min. 0,04 Megapixel, max. 16 Megapixel, max. 4MB Dateigröße – WebM nur mit VP8 codec, max. 180sek, keine Audiospur) <?js } else if( error === \'blacklisted\' ) {?> Bild oder Domain gesperrt. <?js } else if( error === \'internal\' ) {?> Interner Fehler bei der Verarbeitung. <?js } else if( error === \'download\' ) {?> Download fehlgeschlagen (4MB max). <?js } else if( error === \'missingData\' ) {?> Kein Bild oder URL angegeben. <?js } ?> </p> <?js } ?> <form id="upload-form"> <input type="hidden" name="imageUrl" value="{{imageUrl}}"/> <input type="hidden" name="siteUrl" value="{{siteUrl}}"/> <div id="upload-preview" style="display:block"> <?js if( params.type == \'video\' ) { ?> <video src="{{imageUrl}}" autoplay loop></video> <?js } else { ?> <img src="{{imageUrl}}"/> <?js } ?> </div> <div id="upload-progress"> <div class="progress-bar"> <div class="progress"></div> </div> </div> <div class="upload-tag-container"> <div class="sfw-status"> <label title="Safe for Work"> <input type="radio" name="sfwstatus" value="sfw"> sfw </label> <label title="Not Safe for Work"> <input type="radio" name="sfwstatus" value="nsfw"> nsfw </label> <label title="Not Safe for Life"> <input type="radio" name="sfwstatus" value="nsfl"> nsfl </label> </div> <h3>SFW Status und Tags</h3> <input type="text" class="upload-tagsinput" name="tags"/> </div> <div class="upload-similar"></div> <div> <input type="hidden" name="checkSimilar" value="1"/> <input type="submit" class="button" value="Bild Hochladen"/> </div> </form> <div class="post-rules"></div> <?js } ?> </div> ',
8032 requiresLogin: true,
8033 loginUrl: 'bm/login',
8034 data: {
8035 error: null,
8036 posted: false
8037 },
8038 load: function() {
8039 this.data.imageUrl = decodeURIComponent(this.data.params.imageUrl);
8040 this.data.siteUrl = decodeURIComponent(this.data.params.siteUrl);
8041 return true;
8042 },
8043 render: function() {
8044 this.parent();
8045 var that = this;
8046 var tags = this.$container.find('.upload-tagsinput');
8047 tags.tagsInput(CONFIG.TAGS_INPUT_SETTINGS);
8048 this.$container.find('input[name=sfwstatus]').change(function() {
8049 that.setSFWTags($(this));
8050 });
8051 this.$container.find('form').submit(this.submit.bind(this));
8052 this.rulesView = new p.View.Rules(this.$container.find('.post-rules'), this);
8053 this.rulesView.show();
8054 this.filterView = new p.View.Filter(this.$container.find('.post-filter'), this);
8055 this.filterView.show();
8056 },
8057 setSFWTags: function($radio) {
8058 var tags = this.$container.find('.upload-tagsinput');
8059 var status = $radio.val();
8060 tags.removeTag('nsfw');
8061 tags.removeTag('nsfl');
8062 if (status != 'sfw') {
8063 tags.addTag(status);
8064 }
8065 },
8066 submit: function(ev) {
8067 if (!this.$container.find('input[name=sfwstatus]:checked').length) {
8068 this.$container.find('.sfw-status').highlight(252, 136, 52, 1);
8069 return false;
8070 }
8071 p.api.post('items.post', ev.target, this.posted.bind(this), this.onError.bind(this));
8072 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
8073 this.showLoader();
8074 return false;
8075 },
8076 posted: function(response) {
8077 this.data.posted = !response.error;
8078 this.data.error = response.error;
8079 this.data.selfPosted = !!response.selfPosted;
8080 this.data.item = response.item;
8081 this.render();
8082 if (response.error == 'similar') {
8083 this.similarView = new p.View.UploadSimilar(this.$container.find('.upload-similar'), this);
8084 this.similarView.show(response.similar);
8085 this.$container.find('input[name=checkSimilar]').val(0);
8086 }
8087 },
8088 onError: function(response) {
8089 return p.setView(p.View.Overlay.Error, response.responseJSON);
8090 }
8091});
8092p.View.SecretSanta = p.View.Overlay || {};
8093p.View.SecretSanta = p.View.Base.extend({
8094 name: 'overlay-secretsanta',
8095 template: '<h1 class="pane-head secret-santa">wichteln 2016</h1> <div class="pane secret-santa"> <?js /* not allowed */ if( error === \'notAllowed\' ) { ?> <h2 class="warn">Entschuldige,<br/>Du darfst nicht teilnehmen :/</h2> <p> Am pr0gramm Wichteln dürfen nur nicht-Fliesentischbesitzer teilnehmen, die bereits vor dem 1. Nov 2016 schon mindestens 50 Kommentare oder 10 Uploads hatten. </p> <p>(<a href="{announcementPostLink}">Wichtelrelevante Posts</a>)</p> <?js /* saved */ } else if( saved || (phase == \'confirm\' && confirmed) ) { ?> <h3>Danke!</h3> <p> Am <span class="important">6. Dezember 2016</span> erhältst du von <a href="/user/wichtelb0t">@wichtelb0t</a> per privater Nachricht den Benutzernamen und die Anschrift des zu Beschenkenden. </p> <p>(<a href="{announcementPostLink}">Wichtelrelevante Posts</a>)</p> <?js /* confirm */ } else if( phase == \'confirm\' && !confirmed && isInList ) { ?> <form method="post" id="secret-santa-form"> <?js if( error ) { ?> <p class="warn">Da ist was schief gelaufen!</p> <?js } else { ?> <p class="warn"> Bitte bestätige nochmals Deine Teilnahme, damit wir wissen, dass Du es tatsächlich ernst meinst! </p> <?js } ?> <h3>Deine Anschrift</h3> <p> {{firstName}} {{lastName}}<br/> {{packstation}}<br/> {{street}} {{houseNumber}}<br/> {{zip}} {{city}}<br/> {{country}} </p> <div class="form-row" style="width: 400px; padding-top: 24px"> <h3>Teilnahmebedingungen</h3> <p> Deine Anschrift und Dein Benutzername wird einmalig, im Rahmen des pr0gramm-Wichtelns, an einen anderen zufällig ausgewählten Teilnehmer übermittelt. </p> <p> Du erhältst am <span class="important">6. Dezember 2016</span> per Privater Nachricht die Anschrift Deines Dir zugelosten Wichtels und verpflichtest Dich dazu, diesem Teilnehmer bis zum <span class="important">21. Dezember 2016</span> ein kleines Geschenk per Post zu schicken. </p> <p> Du verpflichtest Dich, die Anschrift des anderen Teilnehmers zu keinem anderen Zweck zu verwenden, nicht zu publizieren und keinen sonstigen Mist damit anzustellen. </p> <p> Wir haften nicht für Schäden oder Unannehmlichkeiten, die durch Geschenke Anderer entstehen. </p> <?js if( error === \'mustAcceptTos\' ) { ?> <p class="warn">Du musst die Teilnahmebedingungen akzeptieren!</p> <?js } ?> <input type="checkbox" name="tos" id="secret-santa-tos" value="1"/> <input type="hidden" name="confirm" value="1"/> <label for="secret-santa-tos" class="checkbox-label"> Ich akzeptiere die oben stehenden Teilnahmebedingungen und schwöre auf meine Mutter (optional auch auf den Koran) mich nicht wie ein Arschloch zu verhalten. </label> </div> <div class="form-row" style="padding-top: 24px"> <input type="submit" class="secret-santa-submit" value="Ja Mann, ich will wirklich mitmachen!"/> </div> </form> <?js /* running, show address */ } else if( phase == \'running\' && isInList && partner ) { ?> <h3>Dein Wichtelpartner</h3> <p><a href="/user/{{partner.user}}" class="user um8">{{partner.user}}</a></p> <p> {{partner.firstName}} {{partner.lastName}}<br/> {{partner.packstation}}<br/> {{partner.street}} {{partner.houseNumber}}<br/> {{partner.zip}} {{partner.city}}<br/> {{partner.country}} </p> <p> Bitte verschicke dein Wichtelgeschenk bis spätestens zum <span class="important">21. Dezember 2016</span>! Wer kein Geschenk verschickt, muss mit einer Sperrung rechnen sowie mit einem Ausschluss bei zukünftigen Aktionen. </p> <h3>Du bekommst ein Geschenk von</h3> <p><a href="/user/{{partner2.user}}" class="user um8">{{partner2.user}}</a></p> <h3>Ein paar Tipps zum Wichteln</h3> <ul> <li> Gib die Adresse Deines Wichtelpartners in <a href="https://www.google.de/maps/place/{{partner.street}},+{{partner.zip}}+{{partner.city}}">Google Maps</a> ein und überprüfe ob sie plausibel ist </li> <li> Mache ein paar Fotos Deines Geschenks, bevor Du es verschickst, falls irgendetwas schief läuft </li> <li> Einen OC-Post von Deinem Geschenk zu erstellen ist Aufgabe des Beschenkten – um die Überraschung zu erhalten, solltest Du es nicht selbst posten. Falls Dein Wichtelpartner dieser Aufgabe nicht nachkommt, kannst du später immernoch einen Post erstellen. </li> <li> Markiert euer Päckchen mit den <a href="/misc/wichtel_incoming.pdf">Wichtel-Paketaufklebern</a>, damit man schon vor dem Auspacken weiß, dass es sich um das Wichtelgeschenk handelt. </li> <li>An Packstationen kann nur via Post/DHL gesendet werden. Es können dort nur Pakete, Päckchen, Groß- und Maxibriefe angenommen werden.</li> <li>Bei Fragen zur Adresse eures Wichtelpartners, fragt ihn bitte selbst.</li> <li>Stuhle nicht ins Päckchen</li> <li>Hinweis: Dein hier angezeigter Wichtelpartner ERHÄLT ein Geschenk von dir. Er selbst beschenkt jemand anderen und du bekommst von einer dritten Person etwas.</li> </ul> <p> Falls es Probleme gibt – und damit meine ich nicht <em>“Ich weiß nicht was ich schenken soll!â€</em> – schreibt uns: <a href="#contact">/contact</a> </p> <?js /* closed */ } else if( (phase == \'confirm\' || phase == \'running\') && (!isInList || !partner) ) { ?> <h2 class="warn">Entschuldige,<br/>die Anmeldung ist geschlossen :/</h2> <p> Vielleicht kannst du ja nächstes Jahr mitmachen. </p> <p>(<a href="{announcementPostLink}">Wichtelrelevante Posts</a>)</p> <?js /* register */ } else if( phase == \'register\' ) { ?> <?js if( error ) { ?> <p class="warn">Da ist was schief gelaufen!</p> <?js } if( isInList ) { ?> <h3>Du nimmst am Wichteln teil!</h3> <p> Am <span class="important">6. Dezember 2016</span> erhältst du von <a href="/user/wichtelb0t">@wichtelb0t</a> per privater Nachricht die Anschrift des zu Beschenkenden. </p> <p> Hier kannst Du Deine Anschrift ändern oder Dich aus der Wichtelliste austragen, falls Du es dir doch anders überlegt hast. </p> <?js } else { ?> <p> <span class="important">Lies diese Seite KOMPLETT durch bevor wieder dumme vermeidbare Fragen kommen.</span> </p> <p> Beim Wichteln schickst Du einem zufällig ausgewählten Wichtel-Teilnehmer ein kleines Geschenk. Im Gegenzug erhältst Du von einem anderen zufällig ermittelten Teilnehmer selbst ein Geschenk. Um es nochmal für die Langsamen klar zu stellen, <span class="important">du beschenkst nicht die gleiche Person die dich beschenkt!</span> </p> <p> Die Geschenke können irgendwas selbst Gebasteltes oder Gemaltes sein, oder einfach eine gekaufte Kleinigkeit. Wir empfehlen so um die 15€ für das Geschenk auszugeben. Wer Dinge verschickt um anderen zu schaden oder gar nichts versendet muss mit einer Sperrung seines Accounts rechnen. Genauso wenn jemand verbotene Gegenstände versendet. </p> <p> Wenn du am pr0gramm Wichteln teilnehmen möchtest, trage einfach unten deine Anschrift ein, die wir dann einem einzelnen anderen Teilnehmer zulosen. </p> <p> Deine Anschrift wird von uns zu keinem anderen Zweck verwendet und wird nach Ende des Wichtelns restlos von unseren Servern gelöscht. </p> <p> Alle <span class="important">Packstation Nutzer</span> können in das Postnummer Feld ihre paket.de Nummer eintragen. Als Straße "Packstation" eintragen und als Hausnummer die Nummer der Packstation angeben. Vorsicht die Zustellrate bei Packstationen ist nicht besonders gut, also nachher nicht jammern wenn nichts ankam. </p> <p> Alle <span class="important">Aluhutträger</span> können beim Namen den Vornamen abkürzen. Also z.B. "L. Simpson". Postlagernd funktioniert nicht, wer so seine Adresse eingibt wird aussortiert. </p> <?js } ?> <p>(<a href="{announcementPostLink}">Wichtelrelevante Posts</a>)</p> <form method="post" id="secret-santa-form"> <h3>Deine Anschrift</h3> <?js if( error === \'incomplete\' ) { ?> <p class="warn">Gib Deine vollständige Anschrift an!</p> <?js } ?> <div class="form-row"> <input type="text" name="firstName" placeholder="Vorname" value="{{firstName}}" style="width:198px"/> <input type="text" name="lastName" placeholder="Nachname" value="{{lastName}}" style="width:198px"/> </div> <div class="form-row"> <input type="text" name="packstation" placeholder="Postnummer oder Adresszusatz (optional)" value="{{packstation}}" style="width:400px"/> </div> <div class="form-row"> <input type="text" name="street" placeholder="Straße" value="{{street}}" style="width:348px"/> <input type="text" name="houseNumber" placeholder="Nr" value="{{houseNumber}}" style="width:50px"/> </div> <div class="form-row"> <input type="text" class="number" name="zip" placeholder="PLZ" value="{{zip}}" style="width:64px"/> <input type="text" name="city" placeholder="Ort" value="{{city}}" style="width:334px"/> </div> <div class="form-row"> <select name="country" class="secret-santa-country"> <option <?js print(country===\'Deutschland\'?\'selected\':\'\');?> value="Deutschland">Deutschland</option> <option <?js print(country===\'Österreich\'?\'selected\':\'\');?> value="Österreich">Österreich</option> <option <?js print(country===\'Schweiz\'?\'selected\':\'\');?> value="Schweiz">Schweiz</option> </select> <p> (Ihr wichtelt nur mit euren eigenen Landsmännern. Österreicher werden nur mit anderen Österreichern wichteln, Schweizer nur mit anderen Schweizern.) </p> </div> <div class="form-row"> <p> <input type="checkbox" name="email" id="email" value="1" <?js print(email==1?\'checked\':\'\');?>/> <label for="email" class="checkbox-label">Ja ich möchte außerdem an meine hinterlegte E-Mail Adresse an das nochmalige Bestätigen der Teilnahme sowie das eigentliche Versenden erinnert werden (optional).</label> </p> </div> <div class="form-row" style="width: 400px; padding-top: 24px"> <h3>Teilnahmebedingungen</h3> <p> Deine Anschrift und Dein Benutzername wird einmalig, im Rahmen des pr0gramm-Wichtelns, an einen anderen zufällig ausgewählten Teilnehmer übermittelt. </p> <p> In den nächsten Tagen wirst du aufgefordert werden deine <span class="important">Teilnahme nochmals zu bestätigen.</span> Dies erscheint uns aufgrund der Unzuverlässigkeit einiger weniger Teilnehmer als nötig. </p> <p> Du erhältst am <span class="important">6. Dezember 2016</span> per privater Nachricht die Anschrift Deines Dir zugelosten Wichtels und verpflichtest Dich dazu, diesem Teilnehmer bis zum <span class="important">21. Dezember 2016</span> ein kleines Geschenk per Post zu schicken. </p> <p> Du verpflichtest Dich, die Anschrift des anderen Teilnehmers zu keinem anderen Zweck zu verwenden, nicht zu publizieren und keinen sonstigen Mist damit anzustellen. </p> <p> Wir haften nicht für Schäden oder Unannehmlichkeiten, die durch Geschenke Anderer entstehen. </p> <?js if( error === \'mustAcceptTos\' ) { ?> <p class="warn">Du musst die Teilnahmebedingungen akzeptieren!</p> <?js } ?> <input <?js print(isInList?\'checked\':\'\');?> type="checkbox" name="tos" id="secret-santa-tos" value="1"/> <label for="secret-santa-tos" class="checkbox-label"> Ich akzeptiere die oben stehenden Teilnahmebedingungen und schwöre auf meine Mutter (optional auch auf den Koran) mich nicht wie ein Arschloch zu verhalten. </label> </div> <div class="form-row" style="padding-top: 24px"> <?js if( isInList ) { ?> <input type="submit" class="secret-santa-submit" value="Änderungen Speichern"/> <input type="button" class="secret-santa-delete cancel" value="Aus der Liste löschen"/> <?js } else { ?> <input type="submit" class="secret-santa-submit" value="Am Wichteln teilnehmen"/> <?js } ?> </div> </form> <?js } ?> </div>',
8096 data: {
8097 phase: 'register',
8098 error: null,
8099 saved: false,
8100 isInList: false,
8101 firstName: '',
8102 lastName: '',
8103 street: '',
8104 houseNumber: '',
8105 packstation: '',
8106 zip: '',
8107 city: '',
8108 country: '',
8109 confirmed: 0,
8110 email: 0,
8111 announcementPostLink: '#top/1612974'
8112 },
8113 animationInterval: 0,
8114 load: function() {
8115 p.api.get('secretsanta.info', {}, this.loaded.bind(this), this.error.bind(this));
8116 if (this.data.params.iap) {
8117 $('#head').hide();
8118 }
8119 return false;
8120 },
8121 remove: function() {
8122 clearInterval(this.animationInterval);
8123 },
8124 error: function() {
8125 this.loaded({
8126 error: 'notAllowed'
8127 });
8128 },
8129 loaded: function(response) {
8130 this.data.error = response.error;
8131 if (response.entry) {
8132 this.data = p.merge(this.data, response.entry);
8133 this.data.isInList = true;
8134 }
8135 this.data.partner = response.partner;
8136 this.data.partner2 = response.partner2;
8137 this.data.phase = response.phase;
8138 this.render();
8139 var snowDivHTML = "";
8140 for (var i = 0; i < 7; i++) {
8141 snowDivHTML += '<div class="snowflake">*</div>';
8142 }
8143 var $snowDivs = $(snowDivHTML);
8144 this.$container.append($snowDivs);
8145 var w = this.$container.width(),
8146 h = this.$container.height();
8147 this.flakes = [];
8148 for (var i = 0; i < $snowDivs.length; i++) {
8149 var div = $snowDivs[i];
8150 var x = w * Math.random(),
8151 y = h * Math.random();
8152 div.style.left = x + 'px';
8153 div.style.top = y + 'px';
8154 this.flakes.push({
8155 x: x,
8156 y: y,
8157 div: div,
8158 s: 0.5 + Math.random() * 0.75
8159 });
8160 }
8161 this.animationInterval = setInterval(this.animate.bind(this), 16);
8162 },
8163 animate: function() {
8164 var mh = this.$container.height() - 34;
8165 for (var i = 0; i < this.flakes.length; i++) {
8166 var flake = this.flakes[i];
8167 flake.y += flake.s;
8168 if (flake.y > mh) {
8169 flake.y = 0;
8170 }
8171 var x = flake.x + Math.sin((flake.y + i * 37) / 100) * 50;
8172 flake.div.style.top = flake.y + 'px';
8173 flake.div.style.left = x + 'px';
8174 }
8175 },
8176 render: function() {
8177 this.parent();
8178 this.$container.find('#secret-santa-form').submit(this.submit.bind(this));
8179 this.$container.find('.secret-santa-delete').fastclick(this.removeList.bind(this));
8180 },
8181 submit: function(ev) {
8182 if (this.data.phase == 'register ') {
8183 this.data.firstName = this.$container.find('input[name=firstName]').val();
8184 this.data.lastName = this.$container.find('input[name=lastName]').val();
8185 this.data.street = this.$container.find('input[name=street]').val();
8186 this.data.houseNumber = this.$container.find('input[name=houseNumber]').val();
8187 this.data.packstation = this.$container.find('input[name=packstation]').val();
8188 this.data.zip = this.$container.find('input[name=zip]').val();
8189 this.data.city = this.$container.find('input[name=city]').val();
8190 this.data.country = this.$container.find('select[name=country]').val();
8191 this.data.email = this.$container.find('input[name=email]').val();
8192 }
8193 p.api.post('secretsanta.save', ev.target, this.posted.bind(this));
8194 this.$container.find('input[type=submit]').attr('disabled', 'disabled');
8195 this.showLoader();
8196 return false;
8197 },
8198 removeList: function(response) {
8199 if (confirm('Willst Du Dich wirklich aus der Wichtelliste löschen?')) {
8200 p.api.post('secretsanta.remove', {}, p.reload);
8201 }
8202 },
8203 posted: function(response) {
8204 this.data.error = response.error;
8205 this.data.saved = response.saved;
8206 this.render();
8207 }
8208});
8209p.api = new p.ServerAPI(CONFIG.API.ENDPOINT);
8210p.user = new p.User();
8211p.hotkeys = new p.Hotkeys($(document));
8212p.mainView = null;
8213if (p.getLocation().match(/^newest/)) {
8214 document.location = '/';
8215}
8216if (p.getLocation().match(/^bm\//)) {
8217 p.mainView = new p.View.Bookmarklet.Layout('body');
8218 p.addRoute(p.View.Bookmarklet.Login, 'bm/login');
8219 p.addRoute(p.View.Bookmarklet.Post, 'bm/post/<type>/<siteUrl>/<imageUrl>');
8220} else {
8221 p.mainView = new p.View.Layout('body');
8222 p.addRoute(p.View.Stream.Main, '');
8223 p.addRoute(p.View.Stream.Main, '<tab:top|new|stalk>');
8224 p.addRoute(p.View.Stream.Main, '<tab:top|new|stalk>/<itemId:d>');
8225 p.addRoute(p.View.Stream.Main, '<tab:top|new>/<tags>');
8226 p.addRoute(p.View.Stream.Main, '<tab:top|new>/<tags>/<itemId:d>');
8227 p.addRoute(p.View.Stream.Main, 'user/<userName>/<userTab:likes|uploads>');
8228 p.addRoute(p.View.Stream.Main, 'user/<userName>/<userTab:likes|uploads>/<itemId:d>');
8229 p.addRoute(p.View.Stream.Main, 'user/<userName>/<userTab:likes|uploads>/<tags>');
8230 p.addRoute(p.View.Stream.Main, 'user/<userName>/<userTab:likes|uploads>/<tags>/<itemId:d>');
8231 p.addRoute(p.View.User, 'user/<name>');
8232 p.addRoute(p.View.User.Comments, 'user/<name>/comments/<search:after|before>/<timestamp:d>');
8233 p.addRoute(p.View.Inbox, 'inbox/<tab:unread|all|messages>');
8234 p.addRoute(p.View.Validate, 'user/<name>/validate/<token>');
8235 p.addRoute(p.View.ResetPassword, 'user/<name>/resetpass/<token>');
8236 p.addRoute(p.View.FollowList, 'stalk/list/<sort:stalk-date|post-date>');
8237 p.addRoute(p.View.Settings, 'settings/account/mail/<token>');
8238 p.addRoute(p.View.Settings, 'settings/<tab:bookmarklet|site|account|invites>');
8239 p.addRoute(p.View.Upload, 'upload');
8240 p.addRoute(p.View.Contact, 'contact');
8241 p.addRoute(p.View.RegisterInvite, 'register/<token>');
8242 p.addRoute(p.View.RedeemThanks, 'redeem/thanks');
8243 p.addRoute(p.View.RedeemCode, 'redeem/<token>');
8244 p.addRoute(p.View.BuyCode.PaypalThanks, 'pr0mium/thanks');
8245 p.addRoute(p.View.BuyCode.Products, 'pr0mium');
8246 p.addRoute(p.View.BuyCode.Products, 'pr0mium/<iap:iap>');
8247 p.addRoute(p.View.RedeemShopCoupon, 'code');
8248 p.addRoute(p.View.FAQ, 'faq');
8249 p.addRoute(p.View.Imprint, 'imprint');
8250 p.addRoute(p.View.TOS, 'tos');
8251 p.addRoute(p.View.Overlay.ResetPassword, 'resetpassword');
8252 p.addRoute(p.View.SecretSanta, 'secret-santa');
8253 p.addRoute(p.View.SecretSanta, 'secret-santa/<iap:iap>');
8254}
8255p.addRoute(p.View.Error404, '*');
8256p.mainView.show();
8257p.start('#main-view');
8258if (CONFIG.ANALYTICS.ENABLED) {
8259 (function(i, s, o, g, r, a, m) {
8260 i['GoogleAnalyticsObject'] = r;
8261 i[r] = i[r] || function() {
8262 (i[r].q = i[r].q || []).push(arguments)
8263 }, i[r].l = 1 * new Date();
8264 a = s.createElement(o), m = s.getElementsByTagName('head')[0];
8265 a.async = 1;
8266 a.src = g;
8267 m.appendChild(a)
8268 })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
8269 ga('create', CONFIG.ANALYTICS.ACCOUNT, 'auto');
8270 ga('set', 'dimension1', (p.user.id ? 'yes' : 'no'));
8271 ga('set', 'dimension2', p.user.flagsName);
8272 ga('send', 'pageview', {
8273 page: p.getLocation()
8274 });
8275}