PluginProbe ʕ •ᴥ•ʔ
Event Tickets with Ticket Scanner / 2.7.4
Event Tickets with Ticket Scanner v2.7.4
3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.4 trunk 2.6.0 2.7.0 2.7.1 2.7.10 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.10 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 2.9.8 2.9.9 3.0.0 3.0.1 3.0.2 3.0.3
event-tickets-with-ticket-scanner / ticket_events.js
event-tickets-with-ticket-scanner Last commit date
3rd 11 months ago css 11 months ago img 11 months ago languages 11 months ago ticket 11 months ago vendors 11 months ago SASO_EVENTTICKETS.php 11 months ago backend.js 11 months ago changelog.txt 11 months ago db.php 11 months ago index.php 11 months ago init_file.php 11 months ago js_seatingplan.js 11 months ago order_details.js 11 months ago readme.txt 11 months ago saso-eventtickets-validator.js 11 months ago sasoEventtickets_AdminSettings.php 11 months ago sasoEventtickets_Authtoken.php 11 months ago sasoEventtickets_Base.php 11 months ago sasoEventtickets_Core.php 11 months ago sasoEventtickets_Frontend.php 11 months ago sasoEventtickets_Messenger.php 11 months ago sasoEventtickets_Options.php 11 months ago sasoEventtickets_PDF.php 11 months ago sasoEventtickets_Ticket.php 11 months ago sasoEventtickets_TicketBadge.php 11 months ago sasoEventtickets_TicketDesigner.php 11 months ago sasoEventtickets_TicketQR.php 11 months ago ticket_events.js 11 months ago ticket_scanner.js 11 months ago validator.js 11 months ago wc_backend.js 11 months ago wc_frontend.js 11 months ago woocommerce-hooks.php 11 months ago
ticket_events.js
494 lines
1 jQuery(document).ready(()=>{
2 const { __, _x, _n, sprintf } = wp.i18n;
3 let system = {code:0, nonce:'', data:null, redeemed_successfully:false, img_pfad:'', last_scanned_ticket:{code:'', timestamp:0, auto_redeem:false}};
4 let myAjax;
5 if (typeof IS_PRETTY_PERMALINK_ACTIVATED === "undefined") {
6 IS_PRETTY_PERMALINK_ACTIVATED = false;
7 }
8 let DIV;
9
10 if (typeof Ajax_ticket_events_sasoEventtickets === "undefined") {
11 myAjax = {
12 url: '/admin-ajax.php'
13 };
14 system.nonce = NONCE;
15 } else {
16 myAjax = Ajax_ticket_events_sasoEventtickets;
17 system.nonce = myAjax.nonce;
18 }
19 //console.log(myAjax);
20
21 function intval(v) {
22 let retv = parseInt(v,10);
23 if (isNaN(retv)) retv = 0;
24 return retv;
25 }
26
27 function toBool(v) {
28 if (v == "1") return true;
29 if (v == 1) return true;
30 if (v.toLowerCase() == "yes") return true;
31 return v == true;
32 }
33
34 function addStyleCode(content, media) {
35 let c = document.createElement('style');
36 if (media) c.setAttribute("media", media);
37 c.innerHTML = content;
38 document.getElementsByTagName("head")[0].appendChild(c);
39 }
40
41 function addMetaTag(name, content) {
42 let head = document.getElementsByTagName("head")[0];
43 let metaTags = head.getElementsByTagName("meta");
44 let contains = false;
45 for (let i=0;i<metaTags.length;i++) {
46 let tag = metaTags[i];
47 if (tag.name == name) {
48 tag.content = content;
49 contains = true;
50 break;
51 }
52 }
53 if (!contains) {
54 let metaTag = document.createElement("meta");
55 metaTag.name = name;
56 metaTag.content = content;
57 head.appendChild(metaTag);
58 }
59 }
60 function _getURLAndDateForAjax(action, myData, pcbf) {
61 let _data = {};
62 _data.action = action;
63 _data.t = new Date().getTime();
64 //if (system.nonce != '') _data._wpnonce = system.nonce;
65 if (system.nonce != '') _data.nonce = system.nonce;
66 pcbf && pcbf();
67 //if (myData) for(var key in myData) _data['data['+key+']'] = myData[key];
68 if (myData) for(var key in myData) _data[key] = myData[key];
69 if (ticket_scanner_operating_option && ticket_scanner_operating_option.auth && ticket_scanner_operating_option.auth.code && ticket_scanner_operating_option.auth.code != "") {
70 let key = "auth";
71 if (Ajax_sasoEventtickets && Ajax_sasoEventtickets._params && Ajax_sasoEventtickets._params.auth) key = Ajax_sasoEventtickets._params.auth;
72 _data[key] = ticket_scanner_operating_option.auth.code;
73 }
74 if (system.nonce != '') {
75 $.ajaxSetup({
76 beforeSend: function(xhr) {
77 xhr.setRequestHeader('X-WP-Nonce', system.nonce);
78 },
79 });
80 }
81
82 let url = myAjax.url;
83 if (IS_PRETTY_PERMALINK_ACTIVATED == false) {
84 url = myAjax.non_pretty_permalink_url;
85 }
86 url += action;
87 return {url:url, data:_data};
88 }
89 function _makeGet(action, myData, cbf, ecbf, pcbf) {
90 let call_data = _getURLAndDateForAjax(action, myData, pcbf);
91 //console.log(call_data);
92 $.get( call_data.url, call_data.data, response=>{
93 if (typeof response == "string") {
94 response = JSON.parse(response);
95 }
96 if (response && response.data && response.data.nonce) system.nonce = response.data.nonce;
97 if (!response.success) {
98 if (ecbf) ecbf(response);
99 else {
100 let msg = (typeof response.data !== "undefined" && response.data.status ? response.data.status : '') + " " + (response.data.message ? response.data.message : '');
101 renderFatalError(msg.trim());
102 }
103 } else {
104 cbf && cbf(response.data);
105 }
106 }, "json").always(jqXHR=>{
107 if(jqXHR.status == 401 || jqXHR.status == 403) {
108 renderFatalError(__("Access rights missing. Please login first.", 'event-tickets-with-ticket-scanner') + " "+(jqXHR.responseJSON && jqXHR.responseJSON.message ? jqXHR.responseJSON.message : '') );
109 }
110 if(jqXHR.status == 400) {
111 renderFatalError(jqXHR.responseJSON.message);
112 }
113 });
114 }
115 function _makePost(action, myData, cbf, ecbf, pcbf) {
116 let call_data = _getURLAndDateForAjax(action, myData, pcbf);
117 $.post( call_data.url, call_data.data, response=>{
118 if (typeof response == "string") {
119 response = JSON.parse(response);
120 }
121 if (response && response.data && response.data.nonce) system.nonce = response.data.nonce;
122 if (!response.success) {
123 if (ecbf) ecbf(response);
124 else {
125 let msg = (response.data.status ? response.data.status : '') + " " + (response.data.message ? response.data.message : '');
126 renderFatalError(msg.trim());
127 }
128 } else {
129 cbf && cbf(response.data);
130 }
131 }, "json").always(jqXHR=>{
132 if(jqXHR.status == 401 || jqXHR.status == 403) {
133 renderFatalError(__("Access rights missing. Please login first.", 'event-tickets-with-ticket-scanner') + " " + (jqXHR.responseJSON && jqXHR.responseJSON.message ? jqXHR.responseJSON.message : '') );
134 }
135 if(jqXHR.status == 400) {
136 renderFatalError(jqXHR.responseJSON.message);
137 }
138 });
139 }
140
141 function _getSpinnerHTML() {
142 return '<span class="lds-dual-ring"></span>';
143 }
144
145 function _storeValue(name, wert, days) {
146 if (window.JAVAJSBridge && window.JAVAJSBridge.setItem) window.JAVAJSBridge.setItem(name, wert);
147 else setCookie(name, wert, days);
148 }
149 function _loadValue(name) {
150 if (window.JAVAJSBridge && window.JAVAJSBridge.getItem) return window.JAVAJSBridge.getItem(name);
151 return getCookie(name);
152 }
153 function setCookie(cname, cvalue, exdays) {
154 var d = new Date();
155 if (!exdays) exdays = 30;
156 d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
157 var expires = "expires="+d.toUTCString();
158 document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
159 }
160 function getCookie(cname) {
161 var name = cname + "=";
162 var ca = document.cookie.split(';');
163 for(var i = 0; i < ca.length; i++) {
164 var c = ca[i];
165 while (c.charAt(0) === ' ') {
166 c = c.substring(1);
167 }
168 if (c.indexOf(name) === 0) {
169 return c.substring(name.length, c.length);
170 }
171 }
172 return "";
173 }
174 function makeDateFromString(timestring, timezone_id) {
175 let d = new Date(timestring);
176 return new Date(d.toLocaleString('en', {timeZone: timezone_id}));
177 }
178 function makeDate(timestamp, timezone_id) {
179 let d = new Date();
180 d.setTime(timestamp);
181 return new Date(d.toLocaleString('en', {timeZone: timezone_id}));
182 }
183 function time(timezone_id, timestamp) {
184 let d = new Date();
185 if (timestamp) {
186 d.setTime(timestamp);
187 }
188 if (timezone_id && timezone_id.indexOf("/") > 0) {
189 d = new Date(d.toLocaleString('en', {timeZone: timezone_id}));
190 }
191 return parseInt(d.getTime() / 1000);
192 }
193 function parseDate(str){
194 if (!str) return null;
195 let d = new Date(str.split(' ')[0].replace(/-/g,"/"));
196 return d;
197 }
198 function parseDateAndText(str, format) {
199 return Date2Text(parseDate(str).getTime(), format);
200 }
201 function DateTime2Text(millisek) {
202 return Date2Text(millisek, myAjax.format_datetime ? myAjax.format_datetime : "d.m.Y H:i");
203 }
204 function Date2Text(millisek, format, timezone_id) {
205 if (!millisek)
206 millisek = time(timezone_id);
207 var d = new Date(millisek);
208 if (!format) {
209 //format = system.format_date ? system.format_date : "%d.%m.%Y";
210 format = myAjax.format_date ? myAjax.format_date : "d.m.Y";
211 //format = "%d.%m.%Y %H:%i";
212 }
213 var tage = [
214 _x('Sun', 'cal', 'event-tickets-with-ticket-scanner'),
215 _x('Mon', 'cal', 'event-tickets-with-ticket-scanner'),
216 _x('Tue', 'cal', 'event-tickets-with-ticket-scanner'),
217 _x('Wed', 'cal', 'event-tickets-with-ticket-scanner'),
218 _x('Thu', 'cal', 'event-tickets-with-ticket-scanner'),
219 _x('Fri', 'cal', 'event-tickets-with-ticket-scanner'),
220 _x('Sat', 'cal', 'event-tickets-with-ticket-scanner')
221 ];
222 var monate = [
223 _x('Jan', 'cal', 'event-tickets-with-ticket-scanner'),
224 _x('Feb', 'cal', 'event-tickets-with-ticket-scanner'),
225 _x('Mar', 'cal', 'event-tickets-with-ticket-scanner'),
226 _x('Apr', 'cal', 'event-tickets-with-ticket-scanner'),
227 _x('May', 'cal', 'event-tickets-with-ticket-scanner'),
228 _x('Jun', 'cal', 'event-tickets-with-ticket-scanner'),
229 _x('Jul', 'cal', 'event-tickets-with-ticket-scanner'),
230 _x('Aug', 'cal', 'event-tickets-with-ticket-scanner'),
231 _x('Sep', 'cal', 'event-tickets-with-ticket-scanner'),
232 _x('Oct', 'cal', 'event-tickets-with-ticket-scanner'),
233 _x('Nov', 'cal', 'event-tickets-with-ticket-scanner'),
234 _x('Dec', 'cal', 'event-tickets-with-ticket-scanner')
235 ];
236 var formate = {'d':d.getDate()<10?'0'+d.getDate():d.getDate(),
237 'j':d.getDate(),'D':tage[d.getDay()],'w':d.getDate(),'m':d.getMonth()+1<10?'0'+(d.getMonth()+1):d.getMonth()+1,'M':monate[d.getMonth()],
238 'n':d.getMonth()+1,'Y':d.getFullYear(),'y':d.getYear()>100?d.getYear().toString().substring(d.getYear().toString().length-2):d.getYear(),
239 'H':d.getHours()<10?'0'+d.getHours():d.getHours(),'h':d.getHours()>12?d.getHours()-12:d.getHours(),
240 'i':d.getMinutes()<10?'0'+d.getMinutes():d.getMinutes(),'s':d.getSeconds()<10?'0'+d.getSeconds():d.getSeconds()
241 };
242 for (var akey in formate) {
243 //var rg = new RegExp('%'+akey, "g");
244 var rg = new RegExp(akey, "g");
245 format = format.replace(rg, formate[akey]);
246 }
247 return format;
248 }
249 function renderInfoBox(title, content) {
250 let _options = {
251 title: title,
252 modal: true,
253 minWidth: 400,
254 minHeight: 200,
255 buttons: [{text:_x('Ok', 'label', 'event-tickets-with-ticket-scanner'), click:function(){
256 $(this).dialog("close");
257 $(this).html("");
258 clearAreas();
259 $('#ticket_info').html(content);
260 $('#reader').html("");
261 }}]
262 };
263 if (typeof content !== "string") content = JSON.stringify(content);
264 let dlg = $('<div/>').html(content);
265 dlg.dialog(_options);
266 return dlg;
267 }
268 function renderFatalError(content) {
269 return renderInfoBox('Error', content);
270 }
271 function basics_ermittelURLParameter() {
272 var parawerte = {};
273 var teile;
274 if (window.location.search !== "") {
275 teile = window.location.search.substring(1).split("&");
276 for (var a=0;a<teile.length;a++)
277 {
278 var pos = teile[a].indexOf("=");
279 if (pos < 0) {
280 parawerte[teile[a]] = true;
281 } else {
282 var key = teile[a].substring(0,pos);
283 parawerte[key] = decodeURIComponent(teile[a].substring(pos+1));
284 }
285 }
286 }
287 return parawerte;
288 }
289
290 function renderEventsAsList() {
291 let events = myAjax.events;
292 let list_infos = myAjax.list_infos;
293 let browserLanguage = navigator.language || navigator.userLanguage;
294 let language = browserLanguage.split('-')[0];
295
296 // iterate over the months
297 let months_to_show = list_infos.months_to_show ? list_infos.months_to_show : 1;
298 let html = '<div class="sasoEventTicketsValidator_list">';
299 for (let i = 0; i < months_to_show; i++) {
300 let monthHtml = renderEventsForMonth(i)
301 html += monthHtml;
302 }
303 html += '</div>';
304
305 let ret = $(html);
306 // find all events and add click event
307 ret.find('.sasoEventTicketsValidator_event-info-btn').click(event=>{
308 event.preventDefault();
309 //let div = $(event.target).closest('.sasoEventTicketsValidator_event');
310 let elem = $(event.target).closest('.sasoEventTicketsValidator_list_event');
311 let eventId = elem.data('event-id');
312 // find url to the event
313 let url = '';
314 events.forEach(event=>{
315 if (event.ID == eventId) {
316 url = event.product.url;
317 url += '?event_id=' + eventId;
318 url += '&event_date=' + elem.data('event-date');
319 url += '&cal_date=' + elem.data('cal-date');
320 if (event.dates.ticket_start_date && event.dates.ticket_start_date !== '') {
321 //url += '&date=' + event.dates.ticket_start_date;
322 }
323 }
324 });
325 if (url !== '') {
326 window.location.href = url;
327 }
328 });
329
330 return ret;
331
332 function renderEventsForMonth(monthOffset) {
333 // calculate the month to show with the offset
334 let d = new Date(); // actual date
335 d.setMonth(d.getMonth() + monthOffset); // add the offset
336 let month = d.getMonth();
337 let year = d.getFullYear();
338 let daysInMonth = new Date(year, month + 1, 0).getDate();
339 //let firstDay = new Date(year, month, 1).getDay();
340 let monthName = new Date(year, month, 1).toLocaleString(language, {month: 'long'});
341
342 let html = '<div class="sasoEventTicketsValidator_list_events" data-month="' + month + '" data-year="' + year + '">';
343 html += '<div class="sasoEventTicketsValidator_list_events-header">' + monthName + ' ' + year + '</div>';
344 // render the actual month per day
345 for (let day = 1; day <= daysInMonth; day++) {
346 let eventHtml = '';
347 // date object for the current day
348 let date_today = new Date(year, month, day);
349 // get the name of the day
350 let dayName = date_today.toLocaleString(language, {weekday: 'long'});
351
352 events.forEach(event => {
353 let eventStartDate = date_today;
354 let eventEndDate = date_today;
355 if (event.dates.is_date_set) {
356 eventStartDate = new Date(intval(event.dates.ticket_start_p_year), intval(event.dates.ticket_start_p_month)-1, intval(event.dates.ticket_start_p_date));
357 }
358 if (event.dates.is_end_date_set) {
359 eventEndDate = new Date(intval(event.dates.ticket_end_p_year), intval(event.dates.ticket_end_p_month)-1, intval(event.dates.ticket_end_p_date));
360 }
361
362 let show_event = false;
363 if (intval(event.dates.ticket_start_p_date) == date_today.getDate() && intval(event.dates.ticket_start_p_month)-1 == date_today.getMonth() && intval(event.dates.ticket_start_p_year) == date_today.getFullYear()) {
364 show_event = true;
365 }
366 if (show_event == false) {
367 if (event.dates.is_end_date_set == true) {
368 // if end date is in the future and the start date is in the past
369 if (eventStartDate.getTime() <= date_today.getTime() && eventEndDate.getTime() >= date_today.getTime()) {
370 show_event = true;
371 }
372 }
373 }
374 if (show_event == false && event.dates.is_date_set == false && event.dates.is_end_date_set == false) { // daily events
375 show_event = true;
376 }
377 if (show_event == true && event.dates.daychooser_exclude_wdays && event.dates.daychooser_exclude_wdays.length > 0 && event.dates.daychooser_exclude_wdays.includes(date_today.getDay().toString())) {
378 show_event = false;
379 }
380 if (show_event == true && event.dates.daychooser_exclude_dates && event.dates.daychooser_exclude_dates.length > 0) {
381 event.dates.daychooser_exclude_dates.forEach(exclude_date => {
382 let exclude_date_obj = new Date(exclude_date);
383 if (exclude_date_obj == date_today) {
384 show_event = false;
385 }
386 });
387 }
388
389 if (show_event) {
390 eventHtml += '<div class="sasoEventTicketsValidator_list_event" data-event-id="' + event.ID + '" data-cal-date="' + date_today.getTime() + '" data-event-date="' + eventStartDate.getTime() + '">';
391 eventHtml += '<div class="sasoEventTicketsValidator_event-title">' + event.product.title + '</div>';
392 if (event.event.location && event.event.location !== '') {
393 eventHtml += '<div class="sasoEventTicketsValidator_event-location">' + event.event.location_label + ' ' +event.event.location + '</div>';
394 }
395
396 let event_date = Date2Text(eventStartDate.getTime()) + (eventStartDate == eventEndDate ? '' : ' - ' + Date2Text(eventEndDate.getTime()));
397
398 eventHtml += '<div class="sasoEventTicketsValidator_event-date">' + event_date + '</div>';
399 if (event.dates.ticket_start_time && event.dates.ticket_start_time !== '') {
400 let dd = new Date(event.dates.ticket_start_date+' '+event.dates.ticket_start_time);
401 let start_time = Date2Text(dd.getTime(), myAjax.format_time ? myAjax.format_time : "H:i");
402 eventHtml += '<div class="sasoEventTicketsValidator_event-time">' + start_time;
403 if (event.dates.ticket_end_time && event.dates.ticket_end_time !== '') {
404 let de = new Date(event.dates.ticket_end_date+' '+event.dates.ticket_end_time);
405 let end_time = Date2Text(de.getTime(), myAjax.format_time ? myAjax.format_time : "H:i");
406 eventHtml += ' - ' + end_time;
407 }
408 eventHtml += '</div>';
409 }
410 if (event.event.description && event.event.description !== '') {
411 eventHtml += '<div class="sasoEventTicketsValidator_event-description">' + event.event.description + '</div>';
412 }
413 // add info button aligned to the right
414 eventHtml += '<div class="sasoEventTicketsValidator_event-info"><button class="sasoEventTicketsValidator_event-info-btn">' + __('Info', 'event-tickets-with-ticket-scanner') + '</button></div>';
415 eventHtml += '</div>';
416 }
417 });
418 let is_today = date_today.toDateString() === new Date().toDateString();
419 html += '<div class="sasoEventTicketsValidator_list_calendar-row'+(is_today ? '-today' : '')+'">'
420 + '<div class="sasoEventTicketsValidator_list_calendar-header'+(is_today ? '-today' : '')+'">' + Date2Text(date_today.getTime()) + ' - ' + dayName + '</div>'
421 + (eventHtml == '' ? '-' : eventHtml)
422 + '</div>';
423 }
424
425 html += '</div>';
426 return html;
427 }
428 }
429
430 function renderEvents() { // todo: render events as calendar - for now it looks ugly and the event information is not displayed correctly
431 let events = myAjax.events;
432 let d = new Date();
433 let month = d.getMonth();
434 let year = d.getFullYear();
435 let daysInMonth = new Date(year, month + 1, 0).getDate();
436 let firstDay = new Date(year, month, 1).getDay();
437
438 let html = '<div class="sasoEventTicketsValidator_calendar">';
439 html += '<div class="sasoEventTicketsValidator_calendar-header">';
440 html += '<div class="sasoEventTicketsValidator_calendar-header-month">' + (month + 1) + '/' + year + '</div>';
441 html += '</div>';
442 html += '<div class="sasoEventTicketsValidator_calendar-body">';
443 html += '<div class="sasoEventTicketsValidator_calendar-row">';
444 let daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
445 for (let i = 0; i < 7; i++) {
446 html += '<div class="sasoEventTicketsValidator_calendar-cell sasoEventTicketsValidator_calendar-day">' + daysOfWeek[i] + '</div>';
447 }
448 html += '</div>';
449 html += '<div class="sasoEventTicketsValidator_calendar-row">';
450 for (let i = 0; i < firstDay; i++) {
451 html += '<div class="sasoEventTicketsValidator_calendar-cell"></div>';
452 }
453 for (let day = 1; day <= daysInMonth; day++) {
454 let eventHtml = '';
455 events.forEach(event => {
456 let eventDate = new Date(parseFloat(event.dates.ticket_start_date_timestamp) * 1000);
457 if (eventDate.getDate() === day && eventDate.getMonth() === month && eventDate.getFullYear() === year) {
458 eventHtml += '<div class="sasoEventTicketsValidator_event">' + event.product.title + '</div>';
459 }
460 });
461 html += '<div class="sasoEventTicketsValidator_calendar-cell">' + day + eventHtml + '</div>';
462 if ((day + firstDay) % 7 === 0 && day !== daysInMonth) {
463 html += '</div><div class="sasoEventTicketsValidator_calendar-row">';
464 }
465 }
466 html += '</div>';
467 html += '</div>';
468 html += '</div>';
469
470 let calendar_view = $(html)
471 .find('.sasoEventTicketsValidator_calendar-cell')
472 .click(function () {
473 let day = $(this).text();
474 //console.log(day);
475 });
476 return calendar_view;
477 }
478
479 function starten() {
480 $ = jQuery;
481
482 addStyleCode('.lds-dual-ring {display:inline-block;width:64px;height:64px;}.lds-dual-ring:after {content:" ";display:block;width:46px;height:46px;margin:1px;border-radius:50%;border:5px solid #fff;border-color:#2e74b5 transparent #2e74b5 transparent;animation:lds-dual-ring 0.6s linear infinite;}@keyframes lds-dual-ring {0% {transform: rotate(0deg);}100% {transform: rotate(360deg);}}');
483 addMetaTag("viewport", "width=device-width, initial-scale=1");
484
485 DIV = $('#'+myAjax.divId);
486 DIV.html(_getSpinnerHTML());
487 //DIV.html(JSON.stringify(myAjax));
488 window.setTimeout(()=>{DIV.html(renderEventsAsList());},250);
489 }
490
491 var $;
492 //window.onload = starten;
493 starten();
494 } );