PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/NuGet/ServiceStack/content/default.htm

http://github.com/ServiceStack/ServiceStack
HTML | 685 lines | 597 code | 85 blank | 3 comment | 0 complexity | a1a99a203f88763a49d4e8ac3308fe52 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Backbone Demo: Todos</title>
  5. <script>window.JSON || document.write('<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js">\x3C/script>')</script>
  6. <!-- see: https://github.com/AjaxStack/AjaxStack -->
  7. <script src="jqunback-1.51.min.js"></script>
  8. <script type="text/javascript">
  9. // An example Backbone application contributed by
  10. // [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
  11. // [LocalStorage adapter](backbone-localstorage.html)
  12. // to persist Backbone models within your browser.
  13. // Load the application once the DOM is ready, using `jQuery.ready`:
  14. var todosUrl = "todos";
  15. $(function () {
  16. // Todo Model
  17. // ----------
  18. // Our basic **Todo** model has `content`, `order`, and `done` attributes.
  19. window.Todo = Backbone.Model.extend({
  20. // Default attributes for the todo.
  21. defaults: {
  22. Content: "empty todo...",
  23. Done: false
  24. },
  25. // Ensure that each todo created has `content`.
  26. initialize: function () {
  27. if (!this.get("Content")) {
  28. this.set({ "Content": this.defaults.Content });
  29. }
  30. },
  31. // Toggle the `done` state of this todo item.
  32. toggle: function () {
  33. this.save({ Done: !this.get("Done") });
  34. },
  35. url: function () {
  36. return this.get("Id") ? todosUrl + '/' + this.get("Id") : todosUrl;
  37. },
  38. // Remove this Todo from *localStorage* and delete its view.
  39. clear: function () {
  40. this.destroy();
  41. this.view.remove();
  42. }
  43. });
  44. // Todo Collection
  45. // ---------------
  46. // The collection of todos is backed by *localStorage* instead of a remote
  47. // server.
  48. window.TodoList = Backbone.Collection.extend({
  49. // Reference to this collection's model.
  50. model: Todo,
  51. // Save all of the todo items under the `"todos"` namespace.
  52. //localStorage: new Store("todos"),
  53. url: todosUrl,
  54. // Filter down the list of all todo items that are finished.
  55. done: function () {
  56. return this.filter(function (todo) { return todo.get('Done'); });
  57. },
  58. // Filter down the list to only todo items that are still not finished.
  59. remaining: function () {
  60. return this.without.apply(this, this.done());
  61. },
  62. // We keep the Todos in sequential order, despite being saved by unordered
  63. // GUID in the database. This generates the next order number for new items.
  64. nextOrder: function () {
  65. if (!this.length) return 1;
  66. return this.last().get('Order') + 1;
  67. },
  68. // Todos are sorted by their original insertion order.
  69. comparator: function (todo) {
  70. return todo.get('Order');
  71. }
  72. });
  73. // Create our global collection of **Todos**.
  74. window.Todos = new TodoList;
  75. // Todo Item View
  76. // --------------
  77. // The DOM element for a todo item...
  78. window.TodoView = Backbone.View.extend({
  79. //... is a list tag.
  80. tagName: "li",
  81. // Cache the template function for a single item.
  82. template: _.template($('#item-template').html()),
  83. // The DOM events specific to an item.
  84. events: {
  85. "click .check": "toggleDone",
  86. "dblclick div.todo-content": "edit",
  87. "click span.todo-destroy": "clear",
  88. "keypress .todo-input": "updateOnEnter"
  89. },
  90. // The TodoView listens for changes to its model, re-rendering. Since there's
  91. // a one-to-one correspondence between a **Todo** and a **TodoView** in this
  92. // app, we set a direct reference on the model for convenience.
  93. initialize: function () {
  94. _.bindAll(this, 'render', 'close');
  95. this.model.bind('change', this.render);
  96. this.model.view = this;
  97. },
  98. // Re-render the contents of the todo item.
  99. render: function () {
  100. $(this.el).html(this.template(this.model.toJSON()));
  101. this.setContent();
  102. return this;
  103. },
  104. // To avoid XSS (not that it would be harmful in this particular app),
  105. // we use `jQuery.text` to set the contents of the todo item.
  106. setContent: function () {
  107. var content = this.model.get('Content');
  108. this.$('.todo-content').text(content);
  109. this.input = this.$('.todo-input');
  110. this.input.bind('blur', this.close);
  111. this.input.val(content);
  112. },
  113. // Toggle the `"done"` state of the model.
  114. toggleDone: function () {
  115. this.model.toggle();
  116. },
  117. // Switch this view into `"editing"` mode, displaying the input field.
  118. edit: function () {
  119. $(this.el).addClass("editing");
  120. this.input.focus();
  121. },
  122. // Close the `"editing"` mode, saving changes to the todo.
  123. close: function () {
  124. this.model.save({ Content: this.input.val() });
  125. $(this.el).removeClass("editing");
  126. },
  127. // If you hit `enter`, we're through editing the item.
  128. updateOnEnter: function (e) {
  129. if (e.keyCode == 13) this.close();
  130. },
  131. // Remove this view from the DOM.
  132. remove: function () {
  133. $(this.el).remove();
  134. },
  135. // Remove the item, destroy the model.
  136. clear: function () {
  137. this.model.clear();
  138. }
  139. });
  140. // The Application
  141. // ---------------
  142. // Our overall **AppView** is the top-level piece of UI.
  143. window.AppView = Backbone.View.extend({
  144. // Instead of generating a new element, bind to the existing skeleton of
  145. // the App already present in the HTML.
  146. el: $("#todoapp"),
  147. // Our template for the line of statistics at the bottom of the app.
  148. statsTemplate: _.template($('#stats-template').html()),
  149. // Delegated events for creating new items, and clearing completed ones.
  150. events: {
  151. "keypress #new-todo": "createOnEnter",
  152. "keyup #new-todo": "showTooltip",
  153. "click .todo-clear a": "clearCompleted"
  154. },
  155. // At initialization we bind to the relevant events on the `Todos`
  156. // collection, when items are added or changed. Kick things off by
  157. // loading any preexisting todos that might be saved in *localStorage*.
  158. initialize: function () {
  159. _.bindAll(this, 'addOne', 'addAll', 'render');
  160. this.input = this.$("#new-todo");
  161. Todos.bind('add', this.addOne);
  162. Todos.bind('refresh', this.addAll);
  163. Todos.bind('all', this.render);
  164. Todos.fetch();
  165. },
  166. // Re-rendering the App just means refreshing the statistics -- the rest
  167. // of the app doesn't change.
  168. render: function () {
  169. var done = Todos.done().length;
  170. this.$('#todo-stats').html(this.statsTemplate({
  171. Total: Todos.length,
  172. Done: Todos.done().length,
  173. Remaining: Todos.remaining().length
  174. }));
  175. },
  176. // Add a single todo item to the list by creating a view for it, and
  177. // appending its element to the `<ul>`.
  178. addOne: function (todo) {
  179. var view = new TodoView({ model: todo });
  180. this.$("#todo-list").append(view.render().el);
  181. },
  182. // Add all items in the **Todos** collection at once.
  183. addAll: function () {
  184. Todos.each(this.addOne);
  185. },
  186. // Generate the attributes for a new Todo item.
  187. newAttributes: function () {
  188. return {
  189. Content: this.input.val(),
  190. Order: Todos.nextOrder(),
  191. Done: false
  192. };
  193. },
  194. // If you hit return in the main input field, create new **Todo** model,
  195. // persisting it to *localStorage*.
  196. createOnEnter: function (e) {
  197. if (e.keyCode != 13) return;
  198. Todos.create(this.newAttributes());
  199. this.input.val('');
  200. },
  201. // Clear all done todo items, destroying their models.
  202. clearCompleted: function () {
  203. _.each(Todos.done(), function (todo) { todo.clear(); });
  204. return false;
  205. },
  206. // Lazily show the tooltip that tells you to press `enter` to save
  207. // a new todo item, after one second.
  208. showTooltip: function (e) {
  209. var tooltip = this.$(".ui-tooltip-top");
  210. var val = this.input.val();
  211. tooltip.fadeOut();
  212. if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
  213. if (val == '' || val == this.input.attr('placeholder')) return;
  214. var show = function () { tooltip.show().fadeIn(); };
  215. this.tooltipTimeout = _.delay(show, 1000);
  216. }
  217. });
  218. // Finally, we kick things off by creating the **App**.
  219. window.App = new AppView;
  220. });
  221. </script>
  222. <style type="text/css">
  223. html, body, div, span, applet, object, iframe,
  224. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  225. a, abbr, acronym, address, big, cite, code,
  226. del, dfn, em, font, img, ins, kbd, q, s, samp,
  227. small, strike, strong, sub, sup, tt, var,
  228. dl, dt, dd, ol, ul, li,
  229. fieldset, form, label, legend,
  230. table, caption, tbody, tfoot, thead, tr, th, td {
  231. margin: 0;
  232. padding: 0;
  233. border: 0;
  234. outline: 0;
  235. font-weight: inherit;
  236. font-style: inherit;
  237. font-size: 100%;
  238. font-family: inherit;
  239. vertical-align: baseline;
  240. }
  241. body {
  242. line-height: 1;
  243. color: black;
  244. background: white;
  245. }
  246. ol, ul {
  247. list-style: none;
  248. }
  249. a img {
  250. border: none;
  251. }
  252. html {
  253. background: #eeeeee;
  254. }
  255. body {
  256. font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  257. font-size: 14px;
  258. line-height: 1.4em;
  259. background: #eeeeee;
  260. color: #333333;
  261. }
  262. #todoapp {
  263. width: 480px;
  264. margin: 0 auto 40px;
  265. background: white;
  266. padding: 20px;
  267. -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
  268. -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
  269. -o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
  270. box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
  271. }
  272. #todoapp h1 {
  273. font-size: 36px;
  274. font-weight: bold;
  275. text-align: center;
  276. padding: 20px 0 30px 0;
  277. line-height: 1;
  278. }
  279. #create-todo {
  280. position: relative;
  281. }
  282. #create-todo input {
  283. width: 466px;
  284. font-size: 24px;
  285. font-family: inherit;
  286. line-height: 1.4em;
  287. border: 0;
  288. outline: none;
  289. padding: 6px;
  290. border: 1px solid #999999;
  291. -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  292. -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  293. -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  294. box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  295. }
  296. #create-todo input::-webkit-input-placeholder {
  297. font-style: italic;
  298. }
  299. #create-todo span {
  300. position: absolute;
  301. z-index: 999;
  302. width: 170px;
  303. left: 50%;
  304. margin-left: -85px;
  305. }
  306. #todo-list {
  307. margin-top: 10px;
  308. }
  309. #todo-list li {
  310. padding: 12px 20px 11px 0;
  311. position: relative;
  312. font-size: 24px;
  313. line-height: 1.1em;
  314. border-bottom: 1px solid #cccccc;
  315. }
  316. #todo-list li:after {
  317. content: "\0020";
  318. display: block;
  319. height: 0;
  320. clear: both;
  321. overflow: hidden;
  322. visibility: hidden;
  323. }
  324. #todo-list li.editing {
  325. padding: 0;
  326. border-bottom: 0;
  327. }
  328. #todo-list .editing .display,
  329. #todo-list .edit {
  330. display: none;
  331. }
  332. #todo-list .editing .edit {
  333. display: block;
  334. }
  335. #todo-list .editing input {
  336. width: 444px;
  337. font-size: 24px;
  338. font-family: inherit;
  339. margin: 0;
  340. line-height: 1.6em;
  341. border: 0;
  342. outline: none;
  343. padding: 10px 7px 0px 27px;
  344. border: 1px solid #999999;
  345. -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  346. -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  347. -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  348. box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
  349. }
  350. #todo-list .check {
  351. position: relative;
  352. top: 9px;
  353. margin: 0 10px 0 7px;
  354. float: left;
  355. }
  356. #todo-list .done .todo-content {
  357. text-decoration: line-through;
  358. color: #777777;
  359. }
  360. #todo-list .todo-destroy {
  361. position: absolute;
  362. right: 5px;
  363. top: 14px;
  364. display: none;
  365. cursor: pointer;
  366. width: 20px;
  367. height: 20px;
  368. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAYAAAD+MdrbAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAc1JREFUeNrMVsFKw0AQTWIR+gdCrwUFQZSEgv5CQRAEwYPgKfdCC4JHvRTsR3gTAoLQn5AEvSgKxZwEv6EQ0jdlLJtld5OYFfrgHTqbebubmcyrG8exo8AGeAyegtvgPsdfwU8wAp/ATE5sKcRI4B7sKdZ85jn4DF7wBit4UsIAfNGIyejxswOd4Bi8A9tOdbQ5ZywLnoFD5+8YssZScJN3aYob0vK4kh3VE77vV4oxuqRFgn2TmCigiknou+jDD26VyqdJkkQnmNIJt3SrqkSDGKHjOXYxJ8Ef3WrNohC+STApE6Nrilc1iCYkODW9P1FIFZMwpSpTY79xHzVBCu7QCefgtYWCXP0WhfAAThqITVijMG1GfNJ5nTbhnJFqfNH0vQX3eHiWgZ454JzMNLFpAh+BJzw4ujylHW6xlK/3qLSAMAx1J8iEhEy65uq37Enr5ylBENj3FIja9xSILj3FxYdOn96XzgZqYAbuGj2FNqwYK/cUIdEtiRU8xROaVkYuCbmaNRGHRk/RJObr4yk1i2L2FMU7yyuI6j1FEMhLYgVP8fjf6MxCUWisRVY9BaPMnqdA7H88paXwlMgwYGVPucTJ3ssmdiNPWQgwAJAGndsKbcIpAAAAAElFTkSuQmCC) no-repeat 0 0;
  369. }
  370. #todo-list li:hover .todo-destroy {
  371. display: block;
  372. }
  373. #todo-list .todo-destroy:hover {
  374. background-position: 0 -20px;
  375. }
  376. #todo-stats {
  377. *zoom: 1;
  378. margin-top: 10px;
  379. color: #777777;
  380. }
  381. #todo-stats:after {
  382. content: "\0020";
  383. display: block;
  384. height: 0;
  385. clear: both;
  386. overflow: hidden;
  387. visibility: hidden;
  388. }
  389. #todo-stats .todo-count {
  390. float: left;
  391. }
  392. #todo-stats .todo-count .number {
  393. font-weight: bold;
  394. color: #333333;
  395. }
  396. #todo-stats .todo-clear {
  397. float: right;
  398. }
  399. #todo-stats .todo-clear a {
  400. color: #777777;
  401. font-size: 12px;
  402. }
  403. #todo-stats .todo-clear a:visited {
  404. color: #777777;
  405. }
  406. #todo-stats .todo-clear a:hover {
  407. color: #336699;
  408. }
  409. #instructions {
  410. width: 520px;
  411. margin: 10px auto;
  412. color: #777777;
  413. text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
  414. text-align: center;
  415. }
  416. #instructions a {
  417. color: #336699;
  418. }
  419. #credits {
  420. width: 520px;
  421. margin: 30px auto;
  422. color: #999;
  423. text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
  424. text-align: center;
  425. }
  426. #credits a {
  427. color: #888;
  428. }
  429. /*
  430. * François 'cahnory' Germain
  431. */
  432. .ui-tooltip, .ui-tooltip-top, .ui-tooltip-right, .ui-tooltip-bottom, .ui-tooltip-left {
  433. color:#ffffff;
  434. cursor:normal;
  435. display:-moz-inline-stack;
  436. display:inline-block;
  437. font-size:12px;
  438. font-family:arial;
  439. padding:.5em 1em;
  440. position:relative;
  441. text-align:center;
  442. text-shadow:0 -1px 1px #111111;
  443. -webkit-border-top-left-radius:4px ;
  444. -webkit-border-top-right-radius:4px ;
  445. -webkit-border-bottom-right-radius:4px ;
  446. -webkit-border-bottom-left-radius:4px ;
  447. -khtml-border-top-left-radius:4px ;
  448. -khtml-border-top-right-radius:4px ;
  449. -khtml-border-bottom-right-radius:4px ;
  450. -khtml-border-bottom-left-radius:4px ;
  451. -moz-border-radius-topleft:4px ;
  452. -moz-border-radius-topright:4px ;
  453. -moz-border-radius-bottomright:4px ;
  454. -moz-border-radius-bottomleft:4px ;
  455. border-top-left-radius:4px ;
  456. border-top-right-radius:4px ;
  457. border-bottom-right-radius:4px ;
  458. border-bottom-left-radius:4px ;
  459. -o-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
  460. -moz-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
  461. -khtml-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
  462. -webkit-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
  463. box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
  464. background-color:#3b3b3b;
  465. background-image:-moz-linear-gradient(top,#555555,#222222);
  466. background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555555),color-stop(1,#222222));
  467. filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
  468. -ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
  469. }
  470. .ui-tooltip:after, .ui-tooltip-top:after, .ui-tooltip-right:after, .ui-tooltip-bottom:after, .ui-tooltip-left:after {
  471. content:"\25B8";
  472. display:block;
  473. font-size:2em;
  474. height:0;
  475. line-height:0;
  476. position:absolute;
  477. }
  478. .ui-tooltip:after, .ui-tooltip-bottom:after {
  479. color:#2a2a2a;
  480. bottom:0;
  481. left:1px;
  482. text-align:center;
  483. text-shadow:1px 0 2px #000000;
  484. -o-transform:rotate(90deg);
  485. -moz-transform:rotate(90deg);
  486. -khtml-transform:rotate(90deg);
  487. -webkit-transform:rotate(90deg);
  488. width:100%;
  489. }
  490. .ui-tooltip-top:after {
  491. bottom:auto;
  492. color:#4f4f4f;
  493. left:-2px;
  494. top:0;
  495. text-align:center;
  496. text-shadow:none;
  497. -o-transform:rotate(-90deg);
  498. -moz-transform:rotate(-90deg);
  499. -khtml-transform:rotate(-90deg);
  500. -webkit-transform:rotate(-90deg);
  501. width:100%;
  502. }
  503. .ui-tooltip-right:after {
  504. color:#222222;
  505. right:-0.375em;
  506. top:50%;
  507. margin-top:-.05em;
  508. text-shadow:0 1px 2px #000000;
  509. -o-transform:rotate(0);
  510. -moz-transform:rotate(0);
  511. -khtml-transform:rotate(0);
  512. -webkit-transform:rotate(0);
  513. }
  514. .ui-tooltip-left:after {
  515. color:#222222;
  516. left:-0.375em;
  517. top:50%;
  518. margin-top:.1em;
  519. text-shadow:0 -1px 2px #000000;
  520. -o-transform:rotate(180deg);
  521. -moz-transform:rotate(180deg);
  522. -khtml-transform:rotate(180deg);
  523. -webkit-transform:rotate(180deg);
  524. }
  525. </style>
  526. </head>
  527. <body>
  528. <!-- Todo App Interface -->
  529. <div id="todoapp">
  530. <div class="title">
  531. <h1>Todos</h1>
  532. </div>
  533. <div class="content">
  534. <div id="create-todo">
  535. <input id="new-todo" placeholder="What needs to be done?" type="text" />
  536. <span class="ui-tooltip-top" style="display:none;">Press Enter to save this task</span>
  537. </div>
  538. <div id="todos">
  539. <ul id="todo-list"></ul>
  540. </div>
  541. <div id="todo-stats"></div>
  542. </div>
  543. </div>
  544. <ul id="instructions">
  545. <li>Double-click to edit a todo.</li>
  546. <li><a href="https://github.com/ServiceStack/ServiceStack/blob/master/NuGet/ServiceStack/content/App_Start/ServiceStackFramework.cs.pp">Source code of C# TODO REST Service</a> | <a href="http://documentcloud.github.com/backbone/examples/todos/index.html">Backbone.js TODO app</a> </li>
  547. </ul>
  548. <div id="credits">
  549. Created by
  550. <br />
  551. <a href="http://jgn.me/">J&eacute;r&ocirc;me Gravel-Niquet</a>
  552. <br />
  553. <br />
  554. Powered By Open Source
  555. <br />
  556. <a href="http://servicestack.net">servicestack.net</a>
  557. | <a href="http://redis.io">redis</a>
  558. | <a href="http://www.mono-project.com">mono</a>
  559. </div>
  560. <!-- Templates -->
  561. <script type="text/template" id="item-template">
  562. <div class="todo <%= Done ? 'Done' : '' %>">
  563. <div class="display">
  564. <input class="check" type="checkbox" <%= Done ? 'checked="checked"' : '' %> />
  565. <div class="todo-content"></div>
  566. <span class="todo-destroy"></span>
  567. </div>
  568. <div class="edit">
  569. <input class="todo-input" type="text" value="" />
  570. </div>
  571. </div>
  572. </script>
  573. <script type="text/template" id="stats-template">
  574. <% if (Total) { %>
  575. <span class="todo-count">
  576. <span class="number"><%= Remaining %></span>
  577. <span class="word"><%= Remaining == 1 ? 'item' : 'items' %></span> left.
  578. </span>
  579. <% } %>
  580. <% if (Done) { %>
  581. <span class="todo-clear">
  582. <a href="#">
  583. Clear <span class="number-done"><%= Done %></span>
  584. completed <span class="word-done"><%= Done == 1 ? 'item' : 'items' %></span>
  585. </a>
  586. </span>
  587. <% } %>
  588. </script>
  589. <script type="text/javascript">
  590. var _gaq = _gaq || [];
  591. _gaq.push(['_setAccount', 'UA-7722718-7']);
  592. _gaq.push(['_trackPageview']);
  593. (function () {
  594. var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  595. ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  596. var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  597. })();
  598. </script>
  599. </body>
  600. </html>