diff --git a/public/res/editor.js b/public/res/editor.js index 335196ef..67e9b783 100644 --- a/public/res/editor.js +++ b/public/res/editor.js @@ -788,6 +788,7 @@ define([ selectionMgr.updateSelectionRange(); }; + var indentRegex = /^ {0,3}>[ ]*|^[ \t]*(?:[*+\-]|(\d+)\.)[ \t]|^\s+/; var actions = { indent: function(state, options) { function strSplice(str, i, remove, add) { @@ -805,16 +806,19 @@ define([ state.selectionEnd--; } state.selection = state.selection.replace(/^[ \t]/gm, ''); - } else if(state.selection) { - state.before = strSplice(state.before, lf, 0, '\t'); - state.selection = state.selection.replace(/\r?\n(?=[\s\S])/g, '\n\t'); - state.selectionStart++; - state.selectionEnd++; } else { - state.before += '\t'; - state.selectionStart++; - state.selectionEnd++; - return; + var previousLine = state.before.slice(lf); + if(state.selection || previousLine.match(indentRegex)) { + state.before = strSplice(state.before, lf, 0, '\t'); + state.selection = state.selection.replace(/\r?\n(?=[\s\S])/g, '\n\t'); + state.selectionStart++; + state.selectionEnd++; + } else { + state.before += '\t'; + state.selectionStart++; + state.selectionEnd++; + return; + } } state.selectionEnd = state.selectionStart + state.selection.length; @@ -832,7 +836,7 @@ define([ } clearNewline = false; var previousLine = state.before.slice(lf); - var indentMatch = previousLine.match(/^ {0,3}>[ ]*|^[ \t]*(?:[*+\-]|(\d+)\.)[ \t]|^\s+/); + var indentMatch = previousLine.match(indentRegex); var indent = (indentMatch || [''])[0]; if(indentMatch && indentMatch[1]) { var number = parseInt(indentMatch[1], 10); diff --git a/public/res/extensions/markdownExtra.js b/public/res/extensions/markdownExtra.js index 69d22ac1..d42d17d4 100644 --- a/public/res/extensions/markdownExtra.js +++ b/public/res/extensions/markdownExtra.js @@ -89,6 +89,8 @@ define([ _DoItalicsAndBold: function(text) { text = text.replace(/([^\w*]|^)(\*\*|__)(?=\S)(.+?[*_]*)(?=\S)\2(?=[^\w*]|$)/g, "$1$3"); text = text.replace(/([^\w*]|^)(\*|_)(?=\S)(.+?)(?=\S)\2(?=[^\w*]|$)/g, "$1$3"); + // Redo bold to handle _**word**_ + text = text.replace(/([^\w*]|^)(\*\*|__)(?=\S)(.+?[*_]*)(?=\S)\2(?=[^\w*]|$)/g, "$1$3"); return text; } }; diff --git a/public/res/libs/prism-markdown.js b/public/res/libs/prism-markdown.js index c0465945..2be8ef9f 100644 --- a/public/res/libs/prism-markdown.js +++ b/public/res/libs/prism-markdown.js @@ -1,12 +1,12 @@ // Credit to https://editorially.com/ Prism.languages.md = (function() { - var urlPattern = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>\[\]'"]+|\([^\s()<>\[\]'"]*\))+(?:\([^\s()<>\[\]'"]*\)|[^\s`!()\[\]{}:'".,<>?«»“”‘’]))/gi; - var emailPattern = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/gi; + var urlPattern = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>\[\]'"]+|\([^\s()<>\[\]'"]*\))+(?:\([^\s()<>\[\]'"]*\)|[^\s`!()\[\]{}:'".,<>?«»“”‘’]))/gi; + var emailPattern = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/gi; - var latex = Prism.languages.latex; + var latex = Prism.languages.latex; - var md = {}; + var md = {}; md['pre gfm'] = { pattern: /^`{3}.*\n(?:[\s\S]*?)\n`{3} *$/gm, inside: { @@ -14,25 +14,26 @@ Prism.languages.md = (function() { lf: /\n/gm } }; - md.pre = { - pattern: /(^|(?:^|(?:^|\n)(?![ \t]*([*+\-]|\d+\.)[ \t]).*\n)\s*?\n)(\s*(?: {4}|\t).*(?:\n|$))+/g, - lookbehind: true, - inside: { - } - }; - md['h1 alt'] = { - pattern: /^(.+)[ \t]*\n=+[ \t]*$/gm, - inside: { - } - }; - md['h2 alt'] = { - pattern: /^(.+)[ \t]*\n-+[ \t]*$/gm, - inside: { - } - }; + md.pre = { + pattern: /(^|(?:^|(?:^|\n)(?![ \t]*([*+\-]|\d+\.)[ \t]).*\n)\s*?\n)(\s*(?: {4}|\t).*(?:\n|$))+/g, + lookbehind: true, + inside: { + } + }; + md['h1 alt'] = { + pattern: /^(.+)[ \t]*\n=+[ \t]*$/gm, + inside: { + } + }; + md['h2 alt'] = { + pattern: /^(.+)[ \t]*\n-+[ \t]*$/gm, + inside: { + } + }; md.table = { pattern: new RegExp( - ['^' , + [ + '^' , '[ ]{0,3}' , // Allowed whitespace '[|]' , // Initial pipe '(.+)\\n' , // $1: Header Row @@ -53,7 +54,8 @@ Prism.languages.md = (function() { }; md['table alt'] = { pattern: new RegExp( - ['^' , + [ + '^' , '[ ]{0,3}' , // Allowed whitespace '(\\S.*[|].*)\\n' , // $1: Header Row @@ -73,271 +75,261 @@ Prism.languages.md = (function() { }; md.hr = { - pattern: /^([*\-_] *){3,}$/gm, - }; - md.li = { - pattern: /^[ \t]*([*+\-]|\d+\.)[ \t].+$/gm, - inside: { - "md md-li": /^ ?([*+\-]|\d+\.)[ \t]/m, - "md md-li2": /^ ?(?: {2}|\t{1})([*+\-]|\d+\.)[ \t]/m, - "md md-li3": /^ ?(?: {4}|\t{2})([*+\-]|\d+\.)[ \t]/m, - "md md-li4": /^ ?(?: {6}|\t{3})([*+\-]|\d+\.)[ \t]/m, - "md md-li5": /^ ?(?: {8}|\t{4})([*+\-]|\d+\.)[ \t]/m, - "md md-li6": /^ ?(?: {10}|\t{5})([*+\-]|\d+\.)[ \t]/m, - "md md-li7": /^ ?(?: {12}|\t{6})([*+\-]|\d+\.)[ \t]/m, - "md md-li8": /^ ?(?: {14}|\t{7})([*+\-]|\d+\.)[ \t]/m, - "md md-li9": /^ ?(?: {16}|\t{8})([*+\-]|\d+\.)[ \t]/m, - "md md-li10": /^ ?(?: {18}|\t{9})([*+\-]|\d+\.)[ \t]/m, - "md md-li11": /^ ?(?: {20}|\t{10})([*+\-]|\d+\.)[ \t]/m - } - }; - for (var i = 6; i >= 1; i--) { - md["h" + i] = { - pattern: new RegExp("^#{" + i + "}.+$", "gm"), - inside: { - "md md-hash": new RegExp("^#{" + i + "} ") - } - }; - } - md.blockquote = { - pattern: /^ {0,3}> *[^\n]+$/gm, - inside: { - "md md-gt": /^ {0,3}> */, - "li": md.li - } - }; - md['math block'] = { - pattern: /(\$\$|\\\\\[|\\\\\\\\\()[\s\S]*?(\$\$|\\\\\]|\\\\\\\\\))/g, - inside: { - "md md-bracket-start": /^(\$\$|\\\\\[|\\\\\\\\\()/, - "md md-bracket-end": /(\$\$|\\\\\]|\\\\\\\\\))/, - lf: /\n/gm, - rest: latex - } - }; - md['latex block'] = { - pattern: /\\?\\begin\{[a-z]*\*?\}[\s\S]*?\\?\\end\{[a-z]*\*?\}/g, - inside: { - "keyword": /\\?\\(begin|end)/, - lf: /\n/gm, - rest: latex - } - }; - md.fndef = { - pattern: /^ {0,3}\[\^.*?\]:[ \t]+.*$/gm, - inside: { - "ref-id": { - pattern: /\[\^.*?\]/, - inside: { - "md md-bracket-start": /\[/, - "md md-bracket-end": /\]/ - } - } - } - }; - md.linkdef = { - pattern: /^ {0,3}\[.*?\]:[ \t]+.*$/gm, - inside: { - "link-id": { - pattern: /\[.*?\]/, - inside: { - "md md-bracket-start": /\[/, - "md md-bracket-end": /\]/ - } - }, - url: urlPattern, - linktitle: /['\"\(][^\'\"\)]*['\"\)]/ - } - }; - md.p = { - pattern: /.+/g, - inside: { - 'md md-toc': /^\s*\[(toc|TOC)\]\s*$/g - } - }; - md.lf = /^\n$/gm; - md.img = { - pattern: /!\[[^\]]*\]\([^\)]+\)/g, - inside: { - "md md-bang": /^!/, - "md md-bracket-start": /\[/, - "md md-alt": /[^\[]+(?=\])/, - "md md-bracket-end": /\](?=\()/, - "md img-parens": { - pattern: /\([^\)]+\)/, - inside: { - "md md-paren-start": /^\(/, - "md md-title": /(['‘][^'’]*['’]|["“][^"”]*["”])(?=\)$)/, - "md md-src": /[^\('" \t]+(?=[\)'" \t])/, - "md md-paren-end": /\)$/ - } - } - } - }; - md.link = { - pattern: /\[(?:(\\.)|[^\[\]])*\]\([^\(\)\s]+(\(\S*?\))??[^\(\)\s]*?(\s(['‘][^'’]*['’]|["“][^"”]*["”]))?\)/gm, - inside: { - "md md-bracket-start": { - pattern: /(^|[^\\])\[/, - lookbehind: true - }, - "md md-underlined-text": { - pattern: /(?:(\\.)|[^\[\]])+(?=\])/ - }, - "md md-bracket-end": /\]\s?\(/, - "md md-paren-end": /\)$/, - "md md-href": /.*/ - } - }; - md.fn = { - pattern: /\[\^(.*?)\]/g, - inside: { - "ref": { - pattern: /^\[[^\[\]]+\] ?/, - inside: { - "md md-bracket-start": /\[/, - "md md-ref": /^[^\[\]]+/, - "md md-bracket-end": /\]/ - } - } - } - }; - md.imgref = { - pattern: /!\[(.*?)\] ?\[(.*?)\]/g, - inside: { - "md md-bang": /^!/, - "ref-end": { - pattern: /\[[^\[\]]+\]$/, - inside: { - "md md-bracket-start": /\[/, - "md md-href": /[^\[\]]+(?=]$)/, - "md md-bracket-end": /\]/ - } - }, - "ref-start": { - pattern: /^\[[^\[\]]+\] ?/, - inside: { - "md md-bracket-start": /\[/, - "md md-alt": /^[^\[\]]+/, - "md md-bracket-end": /\]/ - } - } - } - }; - md.linkref = { - pattern: /\[(.*?)\] ?\[(.*?)\]/g, - inside: { - "ref-end": { - pattern: /\[[^\[\]]+\]$/, - inside: { - "md md-bracket-start": /\[/, - "md md-href": /[^\[\]]+(?=]$)/, - "md md-bracket-end": /\]/ - } - }, - "ref-start": { - pattern: /^\[[^\[\]]+\] ?/, - inside: { - "md md-bracket-start": /\[/, - "md md-underlined-text": /^[^\[\]]+/, - "md md-bracket-end": /\]/ - } - } - } - }; - md.email = { - pattern: emailPattern - }; - md.code = { - pattern: /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/g, - lookbehind: true, - inside: { - "md md-code": /`/ - } - }; - md.math = { - pattern: /\$.*?\$/g, - inside: { - "md md-bracket-start": /^\$/, - "md md-bracket-end": /\$$/, - rest: latex - } - }; - md.strong = { - pattern: /([_\*])\1((?!\1{2}).)*\1{2}/g, - inside: { - "md md-strong": /([_\*])\1/g - } - }; - md.em = { - pattern: /(^|[^\\])(\*|_)(\S[^\2]*?)??[^\s\\]+?\2/g, - lookbehind: true, - inside: { - "md md-em md-start": /^(\*|_)/, - "md md-em md-close": /(\*|_)$/ - } - }; - md.strike = { - pattern: /(^|\n|\W)(~~)(?=\S)([^\r]*?\S)\2/gm, - lookbehind: true, - inside: { - "md md-s": /(~~)/, - "md-strike-text": /[^~]+/ - } - }; - var rest = { - code: md.code, - math: md.math, - fn: md.fn, - img: md.img, - link: md.link, - imgref: md.imgref, - linkref: md.linkref, - url: md.url, - email: md.email, - strong: md.strong, - em: md.em, - strike: md.strike, - conflict: /⧸⧸/g, - comment: Prism.languages.markup.comment, - tag: Prism.languages.markup.tag, - entity: Prism.languages.markup.entity - }; - for (var c = 6; c >= 1; c--) { - md["h" + c].inside.rest = rest; - } - md["h1 alt"].inside.rest = rest; - md["h2 alt"].inside.rest = rest; - md.table.inside.rest = rest; - md["table alt"].inside.rest = rest; - md.p.inside.rest = rest; - md.blockquote.inside.rest = rest; - md.li.inside.rest = rest; - md.fndef.inside.rest = rest; + pattern: /^([*\-_] *){3,}$/gm + }; + md.li = { + pattern: /^[ \t]*([*+\-]|\d+\.)[ \t].+$/gm, + inside: { + "md md-li": /^[ \t]*([*+\-]|\d+\.)[ \t]/m + } + }; + for(var i = 6; i >= 1; i--) { + md["h" + i] = { + pattern: new RegExp("^#{" + i + "}.+$", "gm"), + inside: { + "md md-hash": new RegExp("^#{" + i + "} ") + } + }; + } + md.blockquote = { + pattern: /^ {0,3}> *[^\n]+$/gm, + inside: { + "md md-gt": /^ {0,3}> */, + "li": md.li + } + }; + md['math block'] = { + pattern: /(\$\$|\\\\\[|\\\\\\\\\()[\s\S]*?(\$\$|\\\\\]|\\\\\\\\\))/g, + inside: { + "md md-bracket-start": /^(\$\$|\\\\\[|\\\\\\\\\()/, + "md md-bracket-end": /(\$\$|\\\\\]|\\\\\\\\\))/, + lf: /\n/gm, + rest: latex + } + }; + md['latex block'] = { + pattern: /\\?\\begin\{[a-z]*\*?\}[\s\S]*?\\?\\end\{[a-z]*\*?\}/g, + inside: { + "keyword": /\\?\\(begin|end)/, + lf: /\n/gm, + rest: latex + } + }; + md.fndef = { + pattern: /^ {0,3}\[\^.*?\]:[ \t]+.*$/gm, + inside: { + "ref-id": { + pattern: /\[\^.*?\]/, + inside: { + "md md-bracket-start": /\[/, + "md md-bracket-end": /\]/ + } + } + } + }; + md.linkdef = { + pattern: /^ {0,3}\[.*?\]:[ \t]+.*$/gm, + inside: { + "link-id": { + pattern: /\[.*?\]/, + inside: { + "md md-bracket-start": /\[/, + "md md-bracket-end": /\]/ + } + }, + url: urlPattern, + linktitle: /['\"\(][^\'\"\)]*['\"\)]/ + } + }; + md.p = { + pattern: /.+/g, + inside: { + 'md md-toc': /^\s*\[(toc|TOC)\]\s*$/g + } + }; + md.lf = /^\n$/gm; + md.img = { + pattern: /!\[[^\]]*\]\([^\)]+\)/g, + inside: { + "md md-bang": /^!/, + "md md-bracket-start": /\[/, + "md md-alt": /[^\[]+(?=\])/, + "md md-bracket-end": /\](?=\()/, + "md img-parens": { + pattern: /\([^\)]+\)/, + inside: { + "md md-paren-start": /^\(/, + "md md-title": /(['‘][^'’]*['’]|["“][^"”]*["”])(?=\)$)/, + "md md-src": /[^\('" \t]+(?=[\)'" \t])/, + "md md-paren-end": /\)$/ + } + } + } + }; + md.link = { + pattern: /\[(?:(\\.)|[^\[\]])*\]\([^\(\)\s]+(\(\S*?\))??[^\(\)\s]*?(\s(['‘][^'’]*['’]|["“][^"”]*["”]))?\)/gm, + inside: { + "md md-bracket-start": { + pattern: /(^|[^\\])\[/, + lookbehind: true + }, + "md md-underlined-text": { + pattern: /(?:(\\.)|[^\[\]])+(?=\])/ + }, + "md md-bracket-end": /\]\s?\(/, + "md md-paren-end": /\)$/, + "md md-href": /.*/ + } + }; + md.fn = { + pattern: /\[\^(.*?)\]/g, + inside: { + "ref": { + pattern: /^\[[^\[\]]+\] ?/, + inside: { + "md md-bracket-start": /\[/, + "md md-ref": /^[^\[\]]+/, + "md md-bracket-end": /\]/ + } + } + } + }; + md.imgref = { + pattern: /!\[(.*?)\] ?\[(.*?)\]/g, + inside: { + "md md-bang": /^!/, + "ref-end": { + pattern: /\[[^\[\]]+\]$/, + inside: { + "md md-bracket-start": /\[/, + "md md-href": /[^\[\]]+(?=]$)/, + "md md-bracket-end": /\]/ + } + }, + "ref-start": { + pattern: /^\[[^\[\]]+\] ?/, + inside: { + "md md-bracket-start": /\[/, + "md md-alt": /^[^\[\]]+/, + "md md-bracket-end": /\]/ + } + } + } + }; + md.linkref = { + pattern: /\[(.*?)\] ?\[(.*?)\]/g, + inside: { + "ref-end": { + pattern: /\[[^\[\]]+\]$/, + inside: { + "md md-bracket-start": /\[/, + "md md-href": /[^\[\]]+(?=]$)/, + "md md-bracket-end": /\]/ + } + }, + "ref-start": { + pattern: /^\[[^\[\]]+\] ?/, + inside: { + "md md-bracket-start": /\[/, + "md md-underlined-text": /^[^\[\]]+/, + "md md-bracket-end": /\]/ + } + } + } + }; + md.email = { + pattern: emailPattern + }; + md.code = { + pattern: /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/g, + lookbehind: true, + inside: { + "md md-code": /`/ + } + }; + md.math = { + pattern: /\$.*?\$/g, + inside: { + "md md-bracket-start": /^\$/, + "md md-bracket-end": /\$$/, + rest: latex + } + }; + md.strong = { + pattern: /([_\*])\1((?!\1{2}).)*\1{2}/g, + inside: { + "md md-strong": /([_\*])\1/g + } + }; + md.em = { + pattern: /(^|[^\\])(\*|_)(\S[^\2]*?)??[^\s\\]+?\2/g, + lookbehind: true, + inside: { + "md md-em md-start": /^(\*|_)/, + "md md-em md-close": /(\*|_)$/ + } + }; + md.strike = { + pattern: /(^|\n|\W)(~~)(?=\S)([^\r]*?\S)\2/gm, + lookbehind: true, + inside: { + "md md-s": /(~~)/, + "md-strike-text": /[^~]+/ + } + }; + var rest = { + code: md.code, + math: md.math, + fn: md.fn, + img: md.img, + link: md.link, + imgref: md.imgref, + linkref: md.linkref, + url: md.url, + email: md.email, + strong: md.strong, + em: md.em, + strike: md.strike, + conflict: /⧸⧸/g, + comment: Prism.languages.markup.comment, + tag: Prism.languages.markup.tag, + entity: Prism.languages.markup.entity + }; + for(var c = 6; c >= 1; c--) { + md["h" + c].inside.rest = rest; + } + md["h1 alt"].inside.rest = rest; + md["h2 alt"].inside.rest = rest; + md.table.inside.rest = rest; + md["table alt"].inside.rest = rest; + md.p.inside.rest = rest; + md.blockquote.inside.rest = rest; + md.li.inside.rest = rest; + md.fndef.inside.rest = rest; - rest = { - code: md.code, - fn: md.fn, - link: md.link, - linkref: md.linkref, - conflict: /⧸⧸/g, - }; - md.strong.inside.rest = rest; - md.em.inside.rest = rest; - md.strike.inside.rest = rest; + rest = { + code: md.code, + fn: md.fn, + link: md.link, + linkref: md.linkref, + conflict: /⧸⧸/g, + }; + md.strong.inside.rest = rest; + md.em.inside.rest = rest; + md.strike.inside.rest = rest; - var inside = { - code: md.code, - strong: md.strong, - em: md.em, - strike: md.strike, - conflict: /⧸⧸/g, - comment: Prism.languages.markup.comment, - tag: Prism.languages.markup.tag, - entity: Prism.languages.markup.entity - }; - md.link.inside["md md-underlined-text"].inside = inside; - md.linkref.inside["ref-start"].inside["md md-underlined-text"].inside = inside; + var inside = { + code: md.code, + strong: md.strong, + em: md.em, + strike: md.strike, + conflict: /⧸⧸/g, + comment: Prism.languages.markup.comment, + tag: Prism.languages.markup.tag, + entity: Prism.languages.markup.entity + }; + md.link.inside["md md-underlined-text"].inside = inside; + md.linkref.inside["ref-start"].inside["md md-underlined-text"].inside = inside; - return md; + return md; })(); diff --git a/public/res/styles/base.less b/public/res/styles/base.less index 9078c344..bca50a84 100644 --- a/public/res/styles/base.less +++ b/public/res/styles/base.less @@ -114,6 +114,7 @@ h6 { font-size: @title-base-size * 0.85; } h1, h2, h3, h4, h5, h6 { margin: 1.3em 0; + text-align: start; } pre { diff --git a/public/res/styles/main.less b/public/res/styles/main.less index 6d7102ae..1381eb60 100644 --- a/public/res/styles/main.less +++ b/public/res/styles/main.less @@ -1206,10 +1206,6 @@ a { .blockquote { color: @tertiary-color; - padding-left: 2em; - .li { - padding-left: 0; - } } .h1, .h2, .h3, .h4, .h5, .h6 { @@ -1256,57 +1252,6 @@ a { text-decoration: underline; } - .li { - padding-left: 0.8em; - .li { - padding-left: 0; - } - } - - .md-li { - padding-left: 1.2em; - } - - .md-li2 { - padding-left: 2.4em; - } - - .md-li3 { - padding-left: 3.6em; - } - - .md-li4 { - padding-left: 4.8em; - } - - .md-li5 { - padding-left: 6em; - } - - .md-li6 { - padding-left: 7.2em; - } - - .md-li7 { - padding-left: 8.4em; - } - - .md-li8 { - padding-left: 9.6em; - } - - .md-li9 { - padding-left: 10.8em; - } - - .md-li10 { - padding-left: 12em; - } - - .md-li11 { - padding-left: 13.2em; - } - .img, .imgref { padding: 0.2em 0.4em; diff --git a/tools/eclipse-formatter-config.xml b/tools/eclipse-formatter-config.xml deleted file mode 100644 index ff829786..00000000 --- a/tools/eclipse-formatter-config.xml +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -