hdoc-tools 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/custom_modules/tips.js +69 -0
  2. package/hdoc-build.js +5 -0
  3. package/hdoc-serve.js +366 -0
  4. package/hdoc.js +86 -0
  5. package/package.json +29 -0
  6. package/ui/css/images/hornbill-logo-full.svg +92 -0
  7. package/ui/css/theme-default/fonts/inter-cyrillic-ext.woff2 +0 -0
  8. package/ui/css/theme-default/fonts/inter-cyrillic.woff2 +0 -0
  9. package/ui/css/theme-default/fonts/inter-greek-ext.woff2 +0 -0
  10. package/ui/css/theme-default/fonts/inter-greek.woff2 +0 -0
  11. package/ui/css/theme-default/fonts/inter-italic-cyrillic-ext.woff2 +0 -0
  12. package/ui/css/theme-default/fonts/inter-italic-cyrillic.woff2 +0 -0
  13. package/ui/css/theme-default/fonts/inter-italic-greek-ext.woff2 +0 -0
  14. package/ui/css/theme-default/fonts/inter-italic-greek.woff2 +0 -0
  15. package/ui/css/theme-default/fonts/inter-italic-latin-ext.woff2 +0 -0
  16. package/ui/css/theme-default/fonts/inter-italic-latin.woff2 +0 -0
  17. package/ui/css/theme-default/fonts/inter-italic-vietnamese.woff2 +0 -0
  18. package/ui/css/theme-default/fonts/inter-latin-ext.woff2 +0 -0
  19. package/ui/css/theme-default/fonts/inter-latin.woff2 +0 -0
  20. package/ui/css/theme-default/fonts/inter-roman-cyrillic-ext.woff2 +0 -0
  21. package/ui/css/theme-default/fonts/inter-roman-cyrillic.woff2 +0 -0
  22. package/ui/css/theme-default/fonts/inter-roman-greek-ext.woff2 +0 -0
  23. package/ui/css/theme-default/fonts/inter-roman-greek.woff2 +0 -0
  24. package/ui/css/theme-default/fonts/inter-roman-latin-ext.woff2 +0 -0
  25. package/ui/css/theme-default/fonts/inter-roman-latin.woff2 +0 -0
  26. package/ui/css/theme-default/fonts/inter-roman-vietnamese.woff2 +0 -0
  27. package/ui/css/theme-default/fonts/inter-vietnamese.woff2 +0 -0
  28. package/ui/css/theme-default/styles/base.css +225 -0
  29. package/ui/css/theme-default/styles/components/content.css +82 -0
  30. package/ui/css/theme-default/styles/components/custom-block.css +90 -0
  31. package/ui/css/theme-default/styles/components/htl-doc.css +711 -0
  32. package/ui/css/theme-default/styles/components/sidebar.css +178 -0
  33. package/ui/css/theme-default/styles/fonts.css +221 -0
  34. package/ui/css/theme-default/styles/htldoc.layouts.css +244 -0
  35. package/ui/css/theme-default/styles/vars.css +393 -0
  36. package/ui/index.html +230 -0
  37. package/ui/js/doc.hornbill.js +485 -0
  38. package/ui/js/highlightjs/LICENSE +24 -0
  39. package/ui/js/highlightjs/highlight.pack.js +2 -0
  40. package/ui/js/highlightjs/styles/brown-paper.css +64 -0
  41. package/ui/js/highlightjs/styles/brown-papersq.png +0 -0
  42. package/ui/js/highlightjs/styles/codepen-embed.css +60 -0
  43. package/ui/js/highlightjs/styles/color-brewer.css +71 -0
  44. package/ui/js/highlightjs/styles/darcula.css +77 -0
  45. package/ui/js/highlightjs/styles/dark.css +63 -0
  46. package/ui/js/highlightjs/styles/darkula.css +6 -0
  47. package/ui/js/highlightjs/styles/default.css +99 -0
  48. package/ui/js/highlightjs/styles/dracula.css +76 -0
  49. package/ui/js/highlightjs/styles/far.css +71 -0
  50. package/ui/js/highlightjs/styles/foundation.css +88 -0
  51. package/ui/js/highlightjs/styles/github-gist.css +71 -0
  52. package/ui/js/highlightjs/styles/github-mm.css +71 -0
  53. package/ui/js/highlightjs/styles/github.css +99 -0
  54. package/ui/js/highlightjs/styles/googlecode.css +89 -0
  55. package/ui/js/highlightjs/styles/grayscale.css +101 -0
  56. package/ui/js/highlightjs/styles/idea.css +97 -0
  57. package/ui/js/highlightjs/styles/ir-black.css +73 -0
  58. package/ui/js/highlightjs/styles/kavadocs.css +71 -0
  59. package/ui/js/highlightjs/styles/kavadocsdark.css +120 -0
  60. package/ui/js/highlightjs/styles/kimbie.dark.css +74 -0
  61. package/ui/js/highlightjs/styles/kimbie.light.css +74 -0
  62. package/ui/js/highlightjs/styles/magula.css +70 -0
  63. package/ui/js/highlightjs/styles/mono-blue.css +59 -0
  64. package/ui/js/highlightjs/styles/monokai-sublime.css +83 -0
  65. package/ui/js/highlightjs/styles/monokai.css +70 -0
  66. package/ui/js/highlightjs/styles/obsidian.css +88 -0
  67. package/ui/js/highlightjs/styles/paraiso-dark.css +72 -0
  68. package/ui/js/highlightjs/styles/paraiso-light.css +72 -0
  69. package/ui/js/highlightjs/styles/railscasts.css +106 -0
  70. package/ui/js/highlightjs/styles/rainbow.css +85 -0
  71. package/ui/js/highlightjs/styles/solarized-dark.css +84 -0
  72. package/ui/js/highlightjs/styles/solarized-light.css +84 -0
  73. package/ui/js/highlightjs/styles/sunburst.css +102 -0
  74. package/ui/js/highlightjs/styles/twilight.css +97 -0
  75. package/ui/js/highlightjs/styles/vs.css +68 -0
  76. package/ui/js/highlightjs/styles/vs2015.css +117 -0
  77. package/ui/js/highlightjs/styles/xcode.css +104 -0
  78. package/ui/js/highlightjs/styles/zenburn.css +80 -0
  79. package/ui/js/highlightjs-badge.js +443 -0
@@ -0,0 +1,485 @@
1
+ //-- DOM/URL EVENTS
2
+ //-- THIS CONTROLS NAVIGATION
3
+ //-- loaded in index.html
4
+
5
+ var jqContentContainer = null;
6
+ var jqLeftNav = null;
7
+ var global = {stateParams:{},lastLayoutClass:""};
8
+
9
+ var docAppMethods = {
10
+ switchViewTheme:function()
11
+ {
12
+ if(ThemePreference)document.documentElement.classList.remove(ThemePreference)
13
+
14
+ if(ThemePreference === 'dark')
15
+ {
16
+ ThemePreference = 'light';
17
+ }
18
+ else{
19
+ ThemePreference = 'dark'
20
+ }
21
+
22
+ localStorage.setItem('hdocbook-theme-appearance',ThemePreference)
23
+ document.documentElement.classList.add(ThemePreference)
24
+ },
25
+ renderNavigation:function()
26
+ {
27
+ let self = this;
28
+ self.docApp.navSections = self.docApp.book.navigation.items; //-- show be an array of nav groups
29
+ },
30
+ toggleMobileMenu:function()
31
+ {
32
+ let isOpen = $(".mobile-menu-btn").data("isopen");
33
+ if(isOpen)
34
+ {
35
+ $(".DocSidebar").removeClass("open");
36
+ }
37
+ else
38
+ {
39
+ $(".DocSidebar").addClass("open");
40
+ }
41
+ //-- store new mode
42
+ $(".mobile-menu-btn").data("isopen",!isOpen);
43
+ },
44
+ resetMobileMenu:function(ev)
45
+ {
46
+ if( ev && ($(ev.srcElement).hasClass("mobile-menu-btn")[0] || $(ev.srcElement).closest(".mobile-menu-btn")[0]) )
47
+ {
48
+ //-- skp as have clikc no menu btn
49
+ }
50
+ else
51
+ {
52
+ $(".mobile-menu-btn").data("isopen",false);
53
+ $(".DocSidebar").removeClass("open");
54
+ }
55
+ }
56
+
57
+ };
58
+
59
+
60
+ //--
61
+ //-- user clicked back or forwards
62
+ window.addEventListener('popstate', function (event)
63
+ {
64
+ const loadUrl = new URL(event.target.location.href);
65
+ loadContentUrl(loadUrl.pathname + loadUrl.hash,{},false,true);
66
+ });
67
+
68
+
69
+ //--- GLOBAL FUNCTIONS
70
+ function removeTrailingSlash(str) {
71
+ return str.endsWith('/') ? str.slice(0, -1) : str;
72
+ }
73
+ function removeStartingSlash(str) {
74
+ return str.startsWith('/') ? str.slice(1, str.length) : str;
75
+
76
+ //if(linkRef.indexOf("/")===0)linkRef = linkRef.replace("/","");
77
+ }
78
+
79
+ function toSeoUrl(url) {
80
+ return url.toString() // Convert to string
81
+ .normalize('NFD') // Change diacritics
82
+ .replace(/[\u0300-\u036f]/g,'') // Remove illegal characters
83
+ .replace(/\s+/g,'-') // Change whitespace to dashes
84
+ .toLowerCase() // Change to lowercase
85
+ .replace(/&/g,'-and-') // Replace ampersand
86
+ .replace(/[^a-z0-9\-]/g,'') // Remove anything that is not a letter, number or dash
87
+ .replace(/-+/g,'-') // Remove duplicate dashes
88
+ .replace(/^-*/,'') // Remove starting dashes
89
+ .replace(/-*$/,''); // Remove trailing dashes
90
+ }
91
+
92
+ function listenForHrefClicks()
93
+ {
94
+ //-- trap all link click events - we want to handle links so can cancel and load content ourselves
95
+ $("A").off("click").on("click", function(ev)
96
+ {
97
+
98
+ let ele = this;
99
+ if(ele.href)
100
+ {
101
+ const checkUrl = new URL(ele.href);
102
+
103
+ view.resetMobileMenu();
104
+
105
+ //-- clicking on a hash tag header link element - so jsut scroll to element
106
+ if(checkUrl.origin +"/"===siteBaseLocation)
107
+ {
108
+ //-- if a url that is part of this doc site then handle loading content inline else let link do whatever (i.e. its an external link)
109
+ ev.stopImmediatePropagation();
110
+ ev.preventDefault();
111
+
112
+ //-- do we need to scroll into view element on this page
113
+ if(checkUrl.hash && $(checkUrl.hash +".faq-toc-item")[0])
114
+ {
115
+ $(checkUrl.hash +".faq-toc-item")[0].scrollIntoView();
116
+ if(ele.href!==document.location.href) window.history.pushState(null, null, ele.href); //-- user has clicked a link so we want to add state to history so we can click back
117
+ }
118
+ else
119
+ {
120
+ loadContentUrl(ele.getAttribute("href"),false,false);
121
+ }
122
+ return false;
123
+ }
124
+ else
125
+ {
126
+ //-- if not part of this website then always open in new tab as considered an external site
127
+ ele.setAttribute("target","_blank");
128
+ }
129
+ }
130
+ });
131
+
132
+ }
133
+
134
+ //-- based on content url highlight match navigation menu item
135
+ function highlightNavigationLinkFromUrl(matchLinkHref)
136
+ {
137
+
138
+ matchLinkHref = removeStartingSlash(matchLinkHref).split("#")[0]; //-- remvoe # link
139
+ $('a.DocLink').removeClass("active");
140
+
141
+ document.querySelectorAll('a.DocLink').forEach((el) => {
142
+
143
+ let checkUrl = null;
144
+ try{
145
+ checkUrl = new URL(el.href);
146
+ }
147
+ catch(e)
148
+ {
149
+ console.log("BAD navigation menu item found",el.href)
150
+ }
151
+
152
+ if(checkUrl)
153
+ {
154
+ //console.log(checkUrl.pathname,matchLinkHref)
155
+ if(removeStartingSlash(checkUrl.pathname).indexOf(matchLinkHref)===0)
156
+ {
157
+ $(el).addClass("active");
158
+ return false;//break out
159
+ }
160
+ else if(matchLinkHref.indexOf(removeStartingSlash(checkUrl.pathname) + "/")===0)
161
+ {
162
+ $(el).addClass("active");
163
+ return false;//break out
164
+ }
165
+ }
166
+ });
167
+ }
168
+
169
+ //-- create items to stick in toc from current loaded content
170
+ //-- searches for H2,H3
171
+ function generateTableOfContentsFromDoc()
172
+ {
173
+ let container = jqContentContainer[0];
174
+ if(container)
175
+ {
176
+ const currUrl = new URL(document.location.href);
177
+ view.docApp.tableOfContents = [];
178
+ for (let i=2; i<=3; i++)
179
+ {
180
+ let headers = container.getElementsByTagName("h"+i);
181
+ for (let j=0; j<headers.length; j++)
182
+ {
183
+ let jqCurrHeader = $(headers[j]);
184
+ //-- only process headers that do not have this class
185
+ if(!jqCurrHeader.hasClass("no-auto-anchor")) jqCurrHeader.addClass("faq-toc-item");
186
+ }
187
+ }
188
+
189
+ var headersTocItem = container.getElementsByClassName("faq-toc-item");
190
+ for (let k = 0; k < headersTocItem.length; k++)
191
+ {
192
+ let item = headersTocItem[k];
193
+ let strLabel = $.trim(item.innerText);
194
+ if(strLabel)
195
+ {
196
+ let seoSafeId = toSeoUrl(strLabel); //-- will use SEO to set in url so can scroll to element from url
197
+ let linkUrl = currUrl.pathname + "#" + seoSafeId;
198
+ item.id = seoSafeId;
199
+
200
+ view.docApp.tableOfContents.push({ele:item,eleText:strLabel,tagName:item.tagName,href:linkUrl});
201
+
202
+ //-- add link icon to header (using seo id)
203
+ $(item).append("<a class='header-anchor'><i class='bi bi-link'></i></a>");
204
+ $(item).find("a").attr("href",linkUrl);
205
+
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+
212
+ function loadContentUrl(linkRef,fromPageRefresh,fromPopState)
213
+ {
214
+ //-- clear table of contents
215
+ view.docApp.tableOfContents = [];
216
+
217
+ if(linkRef.indexOf(window.location.origin +"/")===0)
218
+ {
219
+ linkRef = linkRef.replace(window.location.origin +"/","");
220
+ }
221
+
222
+ //-- remove trailing / if has one
223
+ linkRef = removeTrailingSlash(linkRef);
224
+ //-- remove starting / if link starts with it
225
+ linkRef = removeStartingSlash(linkRef);
226
+
227
+ //-- update url in browser
228
+ setBrowserViewUrl(linkRef,{},fromPageRefresh,fromPopState);
229
+
230
+ //-- destroy any existing content children and events properly
231
+ jqContentContainer.empty();
232
+
233
+
234
+ //-- for now just load whatever the href prop is (we can add actions to perform specific processing and then load content based on element atts etc)
235
+ let frontmatterData = {};
236
+ fetch("content/"+linkRef).then(response =>
237
+ {
238
+ if(response.headers.has("X-frontmatter"))
239
+ {
240
+ frontmatterData = response.headers.get("X-frontmatter");
241
+ frontmatterData = JSON.parse(atob(frontmatterData));
242
+ }
243
+ return response.text();
244
+ }).then(html =>
245
+ {
246
+ jqContentContainer.html(html);
247
+
248
+ //-- remove previous layoutclass if have one
249
+ if(global.lastLayoutClass)
250
+ {
251
+ $("#DocContent").removeClass(global.lastLayoutClass);
252
+ global.lastLayoutClass = "";
253
+ }
254
+
255
+ //-- if have layoutclass add it to content container - this is so we can specify table list view sizes etc
256
+ if(frontmatterData.layout)
257
+ {
258
+ $("#DocContent").addClass(frontmatterData.layout);
259
+ global.lastLayoutClass = frontmatterData.layout;
260
+
261
+ //-- if layout supports toc (expects layout to have name "<layoutname>-toc")
262
+ if(frontmatterData.layout.substr(frontmatterData.layout.length - 4)==="-toc")
263
+ {
264
+ //generateTableOfContentsFromDoc();
265
+ }
266
+
267
+ }
268
+
269
+ //--generate toc for all layouts that have h2/h3
270
+ generateTableOfContentsFromDoc();
271
+
272
+ //-- do any code highlighting
273
+ document.querySelectorAll('pre code').forEach((el) => {
274
+ hljs.highlightBlock(el);
275
+ });
276
+
277
+ //-- show copy button by any code blocks
278
+ var options = {
279
+ contentSelector: ".injected-document-content",
280
+ // Delay in ms used for `setTimeout` before badging is applied
281
+ // Use if you need to time highlighting and badge application
282
+ // since the badges need to be applied afterwards.
283
+ // 0 - direct execution (ie. you handle timing
284
+ loadDelay:0,
285
+
286
+ // CSS class(es) used to render the copy icon.
287
+ copyIconClass: "bi bi-clipboard",
288
+ // CSS class(es) used to render the done icon.
289
+ checkIconClass: "bi bi-clipboard-check --htl-c-brand",
290
+
291
+ // intercept text copying - passed in text return text out
292
+ onBeforeCodeCopied: function(text) {
293
+ return text;
294
+ }
295
+ };
296
+
297
+ highlightJsBadge(options);
298
+
299
+ //-- make sure selected link parents are set to .expand=true
300
+ if(expandNavParentSectionBySelectedLinkHref(linkRef))
301
+ {
302
+ view.updateCounter++;
303
+ view.$nextTick(function()
304
+ {
305
+ //-- find any navigation links that match url and highlight
306
+ listenForHrefClicks();
307
+ highlightNavigationLinkFromUrl(linkRef);
308
+
309
+ //-- scroll to element that match hash (if have one)
310
+ if(document.location.hash)
311
+ {
312
+ $(document.location.hash)[0].scrollIntoView();
313
+ }
314
+ });
315
+ view.$forceUpdate();
316
+ }
317
+ });
318
+ }
319
+
320
+ function loadBookDefaultLink()
321
+ {
322
+ $(".DocLink").first().click();
323
+ }
324
+
325
+ function expandNavParentSectionBySelectedLinkHref(findByLinkRef, currentNavSection)
326
+ {
327
+ findByLinkRef = findByLinkRef.split("#")[0];
328
+ if(currentNavSection === undefined)
329
+ currentNavSection = view.docApp.navSections;
330
+
331
+
332
+ for(let x=0;x<currentNavSection.length;x++)
333
+ {
334
+ if(currentNavSection[x].items)
335
+ {
336
+ let res = expandNavParentSectionBySelectedLinkHref(findByLinkRef,currentNavSection[x].items);
337
+ if(res)
338
+ {
339
+ currentNavSection[x].expand=true;
340
+ return res;
341
+ }
342
+ }
343
+ else
344
+ {
345
+ //-- check item to see if it matches url
346
+ if(removeStartingSlash(removeTrailingSlash(currentNavSection[x].link)) == findByLinkRef)
347
+ {
348
+ return true;
349
+ }
350
+ }
351
+ }
352
+
353
+ }
354
+
355
+ function setBrowserViewUrl(strHrefToLoad,viewData,fromPageRefresh,fromPopState)
356
+ {
357
+
358
+ let urlToSet = window.location.origin + "/" + strHrefToLoad;
359
+ const url = new URL(urlToSet);
360
+
361
+ //-- remove any old params
362
+ for(let strKey in global.stateParams)
363
+ {
364
+ url.searchParams.delete(strKey);
365
+ }
366
+
367
+ //-- now set new data params in url
368
+ for(let strKey in viewData)
369
+ {
370
+ url.searchParams.set(strKey,viewData[strKey]);
371
+ }
372
+
373
+ //-- store global params
374
+ global.stateParams = viewData
375
+
376
+ if(!fromPopState)
377
+ {
378
+ if(fromPageRefresh)
379
+ {
380
+ window.history.replaceState(null, null, url); //-- user has refreshed page or jsut visited page
381
+ }
382
+ else
383
+ {
384
+ window.history.pushState(null, null, url); //-- user has clicked a link so we want to add state to history so we can click back
385
+ }
386
+ }
387
+
388
+ }
389
+
390
+ async function fetchContentFile(strFilePath)
391
+ {
392
+ return await fetch(strFilePath).then(response => response.text()).then(fileContent =>
393
+ {
394
+ return fileContent;
395
+ });
396
+ }
397
+
398
+ async function fetchJsonFile(strFilePath)
399
+ {
400
+ return await fetch(strFilePath).then(response => response.json()).then(jsonObject =>
401
+ {
402
+ return jsonObject;
403
+ });
404
+ }
405
+
406
+
407
+ //-- THE INIT APP CALLED FROM index.html
408
+ var view = new Vue({
409
+ el: '#vDocDevApp',
410
+ data: {updateCounter:0,bookId:"", docApp:{book:{},navSections:[],tableOfContents:[]}},
411
+ methods:docAppMethods,
412
+ directives: {
413
+ somedirectivename: {
414
+ bind (el, binding, vnode) {
415
+ //-- do something when created on element
416
+ }
417
+ }
418
+ } ,
419
+ mounted:function()
420
+ {
421
+
422
+ }
423
+ });
424
+
425
+ //-- repeatable conmponent for nav sections
426
+ Vue.component('nav-section-component', {
427
+ props: ['asection'],
428
+ template: '#nav-section-template',
429
+ methods:{
430
+ toggleNavCollapse:function(navSection)
431
+ {
432
+ navSection.expand=!navSection.expand;
433
+ this.$forceUpdate();
434
+ }
435
+ }
436
+ });
437
+
438
+
439
+ async function intialiseApp() {
440
+
441
+ // set theme switch
442
+ $(".theme-switch-checkbox").prop('checked', (ThemePreference === 'dark'));
443
+
444
+ jqContentContainer = $(".injected-document-content");
445
+ jqLeftNav = $("#DocSidebarNav");
446
+
447
+ await fetchJsonFile("content/library.json").then(function(data){
448
+
449
+ // Get docbook library list
450
+ view.docApp.library = data;
451
+ view.docId = view.docApp.library.books[0].docId;
452
+
453
+ }).then(function(){
454
+ // Get hdocbook.json
455
+ fetchJsonFile("content/" + view.docId + "/hdocbook.json").then(function(data)
456
+ {
457
+ view.docApp.book = data;
458
+ view.bookId = data.docId;
459
+ view.docApp.title = data.title || "";
460
+ view.docApp.description = data.description || "";
461
+ //-- now render out the nav menu
462
+ view.renderNavigation();
463
+
464
+ $("#vDocDevApp").removeClass("hb-hidden");
465
+
466
+ setTimeout(function()
467
+ {
468
+ listenForHrefClicks();
469
+
470
+ //-- check if url is not root - in which case we need to load content for url
471
+ var initialLoadContentHref = window.location.href.replace(window.location.origin+"/","");
472
+ if(initialLoadContentHref)
473
+ {
474
+ //-- find the link we are going to show and make sure parent/s are set to .expand=true
475
+ loadContentUrl(initialLoadContentHref,true,false);
476
+ }
477
+ else
478
+ {
479
+ //-- we are loading root so select for link
480
+ loadBookDefaultLink();
481
+ }
482
+ },200)
483
+ })
484
+ })
485
+ }
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2006, Ivan Sagalaev
2
+ All rights reserved.
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of highlight.js nor the names of its contributors
12
+ may be used to endorse or promote products derived from this software
13
+ without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
16
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.