Current File : //usr/share/nodejs/codemirror/mode/markdown/test.js
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE

(function() {
  var config = {tabSize: 4, indentUnit: 2}
  var mode = CodeMirror.getMode(config, "markdown");
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
  var modeHighlightFormatting = CodeMirror.getMode(config, {name: "markdown", highlightFormatting: true});
  function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
  var modeMT_noXml = CodeMirror.getMode(config, {name: "markdown", xml: false});
  function MT_noXml(name) { test.mode(name, modeMT_noXml, Array.prototype.slice.call(arguments, 1)); }
  var modeMT_noFencedHighlight = CodeMirror.getMode(config, {name: "markdown", fencedCodeBlockHighlighting: false});
  function MT_noFencedHighlight(name) { test.mode(name, modeMT_noFencedHighlight, Array.prototype.slice.call(arguments, 1)); }
  var modeAtxNoSpace = CodeMirror.getMode(config, {name: "markdown", allowAtxHeaderWithoutSpace: true});
  function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); }
  var modeOverrideClasses = CodeMirror.getMode(config, {
    name: "markdown",
    strikethrough: true,
    emoji: true,
    tokenTypeOverrides: {
      "header" : "override-header",
      "code" : "override-code",
      "quote" : "override-quote",
      "list1" : "override-list1",
      "list2" : "override-list2",
      "list3" : "override-list3",
      "hr" : "override-hr",
      "image" : "override-image",
      "imageAltText": "override-image-alt-text",
      "imageMarker": "override-image-marker",
      "linkInline" : "override-link-inline",
      "linkEmail" : "override-link-email",
      "linkText" : "override-link-text",
      "linkHref" : "override-link-href",
      "em" : "override-em",
      "strong" : "override-strong",
      "strikethrough" : "override-strikethrough",
      "emoji" : "override-emoji"
  }});
  function TokenTypeOverrideTest(name) { test.mode(name, modeOverrideClasses, Array.prototype.slice.call(arguments, 1)); }
  var modeFormattingOverride = CodeMirror.getMode(config, {
    name: "markdown",
    highlightFormatting: true,
    tokenTypeOverrides: {
      "formatting" : "override-formatting"
  }});
  function FormatTokenTypeOverrideTest(name) { test.mode(name, modeFormattingOverride, Array.prototype.slice.call(arguments, 1)); }
  var modeET = CodeMirror.getMode(config, {name: "markdown", emoji: true});
  function ET(name) { test.mode(name, modeET, Array.prototype.slice.call(arguments, 1)); }


  FT("formatting_emAsterisk",
     "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");

  FT("formatting_emUnderscore",
     "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");

  FT("formatting_strongAsterisk",
     "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");

  FT("formatting_strongUnderscore",
     "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");

  FT("formatting_codeBackticks",
     "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");

  FT("formatting_doubleBackticks",
     "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");

  FT("formatting_atxHeader",
     "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");

  FT("formatting_setextHeader",
     "[header&header-1 foo]",
     "[header&header-1&formatting&formatting-header&formatting-header-1 =]");

  FT("formatting_blockquote",
     "[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]");

  FT("formatting_list",
     "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
  FT("formatting_list",
     "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");

  FT("formatting_link",
     "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url (][string&url http://example.com/][string&formatting&formatting-link-string&url )]");

  FT("formatting_linkReference",
     "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url [][string&url bar][string&formatting&formatting-link-string&url ]]]",
     "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]");

  FT("formatting_linkWeb",
     "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");

  FT("formatting_linkEmail",
     "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");

  FT("formatting_escape",
     "[formatting-escape \\*]");

  FT("formatting_image",
     "[formatting&formatting-image&image&image-marker !][formatting&formatting-image&image&image-alt-text&link [[][image&image-alt-text&link alt text][formatting&formatting-image&image&image-alt-text&link ]]][formatting&formatting-link-string&string&url (][url&string http://link.to/image.jpg][formatting&formatting-link-string&string&url )]");

  FT("codeBlock",
     "[comment&formatting&formatting-code-block ```css]",
     "[tag foo]",
     "[comment&formatting&formatting-code-block ```]");

  MT("plainText",
     "foo");

  // Don't style single trailing space
  MT("trailingSpace1",
     "foo ");

  // Two or more trailing spaces should be styled with line break character
  MT("trailingSpace2",
     "foo[trailing-space-a  ][trailing-space-new-line  ]");

  MT("trailingSpace3",
     "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-new-line  ]");

  MT("trailingSpace4",
     "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-a  ][trailing-space-new-line  ]");

  // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
  MT("codeBlocksUsing4Spaces",
     "    [comment foo]");

  // Code blocks using 4 spaces with internal indentation
  MT("codeBlocksUsing4SpacesIndentation",
     "    [comment bar]",
     "        [comment hello]",
     "            [comment world]",
     "    [comment foo]",
     "bar");

  // Code blocks should end even after extra indented lines
  MT("codeBlocksWithTrailingIndentedLine",
     "    [comment foo]",
     "        [comment bar]",
     "    [comment baz]",
     "    ",
     "hello");

  // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
  MT("codeBlocksUsing1Tab",
     "\t[comment foo]");

  // No code blocks directly after paragraph
  // http://spec.commonmark.org/0.19/#example-65
  MT("noCodeBlocksAfterParagraph",
     "Foo",
     "    Bar");

  MT("codeBlocksAfterATX",
     "[header&header-1 # foo]",
     "    [comment code]");

  MT("codeBlocksAfterSetext",
     "[header&header-2 foo]",
     "[header&header-2 ---]",
     "    [comment code]");

  MT("codeBlocksAfterFencedCode",
     "[comment ```]",
     "[comment foo]",
     "[comment ```]",
     "    [comment code]");

  // Inline code using backticks
  MT("inlineCodeUsingBackticks",
     "foo [comment `bar`]");

  // Block code using single backtick (shouldn't work)
  MT("blockCodeSingleBacktick",
     "[comment `]",
     "[comment foo]",
     "[comment `]");

  // Unclosed backticks
  // Instead of simply marking as CODE, it would be nice to have an
  // incomplete flag for CODE, that is styled slightly different.
  MT("unclosedBackticks",
     "foo [comment `bar]");

  // Per documentation: "To include a literal backtick character within a
  // code span, you can use multiple backticks as the opening and closing
  // delimiters"
  MT("doubleBackticks",
     "[comment ``foo ` bar``]");

  // Tests based on Dingus
  // http://daringfireball.net/projects/markdown/dingus
  //
  // Multiple backticks within an inline code block
  MT("consecutiveBackticks",
     "[comment `foo```bar`]");

  // Multiple backticks within an inline code block with a second code block
  MT("consecutiveBackticks",
     "[comment `foo```bar`] hello [comment `world`]");

  // Unclosed with several different groups of backticks
  MT("unclosedBackticks",
     "[comment ``foo ``` bar` hello]");

  // Closed with several different groups of backticks
  MT("closedBackticks",
     "[comment ``foo ``` bar` hello``] world");

  // info string cannot contain backtick, thus should result in inline code
  MT("closingFencedMarksOnSameLine",
     "[comment ``` code ```] foo");

  // atx headers
  // http://daringfireball.net/projects/markdown/syntax#header

  MT("atxH1",
     "[header&header-1 # foo]");

  MT("atxH2",
     "[header&header-2 ## foo]");

  MT("atxH3",
     "[header&header-3 ### foo]");

  MT("atxH4",
     "[header&header-4 #### foo]");

  MT("atxH5",
     "[header&header-5 ##### foo]");

  MT("atxH6",
     "[header&header-6 ###### foo]");

  // http://spec.commonmark.org/0.19/#example-24
  MT("noAtxH7",
     "####### foo");

  // http://spec.commonmark.org/0.19/#example-25
  MT("noAtxH1WithoutSpace",
     "#5 bolt");

  // CommonMark requires a space after # but most parsers don't
  AtxNoSpaceTest("atxNoSpaceAllowed_H1NoSpace",
     "[header&header-1 #foo]");

  AtxNoSpaceTest("atxNoSpaceAllowed_H4NoSpace",
     "[header&header-4 ####foo]");

  AtxNoSpaceTest("atxNoSpaceAllowed_H1Space",
     "[header&header-1 # foo]");

  // Inline styles should be parsed inside headers
  MT("atxH1inline",
     "[header&header-1 # foo ][header&header-1&em *bar*]");

  MT("atxIndentedTooMuch",
     "[header&header-1 # foo]",
     "    [comment # bar]");

  // disable atx inside blockquote until we implement proper blockquote inner mode
  // TODO: fix to be CommonMark-compliant
  MT("atxNestedInsideBlockquote",
     "[quote&quote-1 > # foo]");

  MT("atxAfterBlockquote",
     "[quote&quote-1 > foo]",
     "[header&header-1 # bar]");

  // Setext headers - H1, H2
  // Per documentation, "Any number of underlining =’s or -’s will work."
  // http://daringfireball.net/projects/markdown/syntax#header
  // Ideally, the text would be marked as `header` as well, but this is
  // not really feasible at the moment. So, instead, we're testing against
  // what works today, to avoid any regressions.
  //
  // Check if single underlining = works
  MT("setextH1",
     "[header&header-1 foo]",
     "[header&header-1 =]");

  // Check if 3+ ='s work
  MT("setextH1",
     "[header&header-1 foo]",
     "[header&header-1 ===]");

  // Check if single underlining - should not be interpreted
  // as it might lead to an empty list:
  // https://spec.commonmark.org/0.28/#setext-heading-underline
  MT("setextH2Single",
     "foo",
     "-");

  // Check if 3+ -'s work
  MT("setextH2",
     "[header&header-2 foo]",
     "[header&header-2 ---]");

  // http://spec.commonmark.org/0.19/#example-45
  MT("setextH2AllowSpaces",
     "[header&header-2 foo]",
     "   [header&header-2 ----      ]");

  // http://spec.commonmark.org/0.19/#example-44
  MT("noSetextAfterIndentedCodeBlock",
     "     [comment foo]",
     "[hr ---]");

  MT("setextAfterFencedCode",
     "[comment ```]",
     "[comment foo]",
     "[comment ```]",
     "[header&header-2 bar]",
     "[header&header-2 ---]");

  MT("setextAfterATX",
     "[header&header-1 # foo]",
     "[header&header-2 bar]",
     "[header&header-2 ---]");

  // http://spec.commonmark.org/0.19/#example-51
  MT("noSetextAfterQuote",
     "[quote&quote-1 > foo]",
     "[hr ---]",
     "",
     "[quote&quote-1 > foo]",
     "[quote&quote-1 bar]",
     "[hr ---]");

  MT("noSetextAfterList",
     "[variable-2 - foo]",
     "[hr ---]");

  MT("noSetextAfterList_listContinuation",
     "[variable-2 - foo]",
     "bar",
     "[hr ---]");

  MT("setextAfterList_afterIndentedCode",
     "[variable-2 - foo]",
     "",
     "      [comment bar]",
     "[header&header-2 baz]",
     "[header&header-2 ---]");

  MT("setextAfterList_afterFencedCodeBlocks",
     "[variable-2 - foo]",
     "",
     "      [comment ```]",
     "      [comment bar]",
     "      [comment ```]",
     "[header&header-2 baz]",
     "[header&header-2 ---]");

  MT("setextAfterList_afterHeader",
     "[variable-2 - foo]",
     "  [variable-2&header&header-1 # bar]",
     "[header&header-2 baz]",
     "[header&header-2 ---]");

  MT("setextAfterList_afterHr",
     "[variable-2 - foo]",
     "",
     "  [hr ---]",
     "[header&header-2 bar]",
     "[header&header-2 ---]");

  MT("setext_nestedInlineMarkup",
     "[header&header-1 foo ][em&header&header-1 *bar*]",
     "[header&header-1 =]");

  MT("setext_linkDef",
     "[link [[aaa]]:] [string&url http://google.com 'title']",
     "[hr ---]");

  // currently, looks max one line ahead, thus won't catch valid CommonMark
  //  markup
  MT("setext_oneLineLookahead",
     "foo",
     "[header&header-1 bar]",
     "[header&header-1 =]");

  // ensure we regard space after a single dash as a list
  MT("setext_emptyList",
     "foo",
     "[variable-2 - ]",
     "foo");

  // Single-line blockquote with trailing space
  MT("blockquoteSpace",
     "[quote&quote-1 > foo]");

  // Single-line blockquote
  MT("blockquoteNoSpace",
     "[quote&quote-1 >foo]");

  // No blank line before blockquote
  MT("blockquoteNoBlankLine",
     "foo",
     "[quote&quote-1 > bar]");

  MT("blockquoteNested",
     "[quote&quote-1 > foo]",
     "[quote&quote-1 >][quote&quote-2 > foo]",
     "[quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");

  // ensure quote-level is inferred correctly even if indented
  MT("blockquoteNestedIndented",
     " [quote&quote-1 > foo]",
     " [quote&quote-1 >][quote&quote-2 > foo]",
     " [quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");

  // ensure quote-level is inferred correctly even if indented
  MT("blockquoteIndentedTooMuch",
     "foo",
     "    > bar");

  // Single-line blockquote followed by normal paragraph
  MT("blockquoteThenParagraph",
     "[quote&quote-1 >foo]",
     "",
     "bar");

  // Multi-line blockquote (lazy mode)
  MT("multiBlockquoteLazy",
     "[quote&quote-1 >foo]",
     "[quote&quote-1 bar]");

  // Multi-line blockquote followed by normal paragraph (lazy mode)
  MT("multiBlockquoteLazyThenParagraph",
     "[quote&quote-1 >foo]",
     "[quote&quote-1 bar]",
     "",
     "hello");

  // Multi-line blockquote (non-lazy mode)
  MT("multiBlockquote",
     "[quote&quote-1 >foo]",
     "[quote&quote-1 >bar]");

  // Multi-line blockquote followed by normal paragraph (non-lazy mode)
  MT("multiBlockquoteThenParagraph",
     "[quote&quote-1 >foo]",
     "[quote&quote-1 >bar]",
     "",
     "hello");

  // disallow lists inside blockquote for now because it causes problems outside blockquote
  // TODO: fix to be CommonMark-compliant
  MT("listNestedInBlockquote",
     "[quote&quote-1 > - foo]");

  // disallow fenced blocks inside blockquote because it causes problems outside blockquote
  // TODO: fix to be CommonMark-compliant
  MT("fencedBlockNestedInBlockquote",
     "[quote&quote-1 > ```]",
     "[quote&quote-1 > code]",
     "[quote&quote-1 > ```]",
     // ensure we still allow inline code
     "[quote&quote-1 > ][quote&quote-1&comment `code`]");

  // Header with leading space after continued blockquote (#3287, negative indentation)
  MT("headerAfterContinuedBlockquote",
     "[quote&quote-1 > foo]",
     "[quote&quote-1 bar]",
     "",
     " [header&header-1 # hello]");

  // Check list types

  MT("listAsterisk",
     "foo",
     "bar",
     "",
     "[variable-2 * foo]",
     "[variable-2 * bar]");

  MT("listPlus",
     "foo",
     "bar",
     "",
     "[variable-2 + foo]",
     "[variable-2 + bar]");

  MT("listDash",
     "foo",
     "bar",
     "",
     "[variable-2 - foo]",
     "[variable-2 - bar]");

  MT("listNumber",
     "foo",
     "bar",
     "",
     "[variable-2 1. foo]",
     "[variable-2 2. bar]");

  MT("listFromParagraph",
     "foo",
     "[variable-2 1. bar]",
     "[variable-2 2. hello]");

  // List after hr
  MT("listAfterHr",
     "[hr ---]",
     "[variable-2 - bar]");

  // List after header
  MT("listAfterHeader",
     "[header&header-1 # foo]",
     "[variable-2 - bar]");

  // hr after list
  MT("hrAfterList",
     "[variable-2 - foo]",
     "[hr -----]");

  MT("hrAfterFencedCode",
     "[comment ```]",
     "[comment code]",
     "[comment ```]",
     "[hr ---]");

  // allow hr inside lists
  // (require prev line to be empty or hr, TODO: non-CommonMark-compliant)
  MT("hrInsideList",
     "[variable-2 - foo]",
     "",
     "  [hr ---]",
     "     [hr ---]",
     "",
     "      [comment ---]");

  MT("consecutiveHr",
     "[hr ---]",
     "[hr ---]",
     "[hr ---]");

  // Formatting in lists (*)
  MT("listAsteriskFormatting",
     "[variable-2 * ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 * ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 * ][variable-2&em&strong ***foo***][variable-2  bar]",
     "[variable-2 * ][variable-2&comment `foo`][variable-2  bar]");

  // Formatting in lists (+)
  MT("listPlusFormatting",
     "[variable-2 + ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 + ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 + ][variable-2&em&strong ***foo***][variable-2  bar]",
     "[variable-2 + ][variable-2&comment `foo`][variable-2  bar]");

  // Formatting in lists (-)
  MT("listDashFormatting",
     "[variable-2 - ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 - ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 - ][variable-2&em&strong ***foo***][variable-2  bar]",
     "[variable-2 - ][variable-2&comment `foo`][variable-2  bar]");

  // Formatting in lists (1.)
  MT("listNumberFormatting",
     "[variable-2 1. ][variable-2&em *foo*][variable-2  bar]",
     "[variable-2 2. ][variable-2&strong **foo**][variable-2  bar]",
     "[variable-2 3. ][variable-2&em&strong ***foo***][variable-2  bar]",
     "[variable-2 4. ][variable-2&comment `foo`][variable-2  bar]");

  // Paragraph lists
  MT("listParagraph",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]");

  // Multi-paragraph lists
  //
  // 4 spaces
  MT("listMultiParagraph",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "    [variable-2 hello]");

  // 4 spaces, extra blank lines (should still be list, per Dingus)
  MT("listMultiParagraphExtra",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "",
     "    [variable-2 hello]");

  // 4 spaces, plus 1 space (should still be list, per Dingus)
  MT("listMultiParagraphExtraSpace",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "     [variable-2 hello]",
     "",
     "    [variable-2 world]");

  // 1 tab
  MT("listTab",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "\t[variable-2 hello]");

  // No indent
  MT("listNoIndent",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "hello");

  MT("listCommonMarkIndentationCode",
     "[variable-2 * Code blocks also affect]",
     "  [variable-3 * The next level starts where the contents start.]",
     "   [variable-3 *    Anything less than that will keep the item on the same level.]",
     "       [variable-3 * Each list item can indent the first level further and further.]",
     "  [variable-3 * For the most part, this makes sense while writing a list.]",
     "    [keyword * This means two items with same indentation can be different levels.]",
     "     [keyword *  Each level has an indent requirement that can change between items.]",
     "       [keyword * A list item that meets this will be part of the next level.]",
     "   [variable-3 * Otherwise, it will be part of the level where it does meet this.]",
     " [variable-2 * World]");

  // should handle nested and un-nested lists
  MT("listCommonMark_MixedIndents",
     "[variable-2 * list1]",
     "    [variable-2 list1]",
     "  [variable-2&header&header-1 # heading still part of list1]",
     "  [variable-2 text after heading still part of list1]",
     "",
     "      [comment indented codeblock]",
     "  [variable-2 list1 after code block]",
     "  [variable-3 * list2]",
     // amount of spaces on empty lines between lists doesn't matter
     "              ",
     // extra empty lines irrelevant
     "",
     "",
     "    [variable-3 indented text part of list2]",
     "    [keyword * list3]",
     "",
     "    [variable-3 text at level of list2]",
     "",
     "  [variable-2 de-indented text part of list1 again]",
     "",
     "  [variable-2&comment ```]",
     "  [comment code]",
     "  [variable-2&comment ```]",
     "",
     "  [variable-2 text after fenced code]");

  // should correctly parse numbered list content indentation
  MT("listCommonMark_NumberedListIndent",
     "[variable-2 1000. list with base indent of 6]",
     "",
     "      [variable-2 text must be indented 6 spaces at minimum]",
     "",
     "         [variable-2 9-spaces indented text still part of list]",
     "",
     "          [comment indented codeblock starts at 10 spaces]",
     "",
     "     [comment text indented by 5 spaces no longer belong to list]");

  // should consider tab as 4 spaces
  MT("listCommonMark_TabIndented",
     "[variable-2 * list]",
     "\t[variable-3 * list2]",
     "",
     "\t\t[variable-3 part of list2]");

  MT("listAfterBlockquote",
     "[quote&quote-1 > foo]",
     "[variable-2 - bar]");

  // shouldn't create sublist if it's indented more than allowed
  MT("nestedListIndentedTooMuch",
     "[variable-2 - foo]",
     "          [variable-2 - bar]");

  MT("listIndentedTooMuchAfterParagraph",
     "foo",
     "    - bar");

  // Blockquote
  MT("blockquote",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "    [variable-2&quote&quote-1 > hello]");

  // Code block
  MT("blockquoteCode",
     "[variable-2 * foo]",
     "",
     "[variable-2 * bar]",
     "",
     "        [comment > hello]",
     "",
     "    [variable-2 world]");

  // Code block followed by text
  MT("blockquoteCodeText",
     "[variable-2 * foo]",
     "",
     "    [variable-2 bar]",
     "",
     "        [comment hello]",
     "",
     "    [variable-2 world]");

  // Nested list

  MT("listAsteriskNested",
     "[variable-2 * foo]",
     "",
     "    [variable-3 * bar]");

  MT("listPlusNested",
     "[variable-2 + foo]",
     "",
     "    [variable-3 + bar]");

  MT("listDashNested",
     "[variable-2 - foo]",
     "",
     "    [variable-3 - bar]");

  MT("listNumberNested",
     "[variable-2 1. foo]",
     "",
     "    [variable-3 2. bar]");

  MT("listMixed",
     "[variable-2 * foo]",
     "",
     "    [variable-3 + bar]",
     "",
     "        [keyword - hello]",
     "",
     "            [variable-2 1. world]");

  MT("listBlockquote",
     "[variable-2 * foo]",
     "",
     "    [variable-3 + bar]",
     "",
     "        [quote&quote-1&variable-3 > hello]");

  MT("listCode",
     "[variable-2 * foo]",
     "",
     "    [variable-3 + bar]",
     "",
     "            [comment hello]");

  // Code with internal indentation
  MT("listCodeIndentation",
     "[variable-2 * foo]",
     "",
     "        [comment bar]",
     "            [comment hello]",
     "                [comment world]",
     "        [comment foo]",
     "    [variable-2 bar]");

  // List nesting edge cases
  MT("listNested",
    "[variable-2 * foo]",
    "",
    "    [variable-3 * bar]",
    "",
    "       [variable-3 hello]"
  );
  MT("listNested",
    "[variable-2 * foo]",
    "",
    "    [variable-3 * bar]",
    "",
    "      [keyword * foo]"
  );

  // Code followed by text
  MT("listCodeText",
     "[variable-2 * foo]",
     "",
     "        [comment bar]",
     "",
     "hello");

  // Following tests directly from official Markdown documentation
  // http://daringfireball.net/projects/markdown/syntax#hr

  MT("hrSpace",
     "[hr * * *]");

  MT("hr",
     "[hr ***]");

  MT("hrLong",
     "[hr *****]");

  MT("hrSpaceDash",
     "[hr - - -]");

  MT("hrDashLong",
     "[hr ---------------------------------------]");

  //Images
  MT("Images",
     "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)]")

  //Images with highlight alt text
  MT("imageEm",
     "[image&image-marker !][image&image-alt-text&link [[][image-alt-text&em&image&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");

  MT("imageStrong",
     "[image&image-marker !][image&image-alt-text&link [[][image-alt-text&strong&image&link **alt text**][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");

  MT("imageEmStrong",
     "[image&image-marker !][image&image-alt-text&link [[][image&image-alt-text&em&strong&link ***alt text***][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");

  // Inline link with title
  MT("linkTitle",
     "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");

  // Inline link without title
  MT("linkNoTitle",
     "[link [[foo]]][string&url (http://example.com/)] bar");

  // Inline link with image
  MT("linkImage",
     "[link [[][link&image&image-marker !][link&image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)][link ]]][string&url (http://example.com/)] bar");

  // Inline link with Em
  MT("linkEm",
     "[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar");

  // Inline link with Strong
  MT("linkStrong",
     "[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar");

  // Inline link with EmStrong
  MT("linkEmStrong",
     "[link [[][link&em&strong ***foo***][link ]]][string&url (http://example.com/)] bar");

  MT("multilineLink",
     "[link [[foo]",
     "[link bar]]][string&url (https://foo#_a)]",
     "should not be italics")

  // Image with title
  MT("imageTitle",
     "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/ \"bar\")] hello");

  // Image without title
  MT("imageNoTitle",
     "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/)] bar");

  // Image with asterisks
  MT("imageAsterisks",
     "[image&image-marker !][image&image-alt-text&link [[ ][image&image-alt-text&em&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)] bar");

  // Not a link. Should be normal text due to square brackets being used
  // regularly in text, especially in quoted material, and no space is allowed
  // between square brackets and parentheses (per Dingus).
  MT("notALink",
     "[link [[foo]]] (bar)");

  // Reference-style links
  MT("linkReference",
     "[link [[foo]]][string&url [[bar]]] hello");

  // Reference-style links with Em
  MT("linkReferenceEm",
     "[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello");

  // Reference-style links with Strong
  MT("linkReferenceStrong",
     "[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello");

  // Reference-style links with EmStrong
  MT("linkReferenceEmStrong",
     "[link [[][link&em&strong ***foo***][link ]]][string&url [[bar]]] hello");

  // Reference-style links with optional space separator (per documentation)
  // "You can optionally use a space to separate the sets of brackets"
  MT("linkReferenceSpace",
     "[link [[foo]]] [string&url [[bar]]] hello");

  // Should only allow a single space ("...use *a* space...")
  MT("linkReferenceDoubleSpace",
     "[link [[foo]]]  [link [[bar]]] hello");

  // Reference-style links with implicit link name
  MT("linkImplicit",
     "[link [[foo]]][string&url [[]]] hello");

  // @todo It would be nice if, at some point, the document was actually
  // checked to see if the referenced link exists

  // Link label, for reference-style links (taken from documentation)

  MT("labelNoTitle",
     "[link [[foo]]:] [string&url http://example.com/]");

  MT("labelIndented",
     "   [link [[foo]]:] [string&url http://example.com/]");

  MT("labelSpaceTitle",
     "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]");

  MT("labelDoubleTitle",
     "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\"");

  MT("labelTitleDoubleQuotes",
     "[link [[foo]]:] [string&url http://example.com/  \"bar\"]");

  MT("labelTitleSingleQuotes",
     "[link [[foo]]:] [string&url http://example.com/  'bar']");

  MT("labelTitleParentheses",
     "[link [[foo]]:] [string&url http://example.com/  (bar)]");

  MT("labelTitleInvalid",
     "[link [[foo]]:] [string&url http://example.com/] bar");

  MT("labelLinkAngleBrackets",
     "[link [[foo]]:] [string&url <http://example.com/>  \"bar\"]");

  MT("labelTitleNextDoubleQuotes",
     "[link [[foo]]:] [string&url http://example.com/]",
     "[string \"bar\"] hello");

  MT("labelTitleNextSingleQuotes",
     "[link [[foo]]:] [string&url http://example.com/]",
     "[string 'bar'] hello");

  MT("labelTitleNextParentheses",
     "[link [[foo]]:] [string&url http://example.com/]",
     "[string (bar)] hello");

  MT("labelTitleNextMixed",
     "[link [[foo]]:] [string&url http://example.com/]",
     "(bar\" hello");

  MT("labelEscape",
     "[link [[foo \\]] ]]:] [string&url http://example.com/]");

  MT("labelEscapeColon",
     "[link [[foo \\]]: bar]]:] [string&url http://example.com/]");

  MT("labelEscapeEnd",
     "\\[[foo\\]]: http://example.com/");

  MT("linkWeb",
     "[link <http://example.com/>] foo");

  MT("linkWebDouble",
     "[link <http://example.com/>] foo [link <http://example.com/>]");

  MT("linkEmail",
     "[link <user@example.com>] foo");

  MT("linkEmailDouble",
     "[link <user@example.com>] foo [link <user@example.com>]");

  MT("emAsterisk",
     "[em *foo*] bar");

  MT("emUnderscore",
     "[em _foo_] bar");

  MT("emInWordAsterisk",
     "foo[em *bar*]hello");

  MT("emInWordUnderscore",
     "foo_bar_hello");

  // Per documentation: "...surround an * or _ with spaces, it’ll be
  // treated as a literal asterisk or underscore."

  MT("emEscapedBySpaceIn",
     "foo [em _bar _ hello_] world");

  MT("emEscapedBySpaceOut",
     "foo _ bar [em _hello_] world");

  MT("emEscapedByNewline",
     "foo",
     "_ bar [em _hello_] world");

  // Unclosed emphasis characters
  // Instead of simply marking as EM / STRONG, it would be nice to have an
  // incomplete flag for EM and STRONG, that is styled slightly different.
  MT("emIncompleteAsterisk",
     "foo [em *bar]");

  MT("emIncompleteUnderscore",
     "foo [em _bar]");

  MT("strongAsterisk",
     "[strong **foo**] bar");

  MT("strongUnderscore",
     "[strong __foo__] bar");

  MT("emStrongAsterisk",
     "[em *foo][em&strong **bar*][strong hello**] world");

  MT("emStrongUnderscore",
     "[em _foo ][em&strong __bar_][strong  hello__] world");

  // "...same character must be used to open and close an emphasis span.""
  MT("emStrongMixed",
     "[em _foo][em&strong **bar*hello__ world]");

  MT("emStrongMixed",
     "[em *foo ][em&strong __bar_hello** world]");

  MT("linkWithNestedParens",
     "[link [[foo]]][string&url (bar(baz))]")

  // These characters should be escaped:
  // \   backslash
  // `   backtick
  // *   asterisk
  // _   underscore
  // {}  curly braces
  // []  square brackets
  // ()  parentheses
  // #   hash mark
  // +   plus sign
  // -   minus sign (hyphen)
  // .   dot
  // !   exclamation mark

  MT("escapeBacktick",
     "foo \\`bar\\`");

  MT("doubleEscapeBacktick",
     "foo \\\\[comment `bar\\\\`]");

  MT("escapeAsterisk",
     "foo \\*bar\\*");

  MT("doubleEscapeAsterisk",
     "foo \\\\[em *bar\\\\*]");

  MT("escapeUnderscore",
     "foo \\_bar\\_");

  MT("doubleEscapeUnderscore",
     "foo \\\\[em _bar\\\\_]");

  MT("escapeHash",
     "\\# foo");

  MT("doubleEscapeHash",
     "\\\\# foo");

  MT("escapeNewline",
     "\\",
     "[em *foo*]");

  // Class override tests
  TokenTypeOverrideTest("overrideHeader1",
    "[override-header&override-header-1 # Foo]");

  TokenTypeOverrideTest("overrideHeader2",
    "[override-header&override-header-2 ## Foo]");

  TokenTypeOverrideTest("overrideHeader3",
    "[override-header&override-header-3 ### Foo]");

  TokenTypeOverrideTest("overrideHeader4",
    "[override-header&override-header-4 #### Foo]");

  TokenTypeOverrideTest("overrideHeader5",
    "[override-header&override-header-5 ##### Foo]");

  TokenTypeOverrideTest("overrideHeader6",
    "[override-header&override-header-6 ###### Foo]");

  TokenTypeOverrideTest("overrideCode",
    "[override-code `foo`]");

  TokenTypeOverrideTest("overrideCodeBlock",
    "[override-code ```]",
    "[override-code foo]",
    "[override-code ```]");

  TokenTypeOverrideTest("overrideQuote",
    "[override-quote&override-quote-1 > foo]",
    "[override-quote&override-quote-1 > bar]");

  TokenTypeOverrideTest("overrideQuoteNested",
    "[override-quote&override-quote-1 > foo]",
    "[override-quote&override-quote-1 >][override-quote&override-quote-2 > bar]",
    "[override-quote&override-quote-1 >][override-quote&override-quote-2 >][override-quote&override-quote-3 > baz]");

  TokenTypeOverrideTest("overrideLists",
    "[override-list1 - foo]",
    "",
    "    [override-list2 + bar]",
    "",
    "        [override-list3 * baz]",
    "",
    "            [override-list1 1. qux]",
    "",
    "                [override-list2 - quux]");

  TokenTypeOverrideTest("overrideHr",
    "[override-hr * * *]");

  TokenTypeOverrideTest("overrideImage",
    "[override-image&override-image-marker !][override-image&override-image-alt-text&link [[alt text]]][override-link-href&url (http://link.to/image.jpg)]");

  TokenTypeOverrideTest("overrideLinkText",
    "[override-link-text [[foo]]][override-link-href&url (http://example.com)]");

  TokenTypeOverrideTest("overrideLinkEmailAndInline",
    "[override-link-email <][override-link-inline foo@example.com>]");

  TokenTypeOverrideTest("overrideEm",
    "[override-em *foo*]");

  TokenTypeOverrideTest("overrideStrong",
    "[override-strong **foo**]");

  TokenTypeOverrideTest("overrideStrikethrough",
    "[override-strikethrough ~~foo~~]");

  TokenTypeOverrideTest("overrideEmoji",
    "[override-emoji :foo:]");

  FormatTokenTypeOverrideTest("overrideFormatting",
    "[override-formatting-escape \\*]");

  // Tests to make sure GFM-specific things aren't getting through

  MT("taskList",
     "[variable-2 * ][link&variable-2 [[ ]]][variable-2 bar]");

  MT("fencedCodeBlocks",
     "[comment ```]",
     "[comment foo]",
     "",
     "[comment bar]",
     "[comment ```]",
     "baz");

  MT("fencedCodeBlocks_invalidClosingFence_trailingText",
     "[comment ```]",
     "[comment foo]",
     "[comment ``` must not have trailing text]",
     "[comment baz]");

  MT("fencedCodeBlocks_invalidClosingFence_trailingTabs",
     "[comment ```]",
     "[comment foo]",
     "[comment ```\t]",
     "[comment baz]");

  MT("fencedCodeBlocks_validClosingFence",
     "[comment ```]",
     "[comment foo]",
     // may have trailing spaces
     "[comment ```     ]",
     "baz");

  MT("fencedCodeBlocksInList_closingFenceIndented",
     "[variable-2 - list]",
     "    [variable-2&comment ```]",
     "    [comment foo]",
     "     [variable-2&comment ```]",
     "    [variable-2 baz]");

  MT("fencedCodeBlocksInList_closingFenceIndentedTooMuch",
     "[variable-2 - list]",
     "    [variable-2&comment ```]",
     "    [comment foo]",
     "      [comment ```]",
     "    [comment baz]");

  MT("fencedCodeBlockModeSwitching",
     "[comment ```javascript]",
     "[variable foo]",
     "",
     "[comment ```]",
     "bar");

  MT_noFencedHighlight("fencedCodeBlock_noHighlight",
     "[comment ```javascript]",
     "[comment foo]",
     "[comment ```]");

  MT("fencedCodeBlockModeSwitchingObjc",
     "[comment ```objective-c]",
     "[keyword @property] [variable NSString] [operator *] [variable foo];",
     "[comment ```]",
     "bar");

  MT("fencedCodeBlocksMultipleChars",
     "[comment `````]",
     "[comment foo]",
     "[comment ```]",
     "[comment foo]",
     "[comment `````]",
     "bar");

  MT("fencedCodeBlocksTildes",
     "[comment ~~~]",
     "[comment foo]",
     "[comment ~~~]",
     "bar");

  MT("fencedCodeBlocksTildesMultipleChars",
     "[comment ~~~~~]",
     "[comment ~~~]",
     "[comment foo]",
     "[comment ~~~~~]",
     "bar");

  MT("fencedCodeBlocksMultipleChars",
     "[comment `````]",
     "[comment foo]",
     "[comment ```]",
     "[comment foo]",
     "[comment `````]",
     "bar");

  MT("fencedCodeBlocksMixed",
     "[comment ~~~]",
     "[comment ```]",
     "[comment foo]",
     "[comment ~~~]",
     "bar");

  MT("fencedCodeBlocksAfterBlockquote",
     "[quote&quote-1 > foo]",
     "[comment ```]",
     "[comment bar]",
     "[comment ```]");

  // fencedCode indented too much should act as simple indentedCode
  //  (hence has no highlight formatting)
  FT("tooMuchIndentedFencedCode",
     "    [comment ```]",
     "    [comment code]",
     "    [comment ```]");

  MT("autoTerminateFencedCodeWhenLeavingList",
     "[variable-2 - list1]",
     "  [variable-3 - list2]",
     "    [variable-3&comment ```]",
     "    [comment code]",
     "  [variable-3 - list2]",
     "  [variable-2&comment ```]",
     "  [comment code]",
     "[quote&quote-1 > foo]");

  // Tests that require XML mode

  MT("xmlMode",
     "[tag&bracket <][tag div][tag&bracket >]",
     "  *foo*",
     "  [tag&bracket <][tag http://github.com][tag&bracket />]",
     "[tag&bracket </][tag div][tag&bracket >]",
     "[link <http://github.com/>]");

  MT("xmlModeWithMarkdownInside",
     "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
     "[em *foo*]",
     "[link <http://github.com/>]",
     "[tag </div>]",
     "[link <http://github.com/>]",
     "[tag&bracket <][tag div][tag&bracket >]",
     "[tag&bracket </][tag div][tag&bracket >]");

  MT("xmlModeLineBreakInTags",
     "[tag&bracket <][tag div] [attribute id]=[string \"1\"]",
     "     [attribute class]=[string \"sth\"][tag&bracket >]xxx",
     "[tag&bracket </][tag div][tag&bracket >]");

  MT("xmlModeCommentWithBlankLine",
     "[comment <!-- Hello]",
     "",
     "[comment World -->]");

  MT("xmlModeCDATA",
     "[atom <![CDATA[ Hello]",
     "",
     "[atom FooBar]",
     "[atom Test ]]]]>]");

  MT("xmlModePreprocessor",
     "[meta <?php] [meta echo '1234'; ?>]");

  MT_noXml("xmlHighlightDisabled",
     "<div>foo</div>");

  // Tests Emojis

  ET("emojiDefault",
    "[builtin :foobar:]");

  ET("emojiTable",
    " :--:");
})();
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!