read.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  5. <link href="lib/bootstrap/v3/css/bootstrap.min.css" rel="stylesheet" media="screen">
  6. <link href="lib/bootstrap/v3/css/bootstrap-theme.min.css" rel="stylesheet" media="screen">
  7. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  8. <script src="lib/bootstrap/v3/js/jquery.js"></script>
  9. <script src="lib/bootstrap/v3/js/bootstrap.min.js"></script>
  10. <script src="lib/zip.min.js"></script>
  11. <script src="lib/localforage.min.js"></script>
  12. <script src="lib/epub.js"></script>
  13. <script src="lib/smartimages.js"></script>
  14. <script src="js/read.js"></script>
  15. <script src="js/common.js"></script>
  16. <link id="favicon" rel="shortcut icon" type="image/png" href="img/favicon.png" />
  17. <link type="text/css" rel="stylesheet" media="screen" href="css/read.css" />
  18. </head>
  19. <body>
  20. <div class="modal fade" id="settings-modal" tabindex="-1" role="dialog">
  21. <div class="modal-dialog" role="document">
  22. <div class="modal-content">
  23. <div class="modal-header">
  24. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  25. <h4 class="modal-title">Settings</h4>
  26. </div>
  27. <div class="modal-body">
  28. <form name="settings-form" onsubmit="return false" class="form-horizontal">
  29. <div class="form-group">
  30. <label class="col-sm-3 control-label">Font</label>
  31. <div class="col-sm-9">
  32. <select class="font_family form-control" onchange="apply_font(this)">
  33. <option>Arial</option>
  34. <option>Times New Roman</option>
  35. <option>Georgia</option>
  36. </select>
  37. </div>
  38. </div>
  39. <div class="form-group">
  40. <label class="col-sm-3 control-label">Text size</label>
  41. <div class="col-sm-9">
  42. <select class="font_size form-control" onchange="apply_font_size(this)"></select>
  43. </div>
  44. </div>
  45. <div class="form-group">
  46. <label class="col-sm-3 control-label">Line height</label>
  47. <div class="col-sm-9">
  48. <select class="line_height form-control" onchange="apply_line_height(this)"></select>
  49. </div>
  50. </div>
  51. <div class="form-group">
  52. <label class="col-sm-3 control-label"></label>
  53. <div class="col-sm-9">
  54. <div class="checkbox">
  55. <label>
  56. <input class="transition_checkbox" onchange="toggle_transitions(this)"
  57. type="checkbox"> Disable transitions (needs page reload)
  58. </label>
  59. </div>
  60. </div>
  61. </div>
  62. <hr/>
  63. <div class="form-group">
  64. <label class="col-sm-3 control-label">Last location</label>
  65. <div class="col-sm-9">
  66. <div class="input-group">
  67. <input type="numeric" disabled="disabled" class="form-control lastread_input">
  68. <span class="input-group-btn">
  69. <button class="btn btn-danger" type="button" onclick="clear_lastread()">Clear</button>
  70. </span>
  71. </div>
  72. </div>
  73. </div>
  74. <div class="form-group">
  75. <label class="col-sm-3 control-label"></label>
  76. <div class="col-sm-9">
  77. <button class="btn btn-primary" type="button" onclick="mark_as_read()">Mark as read</button>
  78. </div>
  79. </div>
  80. </form>
  81. </div>
  82. <div class="modal-footer">
  83. <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
  84. </div>
  85. </div>
  86. </div>
  87. </div>
  88. <div class="modal fade" id="dict-modal" tabindex="-1" role="dialog">
  89. <div class="modal-dialog" role="document">
  90. <div class="modal-content">
  91. <div class="modal-header">
  92. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  93. <h4 class="modal-title">Dictionary Lookup</h4>
  94. </div>
  95. <div class="modal-body">
  96. <div class="dict_result"> </div>
  97. </div>
  98. <div class="modal-footer">
  99. <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
  100. </div>
  101. </div>
  102. </div>
  103. </div>
  104. <div class="modal fade" id="toc-modal" tabindex="-1" role="dialog">
  105. <div class="modal-dialog" role="document">
  106. <div class="modal-content">
  107. <div class="modal-header">
  108. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  109. <h4 class="modal-title">Table of Contents</h4>
  110. </div>
  111. <div class="modal-body">
  112. <ul class="toc_list list-unstyled"> </ul>
  113. </div>
  114. <div class="modal-footer">
  115. <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
  116. </div>
  117. </div>
  118. </div>
  119. </div>
  120. <div class="modal fade" id="search-modal" tabindex="-1" role="dialog">
  121. <div class="modal-dialog" role="document">
  122. <div class="modal-content">
  123. <div class="modal-header">
  124. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  125. <h4 class="modal-title">Search</h4>
  126. </div>
  127. <div class="modal-body">
  128. <form class="form-horizontal" onsubmit="return false;">
  129. <div class="form-group">
  130. <label class="col-sm-4 control-label">Search (active chapter)</label>
  131. <div class="col-sm-8">
  132. <input type="search" class="form-control search_input">
  133. </div>
  134. </div>
  135. <ol class="search_results"> </ol>
  136. </form>
  137. </div>
  138. <div class="modal-footer">
  139. <button type="button" class="btn btn-primary" onclick="search()">Search</button>
  140. <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. <div class="header">
  146. <span>
  147. <a href="#" onclick="save_and_close()">&laquo;&nbsp;Exit</a>
  148. <span class="title"></span>
  149. </span>
  150. <span class="toolbar">
  151. <!-- <button class="btn btn-default btn-xs"
  152. data-toggle="modal" data-target="#toc-modal">
  153. <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
  154. </button> -->
  155. <button class="btn btn-default btn-xs"
  156. data-toggle="modal" data-target="#settings-modal">
  157. <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
  158. </button>
  159. <button class="btn btn-default btn-xs" onclick="toggle_night_mode()">
  160. <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
  161. </button>
  162. <button class="btn btn-default btn-xs"
  163. data-toggle="modal" data-target="#search-modal">
  164. <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
  165. </button>
  166. <!-- <button class="btn btn-default btn-xs hidden-xs" onclick="zoom(2)">
  167. <span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span>
  168. </button>
  169. <button class="btn btn-default btn-xs hidden-xs" onclick="zoom(-2)">
  170. <span class="glyphicon glyphicon-zoom-out" aria-hidden="true"></span>
  171. </button> -->
  172. </span>
  173. </div>
  174. <div class="footer">
  175. <div class="chapter" data-toggle="modal" data-target="#toc-modal"></div>
  176. <div class="location">
  177. <span id="cur_page">?</span> / <span id="total_pages">?</span>
  178. (<span id="page_pct">?</span>)
  179. </div>
  180. </div>
  181. <div id="reader"></div>
  182. <div class="loading">
  183. <div class="loading_message">
  184. Opening book...
  185. </div>
  186. </div>
  187. <script>
  188. var _pagination_stored = 0;
  189. var _last_position_sync = 0;
  190. const DEFAULT_FONT_SIZE = 16;
  191. const DEFAULT_FONT_FAMILY = "Georgia";
  192. const DEFAULT_LINE_HEIGHT = 140;
  193. function cacheId(suffix) {
  194. return "epube-book." + $.urlParam("b") + (suffix ? "." + suffix : "");
  195. }
  196. $(document).ready(function() {
  197. apply_night_mode();
  198. $(window).on('online', function() {
  199. console.log("we're online, storing lastread");
  200. var currentPage = book.pagination.pageFromCfi(book.getCurrentLocationCfi());
  201. var currentCfi = book.getCurrentLocationCfi();
  202. $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: currentPage,
  203. cfi: currentCfi }, function(data) {
  204. if (data.cfi) {
  205. _last_position_sync = new Date().getTime()/1000;
  206. }
  207. });
  208. });
  209. if ('serviceWorker' in navigator) {
  210. navigator.serviceWorker
  211. .register('worker.js')
  212. .then(function() {
  213. console.log("service worker registered");
  214. });
  215. }
  216. localforage.getItem(cacheId("book")).then(function(item) {
  217. if (item) {
  218. console.log("loading from local storage");
  219. var fileReader = new FileReader();
  220. fileReader.onload = function() {
  221. book.open(this.result);
  222. };
  223. fileReader.readAsArrayBuffer(item);
  224. } else {
  225. console.log("loading from network");
  226. if (navigator.onLine) {
  227. var book_url = "backend.php?op=download&id=" + $.urlParam("id");
  228. RSVP.on('error', function(error) {
  229. if ($(".loading").is(":visible")) {
  230. $(".loading_message").html("Unable to load book.");
  231. }
  232. console.log(error);
  233. });
  234. fetch(book_url, {credentials: 'same-origin'}).then(function(resp) {
  235. if (resp.status == 200) {
  236. var bookId = $.urlParam("b");
  237. // let's store this for later
  238. localforage.setItem(cacheId('book'), resp.clone().blob());
  239. // if there's no base information cached yet, let's do that too
  240. localforage.getItem(cacheId()).then(function(info) {
  241. if (!info) {
  242. $.post("backend.php", {op: "getinfo", id: bookId }, function(data) {
  243. if (data) {
  244. localforage.setItem(cacheId(), data);
  245. if (data.has_cover) {
  246. fetch("backend.php?op=cover&id=" + bookId, {credentials: 'same-origin'}).then(function(resp) {
  247. if (resp.status == 200) {
  248. localforage.setItem(cacheId('cover'), resp.blob());
  249. }
  250. });
  251. }
  252. }
  253. });
  254. }
  255. });
  256. resp.blob().then(function(blob) {
  257. var fileReader = new FileReader();
  258. fileReader.onload = function() {
  259. book.open(this.result);
  260. };
  261. fileReader.readAsArrayBuffer(blob);
  262. });
  263. } else {
  264. $(".loading_message").html("Unable to download book: " + resp.status + ".");
  265. }
  266. });
  267. } else {
  268. $(".loading_message").html("This book is not available offline.");
  269. }
  270. }
  271. });
  272. init_taps();
  273. document.onkeydown = hotkey_handler;
  274. EPUBJS.Hooks.register("beforeChapterDisplay").swipeDetection = function(callback, renderer) {
  275. var baseUrl = window.location.href.match(/^.*\//)[0];
  276. EPUBJS.core.addScripts([baseUrl + "lib/bootstrap/v3/js/jquery.js",
  277. baseUrl + "lib/jquery.mobile.custom.js",
  278. baseUrl + "js/dict.js",
  279. baseUrl + "js/swipes.js" ], null, renderer.doc.head);
  280. EPUBJS.core.addCss(baseUrl + "css/reader.css", null, renderer.doc.head);
  281. localforage.getItem("epube.disable-transitions").then(function(disable) {
  282. if (!disable) {
  283. EPUBJS.core.addCss(baseUrl + "css/transitions.css", null, renderer.doc.head);
  284. EPUBJS.Render.Iframe.prototype.setLeft = function(leftPos){
  285. this.docEl.style[this.transform] = 'translate('+ (-leftPos) + 'px, 0)';
  286. }
  287. }
  288. });
  289. if (callback) callback();
  290. }
  291. var book = ePub({
  292. restore: false,
  293. });
  294. Promise.all([
  295. localforage.getItem("epube.fontSize"),
  296. localforage.getItem("epube.fontFamily"),
  297. localforage.getItem("epube.lineHeight")
  298. ]).then(function(res) {
  299. var fontSize = res[0] ? res[0] + "px" : DEFAULT_FONT_SIZE + "px";
  300. var fontFamily = res[1] ? res[1] : DEFAULT_FONT_FAMILY;
  301. var lineHeight = res[2] ? res[2] + "%" : DEFAULT_LINE_HEIGHT + "%";
  302. book.setStyle("fontSize", fontSize);
  303. book.setStyle("fontFamily", fontFamily);
  304. book.setStyle("lineHeight", lineHeight);
  305. book.setStyle("textAlign", "justify");
  306. });
  307. //styles: { fontSize: '24px', lineHeight: '130%', fontFamily: 'Georgia' }
  308. window.book = book;
  309. var rendered = book.renderTo("reader");
  310. $('#settings-modal').on('shown.bs.modal', function() {
  311. $.post("backend.php", { op: "getlastread", id: $.urlParam("id") }, function(data) {
  312. $(".lastread_input").val(data.page);
  313. });
  314. localforage.getItem("epube.disable-transitions").then(function(disable) {
  315. $(".transition_checkbox").attr("checked", disable);
  316. });
  317. localforage.getItem("epube.fontFamily").then(function(font) {
  318. if (!font) font = DEFAULT_FONT_FAMILY;
  319. $(".font_family").val(font);
  320. });
  321. localforage.getItem("epube.fontSize").then(function(size) {
  322. if (!size) size = DEFAULT_FONT_SIZE;
  323. var zoom = $(".font_size").html("");
  324. for (var i = 10; i <= 32; i++) {
  325. var opt = $("<option>").val(i).html(i + " px");
  326. if (i == size) opt.attr("selected", "1");
  327. zoom.append(opt);
  328. }
  329. });
  330. localforage.getItem("epube.lineHeight").then(function(height) {
  331. if (!height) height = DEFAULT_LINE_HEIGHT;
  332. var zoom = $(".line_height").html("");
  333. for (var i = 100; i <= 220; i += 10) {
  334. var opt = $("<option>").val(i).html(i + "%");
  335. if (i == height) opt.attr("selected", "1");
  336. zoom.append(opt);
  337. }
  338. });
  339. })
  340. $('#dict-modal').on('shown.bs.modal', function() {
  341. $(".dict_result").scrollTop(0);
  342. })
  343. $('#toc-modal').on('shown.bs.modal', function() {
  344. function process_toc_sublist(row, list) {
  345. if (row.subitems) {
  346. var sublist = $("<ul class='toc_sublist list-unstyled'>");
  347. $.each(row.subitems, function(i, row) {
  348. var a = $("<a>")
  349. .attr('href', '#')
  350. .html(row.label + " <b class='pull-right'>" +
  351. book.pagination.pageFromCfi(row.cfi) + "</b>")
  352. .attr('data-cfi', row.cfi)
  353. .click(function() {
  354. book.gotoCfi(a.attr('data-cfi'));
  355. });
  356. sublist.append($("<li>").append(a));
  357. process_toc_sublist(row, sublist);
  358. });
  359. list.append(sublist);
  360. }
  361. }
  362. book.getToc().then(function(toc) {
  363. var list = $(".toc_list");
  364. list.html("");
  365. $.each(toc, function(i, row) {
  366. // if anything fails here the toc entry is likely useless anyway (i.e. no cfi)
  367. try {
  368. var a = $("<a>")
  369. .attr('href', '#')
  370. .html(row.label + " <b class='pull-right'>" +
  371. book.pagination.pageFromCfi(row.cfi) + "</b>")
  372. .attr('data-cfi', row.cfi)
  373. .click(function() {
  374. book.gotoCfi(a.attr('data-cfi'));
  375. });
  376. list.append($("<li>").append(a));
  377. process_toc_sublist(row, list);
  378. } catch (e) {
  379. console.warn(e);
  380. }
  381. });
  382. // well the toc didn't work out, might as well generate one
  383. if (list.children().length <= 1) {
  384. list.html("");
  385. $.each(book.spine, function (i, row) {
  386. var a = $("<a>")
  387. .attr('href', '#')
  388. .attr('title', row.url)
  389. .html("Section " + (i+1) + " <b>(Loc. " +
  390. book.pagination.pageFromCfi(row.cfi) + ")</b>")
  391. .attr('data-cfi', row.cfi)
  392. .click(function() {
  393. book.gotoCfi(a.attr('data-cfi'));
  394. });
  395. list.append($("<li>").append(a));
  396. });
  397. }
  398. });
  399. })
  400. book.on("renderer:chapterUnloaded", function() {
  401. $(".chapter").html("Loading...");
  402. });
  403. book.on("renderer:chapterDisplayed", function() {
  404. $(".chapter").html("");
  405. var toc_entry = false;
  406. function iterate_sublist(row) {
  407. if (row.subitems) {
  408. $.each(row.subitems, function (i, r) {
  409. if (r.spinePos == book.currentChapter.spinePos) {
  410. toc_entry = r;
  411. return true;
  412. }
  413. if (iterate_sublist(r))
  414. return true;
  415. });
  416. }
  417. return false;
  418. }
  419. $.each(book.toc, function(i, a) {
  420. if (a.spinePos == book.currentChapter.spinePos) {
  421. toc_entry = a;
  422. return;
  423. }
  424. if (iterate_sublist(a)) return;
  425. });
  426. console.log('toc', toc_entry);
  427. if (toc_entry) $(".chapter").html(toc_entry.label);
  428. });
  429. book.on("renderer:chapterDisplayed", function() {
  430. $("#reader iframe")[0].contentWindow.onwheel = function(event) {
  431. if (event.deltaY > 0) {
  432. next_page();
  433. } else if (event.deltaY < 0) {
  434. prev_page();
  435. }
  436. };
  437. $("#reader iframe")[0].contentWindow.ontouchend = function(event) {
  438. console.log('ontouchend');
  439. };
  440. /*$("#reader iframe")[0].contentWindow.onmouseup = function(event) {
  441. if (!navigator.onLine) return;
  442. var wnd = this;
  443. var sel = wnd.getSelection().toString().trim();
  444. if (sel.match(/^\w+$/)) {
  445. $.post("backend.php", {op: 'define', word: sel}, function(data) {
  446. if (data) {
  447. wnd.getSelection().removeAllRanges();
  448. $(".dict_result").html(data.result.join("<br/>"));
  449. $("#dict-modal").modal('show');
  450. }
  451. });
  452. }
  453. };*/
  454. });
  455. book.on("renderer:keydown", hotkey_handler);
  456. book.getMetadata().then(function(meta){
  457. document.title = meta.bookTitle + " – " + meta.creator;
  458. $(".title").html("<b>" + meta.bookTitle + "</b> - " + meta.creator);
  459. });
  460. rendered.then(function() {
  461. localforage.getItem(cacheId("pagination")).then(function(pageList) {
  462. if (pageList && book.loadPagination(pageList).length > 0) {
  463. _pagination_stored = 1;
  464. } else {
  465. var url = "backend.php?op=getpagination&id=" + encodeURIComponent($.urlParam("id"));
  466. EPUBJS.core.request(url).then(function(pageList) {
  467. console.log("pagination: requesting remote: ");
  468. if (book.loadPagination(pageList).length > 0) {
  469. localforage.setItem(cacheId("pagination"), JSON.parse(pageList));
  470. _pagination_stored = 1;
  471. } else {
  472. book.generatePagination(1020, 2400);
  473. }
  474. }).catch(function() {
  475. book.generatePagination(1020, 2400);
  476. });
  477. }
  478. });
  479. });
  480. book.pageListReady.then(function(pageList) {
  481. if (!_pagination_stored) {
  482. if (navigator.onLine) {
  483. $.post("backend.php", { op: "storepagination", id: $.urlParam("id"),
  484. payload: JSON.stringify(pageList), total: book.pagination.totalPages });
  485. }
  486. localforage.setItem(cacheId("pagination"), pageList);
  487. }
  488. if (navigator.onLine) {
  489. $.post("backend.php", { op: "getlastread", id: $.urlParam("id") }, function(data) {
  490. console.log(data);
  491. if (navigator.onLine && data) {
  492. localforage.setItem(cacheId("lastread"),
  493. {cfi: data.cfi, page: data.page, total: data.total});
  494. if (data.cfi) book.gotoCfi(data.cfi);
  495. } else {
  496. localforage.getItem(cacheId("lastread")).then(function(item) {
  497. if (item && item.cfi) book.gotoCfi(item.cfi);
  498. });
  499. }
  500. });
  501. } else {
  502. localforage.getItem(cacheId("lastread")).then(function(item) {
  503. if (item && item.cfi) book.gotoCfi(item.cfi);
  504. });
  505. }
  506. var curPage = book.pagination.pageFromCfi(book.getCurrentLocationCfi());
  507. $("#total_pages").html(book.pagination.totalPages);
  508. $("#cur_page").html(curPage);
  509. if (book.pagination.totalPages > 0) {
  510. var pct = parseInt(curPage / book.pagination.totalPages * 100);
  511. $("#page_pct").html(pct + "%");
  512. }
  513. window.setTimeout(function() {
  514. $(".loading").hide();
  515. }, 1000);
  516. $(".location").click(function() {
  517. var current = book.pagination.pageFromCfi(book.getCurrentLocationCfi());
  518. var total = book.pagination.totalPages;
  519. var page = prompt("Jump to location [1-" + total + "]", current);
  520. if (page) {
  521. book.gotoPage(page);
  522. }
  523. });
  524. });
  525. book.on('book:pageChanged', function(location) {
  526. //console.log(location);
  527. $(".loading").hide();
  528. $("#cur_page").html(location.anchorPage);
  529. var total = book.pagination.totalPages;
  530. if (book.pagination.totalPages > 0) {
  531. var pct = parseInt(location.anchorPage / book.pagination.totalPages * 100);
  532. $("#page_pct").html(pct + "%");
  533. }
  534. if (_store_position && new Date().getTime()/1000 - _last_position_sync > 15) {
  535. console.log("storing lastread");
  536. var currentCfi = book.getCurrentLocationCfi();
  537. var currentPage = location.anchorPage;
  538. var totalPages = book.pagination.totalPages;
  539. if (navigator.onLine) {
  540. $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: currentPage,
  541. cfi: currentCfi }, function(data) {
  542. if (data.cfi) {
  543. _last_position_sync = new Date().getTime()/1000;
  544. }
  545. });
  546. _store_position = 0;
  547. } else {
  548. _last_position_sync = 0;
  549. }
  550. localforage.setItem(cacheId("lastread"),
  551. {cfi: currentCfi, page: currentPage, total: totalPages});
  552. }
  553. });
  554. });
  555. </script>
  556. </body>
  557. </html>