]> gitweb @ CieloNegro.org - Rakka.git/blob - js/editPage.js
hexdumping
[Rakka.git] / js / editPage.js
1 (function () {
2
3     var $previewHeader = null;
4     var $previewArea   = null;
5
6     Rakka.editPage = function (pageName) {
7         var $area = Rakka.switchScreen();
8
9         Rakka.displayWaitingMessage("Loading... please wait.");
10
11         // XML 版のページを取得する。
12         $.ajax({
13             url    : Rakka.baseURI + pageName + ".xml",
14             success: function (pageXml) {
15                 Rakka.hideWaitingMessage();
16
17                 if (pageXml.documentElement.tagName == "page") {
18                     var $page       = $(pageXml).find("page");
19                     var oldRevision = $page.attr("revision");
20                     var defaultType
21                         = $page.attr("isBinary") == "yes"             ? "binary"
22                         : $page.attr("type")     == "text/x-rakka"    ? "rakka"
23                         : $page.attr("type")     == "text/css"        ? "css"
24                         : $page.attr("type")     == "text/javascript" ? "js"
25                         : $page.attr("redirect") != null              ? "redirect"
26                         :                                               "unknown"
27                         ;
28                     var lang        = $page.attr("lang");
29                     var isLocked    = $page.attr("isLocked") == "yes";
30                     var otherLangs  = (function () {
31                         var obj = {};
32                         $page.find("otherLang > link").each(function () {
33                             obj[this.getAttribute("lang")] = this.getAttribute("page");
34                         });
35                         return obj;
36                     })();
37                     var source
38                         = $page.attr("redirect") != null ? $page.attr("redirect")
39                         : $page.attr("isBinary") != null ? Rakka.decodeBase64($page.find("binaryData").text())
40                         :                                  $page.find("textData").text()
41                         ;
42                     var summary     = $page.find("summary").text();
43
44                     displayPageEditor(pageName, oldRevision, defaultType, lang, isLocked, otherLangs, source, summary);
45                 }
46                 else {
47                     displayPageEditor(pageName, null, "rakka", null, false, {}, null, "");
48                 }
49             },
50             error  : function (req) {
51                 Rakka.hideWaitingMessage();
52
53                 if (req.status == 404) {
54                     displayPageEditor(pageName, null, "rakka", null, false, {}, null, "");
55                 }
56                 else {
57                     $area.text("Error: " + req.status + " " + req.statusText);
58                 }
59             }
60         });
61     };
62
63     Rakka.newPage = function () {
64         displayPageEditor("", null, "rakka", null, false, {}, null, "");
65     };
66
67     var displayPageEditor = function (pageName, oldRevision, defaultType, lang, isLocked, otherLangs, source, summary) {
68         var $area = Rakka.switchScreen();
69
70         $previewHeader = $( $.H1({}, "Preview") );
71         $area.append($previewHeader);
72         $previewHeader.hide();
73
74         $previewArea = $( $.DIV({className: "preview"}) );
75         $area.append($previewArea);
76         $previewArea.hide();
77
78         $area.append($.H1({}, pageName == "" ? "Create page" : "Edit page"));
79
80         var isDirty = null;
81         var makeDirty = function () {
82             isDirty = true;
83         };
84
85         var fldPageName
86             = $.INPUT({type : "text", value: pageName});
87
88         $(fldPageName).change(makeDirty);
89
90         var chkIsLocked
91             = $.INPUT({type    : "checkbox",
92                        checked : (isLocked ? "checked" : "")});
93
94         $(chkIsLocked).change(makeDirty);
95
96         var trIsLocked
97             = $.TR({},
98                    $.TH({}, "Page lock"),
99                    $.TD({},
100                         $.LABEL({},
101                                 chkIsLocked,
102                                 "Disallow anonymous users to edit or delete this page")));
103
104         var btnTypeRakka
105             = $.INPUT({type   : "radio",
106                        name   : "type",
107                        checked: (defaultType == "rakka"    ? "checked" : "")});
108
109         $(btnTypeRakka).change(makeDirty);
110
111         var btnTypeCSS
112             = $.INPUT({type   : "radio",
113                        name   : "type",
114                        checked: (defaultType == "css"      ? "checked" : "")});
115
116         $(btnTypeCSS).change(makeDirty);
117
118         var btnTypeJS
119             = $.INPUT({type   : "radio",
120                        name   : "type",
121                        checked: (defaultType == "js"       ? "checked" : "")});
122         $(btnTypeJS).change(makeDirty);
123
124         var btnTypeBinary
125             = $.INPUT({type   : "radio",
126                        name   : "type",
127                        checked: (defaultType == "binary"   ? "checked" : "")});
128
129         $(btnTypeBinary).change(makeDirty);
130
131         var btnTypeRedirect
132             = $.INPUT({type   : "radio",
133                        name   : "type",
134                        checked: (defaultType == "redirect" ? "checked" : "")});
135
136         $(btnTypeRedirect).change(makeDirty);
137
138         var selPageLang
139             = $.SELECT({},
140                        $.OPTION({value: ""}, "(unspecified)"),
141                        (function () {
142                            var options = [];
143
144                            $.each(Rakka.getSystemConfig().languages, function (tag, name) {
145                                options.push(
146                                    $.OPTION({value: tag}, name));
147                            });
148
149                            return options;
150                        })());
151
152         $(selPageLang).change(makeDirty);
153
154         if (lang == null || lang == "") {
155             $(selPageLang).val($("html").attr("xml:lang"));
156         }
157         else {
158             $(selPageLang).val(lang);
159         }
160
161         var trPageLang
162             = $.TR({},
163                    $.TH({}, "Page language"),
164                    $.TD({}, selPageLang));
165
166         var trOtherLangs = (function () {
167             var options = [];
168
169             $.each(Rakka.getSystemConfig().languages, function (tag, name) {
170                 options.push(
171                     $.OPTION({value: tag}, name));
172             });
173
174             var selLang = $.SELECT({}, options);
175             var fldLink = $.INPUT({type: "text", className: "smallField"});
176
177             $(selLang).change(function () {
178                 var pageName = otherLangs[$(selLang).val()];
179                 $(fldLink).val(
180                     pageName == null ? "" : pageName
181                 );
182             }).trigger("change");
183
184             var onLinkChanged = function () {
185                 isDirty = true;
186
187                 var lang     = $(selLang).val();
188                 var pageName = $(this).val();
189
190                 if (pageName == "") {
191                     delete otherLangs[lang];
192                 }
193                 else {
194                     otherLangs[lang] = pageName;
195                 }
196             };
197             $(fldLink).change(onLinkChanged).keyup(onLinkChanged);
198
199             return $.TR({},
200                         $.TH({}, "Language links"),
201                         $.TD({}, selLang, fldLink));
202         })();
203
204         var fldSummary
205             = $.TEXTAREA({className: "summary"}, summary);
206
207         $(fldSummary).change(makeDirty);
208
209         var trSummary
210             = $.TR({},
211                    $.TH({}, "Summary"),
212                    $.TD({}, fldSummary));
213
214         var fldRakkaSource
215             = $.TEXTAREA({className: "source"},
216                          (defaultType == "rakka" && source != null ? source : ""));
217
218         $(fldRakkaSource).change(makeDirty);
219
220         var fldCSSSource
221             = $.TEXTAREA({className: "source"},
222                          (defaultType == "css"   && source != null ? source : ""));
223
224         $(fldCSSSource).change(makeDirty);
225
226         var fldJSSource
227             = $.TEXTAREA({className: "source"},
228                          (defaultType == "js"    && source != null ? source : ""));
229
230         $(fldJSSource).change(makeDirty);
231
232         var uploadFileBin
233             = (defaultType == "binary" && source != null ? source : "");
234         var fldUploadFile
235             = $.TEXTAREA({className: "hexDump", disabled: true}, Rakka.hexDump(uploadFileBin, 128));
236         var btnSelectFile
237             = $.INPUT({type: "button", value: "Select file..."});
238
239         $(btnSelectFile).click(function () {
240                                    var path = Rakka.selectFile("Select a binary file to upload", "open");
241                                    if (path != null) {
242                                        uploadFileBin = Rakka.loadLocalBinaryFile(path);
243                                        fldUploadFile.value = Rakka.hexDump(uploadFileBin, 128);
244                                        makeDirty();
245                                    }
246                                });
247
248         var fldRedirect
249             = $.INPUT({type: "text", value: (defaultType == "redirect" ? source : "")});
250
251         $(fldRedirect).change(makeDirty);
252
253         var trContent
254             = $.TR({},
255                    $.TH({}),
256                    $.TD({})
257                   );
258
259         var btnPreview
260             = $.INPUT({type: "button", value: "Preview page"});
261
262         $(btnPreview).click(function () {
263             if (btnTypeRakka.checked) {
264                 previewRakkaPage(
265                     fldPageName.value, fldRakkaSource.value);
266             }
267             else if (btnTypeBinary.checked) {
268                 if (uploadFileBin != "") {
269                     previewBinaryPage(
270                         fldPageName.value, uploadFileBin);
271                 }
272             }
273         });
274
275         var btnSubmit
276             = $.INPUT({type: "button", value: "Submit page"});
277
278         $(btnSubmit).click(function () {
279             if (btnTypeRakka.checked) {
280                 submitTextPage(
281                     pageName,
282                     oldRevision,
283                     fldPageName.value,
284                     chkIsLocked.checked,
285                     "text/x-rakka",
286                     $(selPageLang).val(),
287                     otherLangs,
288                     fldSummary.value,
289                     fldRakkaSource.value);
290             }
291             else if (btnTypeCSS.checked) {
292                 submitTextPage(
293                     pageName,
294                     oldRevision,
295                     fldPageName.value,
296                     chkIsLocked.checked,
297                     "text/css",
298                     $(selPageLang).val(),
299                     otherLangs,
300                     fldSummary.value,
301                     fldCSSSource.value);
302             }
303             else if (btnTypeJS.checked) {
304                 submitTextPage(
305                     pageName,
306                     oldRevision,
307                     fldPageName.value,
308                     chkIsLocked.checked,
309                     "text/javascript",
310                     $(selPageLang).val(),
311                     otherLangs,
312                     fldSummary.value,
313                     fldJSSource.value);
314             }
315             else if (btnTypeBinary.checked) {
316                 if (fldUploadFile.value != "") {
317                     submitBinaryPage(
318                         pageName,
319                         oldRevision,
320                         fldPageName.value,
321                         chkIsLocked.checked,
322                         $(selPageLang).val(),
323                         otherLangs,
324                         fldSummary.value,
325                         uploadFileBin);
326                 }
327             }
328             else if (btnTypeRedirect.checked) {
329                 submitRedirection(
330                     pageName,
331                     oldRevision,
332                     fldPageName.value,
333                     chkIsLocked.checked,
334                     fldRedirect.value);
335             }
336         });
337
338         var btnDelete
339             = $.INPUT({type: "button", value: "Delete this page"});
340
341         $(btnDelete).click(function () {
342             if (window.confirm("Do you really want to delete this page?")) {
343                 deletePage(pageName);
344             }
345         });
346
347         var btnCancel
348             = $.INPUT({type: "button", value: "Cancel editing"});
349
350         $(btnCancel).click(function () {
351             if (isDirty) {
352                 if (window.confirm("Do you really want to discard changes?")) {
353                     Rakka.restoreScreen();
354                 }
355             }
356             else {
357                 Rakka.restoreScreen();
358             }
359         });
360
361         var updateTRContent = function () {
362             if (btnTypeRakka.checked) {
363                 $(trPageLang).show();
364                 $(trOtherLangs).show();
365                 $(trSummary).show();
366                 $(trContent).find("th").text("Wiki source");
367                 $(trContent).find("td").empty().append(fldRakkaSource);
368                 $(btnPreview).show();
369             }
370             else if (btnTypeCSS.checked) {
371                 $(trPageLang).show();
372                 $(trOtherLangs).show();
373                 $(trSummary).show();
374                 $(trContent).find("th").text("CSS source");
375                 $(trContent).find("td").empty().append(fldCSSSource);
376                 $(btnPreview).hide();
377             }
378             else if (btnTypeJS.checked) {
379                 $(trPageLang).show();
380                 $(trOtherLangs).show();
381                 $(trSummary).show();
382                 $(trContent).find("th").text("JavaScript source");
383                 $(trContent).find("td").empty().append(fldJSSource);
384                 $(btnPreview).hide();
385             }
386             else if (btnTypeBinary.checked) {
387                 $(trPageLang).show();
388                 $(trOtherLangs).show();
389                 $(trSummary).show();
390                 $(trContent).find("th").text("File");
391                 $(trContent).find("td").empty().append(fldUploadFile).append(btnSelectFile);
392                 $(btnPreview).show();
393             }
394             else if (btnTypeRedirect.checked) {
395                 $(trPageLang).hide();
396                 $(trOtherLangs).hide();
397                 $(trSummary).hide();
398                 $(trContent).find("th").text("Destination Page");
399                 $(trContent).find("td").empty().append(fldRedirect);
400                 $(btnPreview).hide();
401             }
402         };
403         $(btnTypeRakka   ).change(updateTRContent);
404         $(btnTypeCSS     ).change(updateTRContent);
405         $(btnTypeJS      ).change(updateTRContent);
406         $(btnTypeBinary  ).change(updateTRContent);
407         $(btnTypeRedirect).change(updateTRContent);
408         updateTRContent();
409
410         var pageEditor
411             = $.TABLE({className: "pageEditor"},
412                       $.TBODY({},
413                               $.TR({},
414                                    $.TH({}, "Page name"),
415                                    $.TD({}, fldPageName)
416                                   ),
417                               trIsLocked,
418                               $.TR({},
419                                    $.TH({}, "Page type"),
420                                    $.TD({},
421                                         $.UL({},
422                                              $.LI({},
423                                                   $.LABEL({},
424                                                           btnTypeRakka,
425                                                           "Wiki page"
426                                                          )
427                                                  ),
428                                              $.LI({},
429                                                   $.LABEL({},
430                                                           btnTypeCSS,
431                                                           "Style sheet"
432                                                          )
433                                                  ),
434                                              $.LI({},
435                                                   $.LABEL({},
436                                                           btnTypeJS,
437                                                           "JavaScript"
438                                                          )
439                                                  ),
440                                              $.LI({},
441                                                   $.LABEL({},
442                                                           btnTypeBinary,
443                                                           "Binary file"
444                                                          )
445                                                  ),
446                                              $.LI({},
447                                                   $.LABEL({},
448                                                           btnTypeRedirect,
449                                                           "Redirection"
450                                                          )
451                                                  )
452                                             )
453                                        )
454                                   ),
455                               trPageLang,
456                               trOtherLangs,
457                               trSummary,
458                               trContent,
459                               $.TR({},
460                                    $.TH({}),
461                                    $.TD({}, btnPreview, btnSubmit, btnDelete, btnCancel)
462                                   )
463                              )
464                      );
465
466         var validate = function () {
467             var isValid = (function () {
468                 if (fldPageName.value.match(Rakka.rePageName) == null) {
469                     return false;
470                 }
471
472                 if (btnTypeRedirect.checked) {
473                     if (fldRedirect.value.match(Rakka.rePageName) == null) {
474                         return false;
475                     }
476                 }
477                 else {
478                     for (var tag in otherLangs) {
479                         if (otherLangs[tag].match(Rakka.rePageName) == null) {
480                             return false;
481                         }
482                     }
483
484                     if (btnTypeBinary.checked) {
485                         if (uploadFileBin == "") {
486                             return false;
487                         }
488                     }
489                 }
490
491                 return true;
492             })();
493
494             $(btnSubmit).attr({disabled: (isValid ? "" : "disabled")});
495         };
496         $(fldPageName)
497             .add(btnTypeRakka)
498             .add(btnTypeCSS)
499             .add(btnTypeJS)
500             .add(btnTypeBinary)
501             .add(btnTypeRedirect)
502             .add($(trOtherLangs).find("input"))
503             .add(fldUploadFile)
504             .add(fldRedirect)
505             .change(validate)
506             .keyup(validate);
507         $(btnSelectFile).click(validate);
508         validate();
509
510         if (oldRevision == null || oldRevision == 0) {
511             // 削除不可
512             $(btnDelete).hide();
513         }
514
515         $area.append(pageEditor);
516
517         if (!Rakka.isLoggedIn() || Rakka.isGlobalLocked) {
518             $(trIsLocked).hide();
519         }
520     };
521
522     var previewRakkaPage = function (pageName, source) {
523         Rakka.displayWaitingMessage("Loading... please wait.");
524
525         var url = Rakka.baseURI + "render/" + encodeURI(pageName);
526         $.ajax({
527             type       : "POST",
528             url        : url,
529             contentType: "text/x-rakka",
530             data       : source,
531             processData: false,
532             success    : function (resultDoc) {
533                 Rakka.hideWaitingMessage();
534                 showPreview(resultDoc);
535             },
536             error      : function (req) {
537                 Rakka.hideWaitingMessage();
538                 alert("Error: " + req.status + " " + req.statusText);
539             }
540         });
541     };
542
543     var previewBinaryPage = function (pageName, data) {
544         Rakka.displayWaitingMessage("Loading... please wait.");
545
546         /* Firefox でバイナリを送らうとすると 0x00 の位置で切れてしまふ。*/
547         var url = Rakka.baseURI + "render/" + encodeURI(pageName);
548         $.ajax({
549             type       : "POST",
550             url        : url,
551             contentType: "application/x-rakka-base64-stream",
552             data       : Rakka.encodeBase64(data),
553             processData: false,
554             success    : function (resultDoc) {
555                 Rakka.hideWaitingMessage();
556                 showPreview(resultDoc);
557             },
558             error      : function (req) {
559                 Rakka.hideWaitingMessage();
560                 alert("Error: " + req.status + " " + req.statusText);
561             }
562         });
563     };
564
565     var showPreview = function (doc) {
566         $previewArea.empty();
567
568         $previewHeader.show();
569         $previewArea.show();
570
571         var root  = doc.documentElement;
572         var child = root.firstChild;
573         do {
574             if (child.nodeType == 1) {
575                 // 要素だったので複製
576                 $previewArea.append(child.cloneNode(true));
577             }
578         } while (child = child.nextSibling);
579
580         Rakka.scrollToTopLeft();
581     };
582
583     var submitTextPage
584       = function (pageName, oldRevision, givenPageName, isLocked, mimeType, lang, otherLangs, summary, text) {
585          var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
586          var doc  = document.implementation.createDocument(NS, "page", null);
587          var page = doc.documentElement;
588
589         if (oldRevision != null) {
590             // ページ書換時
591             var updateInfo = doc.createElementNS(NS, "updateInfo");
592             updateInfo.setAttribute("oldRevision", oldRevision);
593
594             if (pageName != givenPageName) {
595                 var move = doc.createElementNS(NS, "move");
596                 move.setAttribute("from", pageName);
597                 updateInfo.appendChild(move);
598             }
599
600             page.appendChild(updateInfo);
601         }
602
603         page.setAttribute("isLocked", isLocked ? "yes" : "no");
604         page.setAttribute("type", mimeType);
605
606         if (lang != null && lang != "") {
607             page.setAttribute("lang", lang);
608         }
609
610         if (summary != null && summary != "") {
611             var s = doc.createElementNS(NS, "summary");
612             s.appendChild(
613                 doc.createTextNode(summary));
614             page.appendChild(s);
615         }
616
617         var oLang = doc.createElementNS(NS, "otherLang");
618         for (var tag in otherLangs) {
619             var link = doc.createElementNS(NS, "link");
620             link.setAttribute("lang", tag);
621             link.setAttribute("page", otherLangs[tag]);
622             oLang.appendChild(link);
623         }
624         page.appendChild(oLang);
625
626         var textData = doc.createElementNS(NS, "textData");
627         textData.appendChild(
628             doc.createTextNode(text));
629
630         page.appendChild(textData);
631
632         Rakka.displayWaitingMessage("Submitting... please wait.");
633
634         var url = Rakka.baseURI + encodeURI(givenPageName);
635         $.ajax({
636             type       : "PUT",
637             url        : url,
638             contentType: "text/xml",
639             data       : doc,
640             processData: false,
641             beforeSend : function (req) {
642                 Rakka.setAuthorization(req);
643             },
644             success    : function () {
645                 window.location.replace(url);
646             },
647             error      : function (req) {
648                 Rakka.hideWaitingMessage();
649
650                 var $area = Rakka.switchScreen();
651                 $area.text("Error: " + req.status + " " + req.statusText);
652             }
653         });
654     };
655
656     var submitBinaryPage = function (pageName, oldRevision, givenPageName, isLocked, lang, otherLangs, summary, data) {
657         var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
658         var doc  = document.implementation.createDocument(NS, "page", null);
659         var page = doc.documentElement;
660
661         if (oldRevision != null) {
662             // ページ書換時
663             var updateInfo = doc.createElementNS(NS, "updateInfo");
664             updateInfo.setAttribute("oldRevision", oldRevision);
665
666             if (pageName != givenPageName) {
667                 var move = doc.createElementNS(NS, "move");
668                 move.setAttribute("from", pageName);
669                 updateInfo.appendChild(move);
670             }
671
672             page.appendChild(updateInfo);
673         }
674
675         page.setAttribute("isLocked", isLocked ? "yes" : "no");
676         page.setAttribute("type", "");
677
678         if (lang != null && lang != "") {
679             page.setAttribute("lang", lang);
680         }
681
682         if (summary != null) {
683             var s = doc.createElementNS(NS, "summary");
684             s.appendChild(
685                 doc.createTextNode(summary));
686             page.appendChild(s);
687         }
688
689         var oLang = doc.createElementNS(NS, "otherLang");
690         for (var tag in otherLangs) {
691             var link = doc.createElementNS(NS, "link");
692             link.setAttribute("lang", tag);
693             link.setAttribute("page", otherLangs[tag]);
694             oLang.appendChild(link);
695         }
696         page.appendChild(oLang);
697
698         var b64 = Rakka.encodeBase64(data);
699         var binaryData = doc.createElementNS(NS, "binaryData");
700         binaryData.appendChild(
701             doc.createTextNode(b64));
702
703         page.appendChild(binaryData);
704
705         Rakka.displayWaitingMessage("Submitting... please wait.");
706
707         var url = Rakka.baseURI + encodeURI(givenPageName);
708         $.ajax({
709             type       : "PUT",
710             url        : url,
711             contentType: "text/xml",
712             data       : doc,
713             processData: false,
714             beforeSend : function (req) {
715                 Rakka.setAuthorization(req);
716             },
717             success    : function () {
718                 window.location.replace(url);
719             },
720             error      : function (req) {
721                 Rakka.hideWaitingMessage();
722
723                 var $area = Rakka.switchScreen();
724                 $area.text("Error: " + req.status + " " + req.statusText);
725             }
726         });
727     };
728
729     var submitRedirection = function (pageName, oldRevision, givenPageName, isLocked, destination) {
730         var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
731         var doc  = document.implementation.createDocument(NS, "page", null);
732         var page = doc.documentElement;
733
734         if (oldRevision != null) {
735             // ページ書換時
736             var updateInfo = doc.createElementNS(NS, "updateInfo");
737             updateInfo.setAttribute("oldRevision", oldRevision);
738
739             if (pageName != givenPageName) {
740                 var move = doc.createElementNS(NS, "move");
741                 move.setAttribute("from", pageName);
742                 updateInfo.appendChild(move);
743             }
744
745             page.appendChild(updateInfo);
746         }
747
748         page.setAttribute("isLocked", isLocked ? "yes" : "no");
749         page.setAttribute("redirect", destination);
750
751         Rakka.displayWaitingMessage("Submitting... please wait.");
752
753         var url = Rakka.baseURI + encodeURI(givenPageName);
754         $.ajax({
755             type       : "PUT",
756             url        : url,
757             contentType: "text/xml",
758             data       : doc,
759             processData: false,
760             beforeSend : function (req) {
761                 Rakka.setAuthorization(req);
762             },
763             success    : function () {
764                 window.location.replace(url);
765             },
766             error      : function (req) {
767                 Rakka.hideWaitingMessage();
768
769                 var $area = Rakka.switchScreen();
770                 $area.text("Error: " + req.status + " " + req.statusText);
771             }
772         });
773     };
774
775     var deletePage = function (pageName) {
776         var url = Rakka.baseURI + encodeURI(pageName);
777         $.ajax({
778             type       : "DELETE",
779             url        : url,
780             beforeSend : function (req) {
781                 Rakka.setAuthorization(req);
782             },
783             success    : function () {
784                 window.location.replace(url);
785             },
786             error      : function (req) {
787                 Rakka.hideWaitingMessage();
788
789                 var $area = Rakka.switchScreen();
790                 $area.text("Error: " + req.status + " " + req.statusText);
791             }
792         });
793     };
794
795 })();