---
#default rules shared among several speech rules
- name: default
  tag: math
  match: "."
  replace:
  - with:
      variables:
      - ClearSpeak_Fractions: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_Fractions='Auto', 'EndFrac', $ClearSpeak_Fractions)"
      - ClearSpeak_AbsoluteValue: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_AbsoluteValue='Auto', 'AbsEnd', $ClearSpeak_AbsoluteValue)"
      - ClearSpeak_Roots: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_Roots='Auto', 'RootEnd', $ClearSpeak_Roots)"
      - ClearSpeak_Matrix: "IfThenElse($Verbosity='Verbose' and $ClearSpeak_Matrix='Auto', 'EndMatrix', $ClearSpeak_Matrix)"

      - MatchingPause: false()
      # should be set at mtable level, but unknown intents make that impossible to know
      - IsColumnSilent: false()
      replace:
      - test:
          if: "$MathRate = 100"
          then: [x: "*"]
          else:
          - rate:
              value: "$MathRate"
              replace: [x: "*"]

- name: empty-mrow
  tag: mrow
  match: "not(*)"
  replace:
  - t: " " # say nothing -- placeholder

- name: default
  tag: mrow
  match: "."
  replace:
  - insert:
      nodes: "*"
      replace: [pause: auto]

- name: default
  tag: mn
  match: "."
  replace:
  - bookmark: "@id"
  - x: "translate(., $BlockSeparators, '')"   # remove digit block separators

- name: default
  tag: [mo, mtext]
  match: "."
  replace:
  - bookmark: "@id"
  - x: "text()"

- name: default
  tag: mi
  match: "."
  replace:
  - bookmark: "@id"
  - test:
    - if: "string-length(.) = 1 and text() != '_'"       # need unicode.tdl to kick in for single letter tokens
      then: [x: "text()"]
    - else_if: "@data-chem-element"                      # NavMode=Character needs this
      then: [spell: "text()", pause: "short"]
      else: [x: "translate(., '-_\u00A0', '  ')"]   # from intent literals or from extra spaces added (which get deleted)

- name: default
  tag: ms
  match: "."
  replace:
  - t: "the string"      # phrase('the string' is long)
  - pause: short
  - x: "text()"

- name: default
  tag: mstyle
  match: "."
  replace: [x: "*"]


- name: literal-simple
  # don't include nested fractions. E.g, fraction a plus b over c + 1 end fraction" is ambiguous
  # by simplistic SimpleSpeak's rules "b over c" is a fraction, but if we say nested fractions
  # are never simple, then any 'over' applies only to enclosing "fraction...end fraction" pair.
  tag: mfrac
  match:
  - "(IsNode(*[1],'leaf') and IsNode(*[2],'leaf')) and"
  - "not(ancestor::*[name() != 'mrow'][1]/self::m:fraction)" # FIX: can't test for mrow -- what should be used???
  replace:
  - x: "*[1]"
  - t: "over"               # phrase("the fraction x 'over' y")
  - x: "*[2]"
  - pause: short

- name: literal-default
  tag: mfrac
  match: "."
  replace:
  - t: "start"              # phrase("'start'  fraction x over y end of fraction")
  - pause: short
  - x: "*[1]"
  - test:
      if: "not(IsNode(*[1],'leaf'))"
      then: [pause: short]
  - t: "over"               # phrase("the fraction x 'over' y")
  - test:
      if: "not(IsNode(*[2],'leaf'))"
      then: [pause: short]
  - x: "*[2]"
  - pause: short
  - test:
      if: "$Impairment = 'Blindness'"
      then: [t: "end over"]          # phrase("start of fraction x over y 'end over'")
  - pause: medium


# not sure what really should be said for these since we should not assume they are square roots
- name: literal-default
  tag: msqrt
  match: "."
  replace:
  - test:
      if: "$Verbosity!='Terse'"
      then: [t: "the"]    # phrase("'the' root of x")
  - t: "root"
  - test:
      if: "$Verbosity!='Terse'"
      then: [t: "of"]    # phrase("the root 'of' x")
  - x: "*[1]"
  - pause: short
  - test:
      if: "not(IsNode(*[1],'leaf')) or $Impairment = 'Blindness'"
      then: [t: "end root"] # phrase("root of x 'end root symbol'")

# not sure what really should be said for these since we should not assume they are square roots
- name: literal-default
  tag: mroot
  match: "."
  replace:
  - test:
      if: "$Verbosity!='Terse'"
      then: [t: "the"]   # phrase("'the' root of x")
  - t: "root with index" # phrase("the 'root with index' 3 of 5")
  - x: "*[1]"
  - pause: short
  - t: "of"              # phrase("the root 'of' x")
  - x: "*[2]"
  - pause: short
  - test:
      if: "not(IsNode(*[2],'leaf'))"
      then: [t: "end root symbol"] # phrase("root of x 'end root symbol'")


- name: simple-sub
  tag: indexed-by
  # invisible comma -- want "x 1 when subscript is an integer"
  match: "count(*)=2 and $Verbosity='Terse' and *[2][self::m:mn and translate(., '.,', '')=.]"
  replace:
  - x: "*[1]"
  - x: "*[2]"
  - pause: short

- name: no-end-sub
  tag: indexed-by
  match: "count(*)=2 and *[2][self::m:mrow and *[2][.='⁣']]"
  replace:
  - x: "*[1]"
  - t: "sub"               # phrase(x 'sub' 2)
  - x: "*[2]"
  - pause: short

# otherwise let definitions/default infix handle it

- name: literal
  tag: msub
  match: "."
  replace:
  - x: "*[1]"
  - test:
      if: "not($Verbosity='Terse' and *[2][self::m:mn and not(translate(., '.,', '')!=.)])"  # just say "x 1" for terse vs "x sub 1"
      then: [t: "sub"]      # phrase(x 'sub' 2)
  - x: "*[2]"


- name: literal
  tag: [msup, msubsup]
  match: "."
  replace:
  - x: "*[1]"
  - test:
      if: "name(.)='msubsup'"
      then:
      - t: "sub"          # phrase(x 'sub' 2)
      - x: "*[2]"
  - test:
      if: "*[last()][translate(., '′″‴⁗†‡°*', '')='']"
      then:  [x: "*[last()]"]
      else_test:
          if: "ancestor-or-self::*[contains(@data-intent-property, ':literal:')]"  # FIX: is this test necessary?
          then:
          - t: "super"      # phrase(x 'super' 2)
          - x: "*[last()]"
          - test:
              if: "not(IsNode(*[last()], 'simple')) or $Impairment = 'Blindness'"
              then: [t: "end super"]      # phrase(x super 2 'end of super')
          else:
          - test:
              if: "$Verbosity='Verbose'"
              then: [t: "superscript"]
              else: [t: "super"]
          - x: "*[last()]"
          - test:
              if: "$Verbosity='Verbose'"
              then: [t: "end superscript"]
              else: [t: "end super"]

- name: default
  tag: munder
  match: "."
  replace:
  - test:
      if: "not(IsNode(*[1], 'leaf'))"
      then: [t: "quantity"]      # phrase(phrase(x 'quantity' with y above it)
  - x: "*[1]"
  - t: "with"      # phrase(x 'with' z below it)
  - x: "*[2]"
  - t: "below"      # phrase(x with z 'below' it)

- name: diacriticals
  tag: mover
  match: "*[1][self::m:mi] and *[2][translate(., '\u0306\u030c.\u00A8\u02D9\u20DB\u20DC`^ˇ~→¯_', '')='']"
  replace:
  - x: "*[1]"
  - x: "*[2]"

- name: default
  tag: mover
  match: "."
  replace:
  - test:
      if: "not(IsNode(*[1], 'leaf'))"
      then: [t: "quantity"]      # phrase(phrase(the 'quantity' x plus 1 with y above it)
  - x: "*[1]"
  - t: "with"         # phrase(x modified 'with' y above it)
  - x: "*[2]"
  - t: "above"        # phrase(x modified 'with' y above it)

- name: default
  tag: munderover
  match: "."
  replace:
  - test:
      if: "not(IsNode(*[1], 'leaf'))"
      then: [t: "quantity"]      # phrase(the 'quantity' x plus 1 with y above it)
  - x: "*[1]"
  - t: "with"         # phrase(x modified 'with' y above it)
  - x: "*[2]"
  - t: "below and"    # phrase(x modified with y 'below and' y above it)
  - x: "*[3]"
  - t: "above"        # phrase(x modified with y 'above' it)

- name: default
  #   Here we support up to 2 prescripts and up to 4 postscripts -- that should cover all reasonable cases
  #   If there are more, we just dump them out without regard to sup/super :-(
  # FIX: this could use more special cases 
  # There is (currently) no way in MathCAT to deal with n-ary arguments other than "all" ('*') or an individual entry ('*[1]').
  tag: mmultiscripts
  match: "."
  variables:
  # computing the number of postscripts is messy because of <mprescripts> being optionally present -- we use "mod" to get the count right
  - Prescripts: "m:mprescripts/following-sibling::*"
  - NumChildren: "count(*)" # need to stash this since the count is wrong inside '*[...]' below
  - Postscripts: "*[position()>1 and position() < (last() + ($NumChildren mod 2) -count($Prescripts))]"
  replace:
  - x: "*[1]"
  - test:
      if: "$Prescripts" # more common case
      then:
      - with:
          variables:
          - PreSubscript: "IfThenElse($Verbosity='Verbose', 'pre subscript', 'pre sub')"
          - PreSuperscript: "IfThenElse($Verbosity='Verbose', 'pre superscript', 'pre super')"
          replace:
          - test: # only bother announcing if there is more than one prescript
              if: "count($Prescripts) > 2"
              then:
              - t: "with"      # phrase(substitute x 'with' y)
              - x: "count($Prescripts) div 2"
              - t: "prescripts"      # phrase(in this equation certain 'prescripts' apply)
              - pause: short
          - test:
              if: "not($Prescripts[1][self::m:none])"
              then:
              - x: "$PreSubscript"
              - x: "$Prescripts[1]"
          - test:
              if: "not($Prescripts[1][self::m:none] or $Prescripts[2][self::m:none])"
              then: [t: "and"]      # phrase(10 is greater than 8 'and' less than 15)
          - test:
              if: "not($Prescripts[2][self::m:none])"
              then:
              - x: "$PreSuperscript"
              - x: "$Prescripts[2]"
          - pause: short
          - test:
              if: "count($Prescripts) > 2" # more common case
              then:
              - test:
                  if: "not($Prescripts[3][self::m:none])"
                  then:
                  - x: "$PreSubscript"
                  - x: "$Prescripts[3]"
              - test:
                  if: "not($Prescripts[3][self::m:none] or $Prescripts[4][self::m:none])"
                  then: [t: "and"]      # phrase(10 is grater than 8 'and' less than 15)
              - test:
                  if: "not($Prescripts[4][self::m:none])"
                  then:
                  - x: "$PreSuperscript"
                  - x: "$Prescripts[4]"
              - test:
                  if: "count($Prescripts) > 4" # give up and just dump them out so at least the content is there
                  then:
                  - t: "and alternating prescripts"      # phrase(in this case there are values 'and alternating prescripts')
                  - x: "$Prescripts[position() > 4]"
                  - t: "end prescripts"      # phrase(This is where 'end prescripts' occurs)
  - test:
      if: "$Postscripts"
      then:
      - with:
          variables:
          - PostSubscript: "IfThenElse($Verbosity='Verbose', 'subscript', 'sub')"
          - PostSuperscript: "IfThenElse($Verbosity='Verbose', 'superscript', 'super')"
          replace:
          - test: # only bother announcing if there is more than one postscript
              if: "count($Postscripts) > 2"
              then:
              - test:
                  if: "$Prescripts"
                  then: [t: "and"]      # phrase(10 is greater than 8 'and' less than 15)
              - t: "with"      # phrase(substitute x 'with' y)
              - x: "count($Postscripts) div 2"
              - t: "postscripts"      # phrase(this material includes several 'postscripts')
              - pause: short
          - test:
              if: "not($Postscripts[1][self::m:none])"
              then:
              - x: "$PostSubscript"
              - x: "$Postscripts[1]"
          - test:
              if: "not($Postscripts[1][self::m:none] or $Postscripts[2][self::m:none])"
              then: [t: "and"]      # phrase(10 is greater than 8 'and' less than 15)
          - test:
              if: "not($Postscripts[2][self::m:none])"
              then:
              - x: "$PostSuperscript"
              - x: "$Postscripts[2]"
          - test:
              if: "count($Postscripts) > 2"
              then:
              - test:
                  if: "not($Postscripts[3][self::m:none])"
                  then:
                  - x: "$PostSubscript"
                  - x: "$Postscripts[3]"
              - test:
                  if: "not($Postscripts[3][self::m:none] or $Postscripts[4][self::m:none])"
                  then: [t: "and"]      # phrase(10 is greater than 8 'and' less than 15)
              - test:
                  if: "not($Postscripts[4][self::m:none])"
                  then:
                  - x: "$PostSuperscript"
                  - x: "$Postscripts[4]"
              - test:
                  if: "count($Postscripts) > 4"
                  then:
                  - test:
                      if: "not($Postscripts[5][self::m:none])"
                      then:
                      - x: "$PostSubscript"
                      - x: "$Postscripts[5]"
                  - test:
                      if: "not($Postscripts[5][self::m:none] or $Postscripts[6][self::m:none])"
                      then: [t: "and"]      # phrase(10 is greater than 8 'and' less than 15)
                  - test:
                      if: "not($Postscripts[6][self::m:none])"
                      then:
                      - x: "$PostSuperscript"
                      - x: "$Postscripts[6]"
                  - test:
                      if: "count($Postscripts) > 6"
                      then:
                      - test:
                          if: "not($Postscripts[7][self::m:none])"
                          then:
                          - x: "$PostSubscript"
                          - x: "$Postscripts[7]"
                      - test:
                          if: "not($Postscripts[7][self::m:none] or $Postscripts[8][self::m:none])"
                          then: [t: "and"]      # phrase(10 is less than 15 'and' greater than 5)
                      - test:
                          if: "not($Postscripts[8][self::m:none])"
                          then:
                          - x: "$PostSuperscript"
                          - x: "$Postscripts[8]"
                      - test:
                          if: "count($Postscripts) > 8" # give up and just dump them out so at least the content is there
                          then:
                          - t: "and alternating scripts"      # phrase(this situation involves complexities 'and alternating scripts')
                          - x: "$Postscripts[position() > 8]"
                          - t: "end scripts"      # phrase(At this point 'end scripts' occurs)

- name: default
  tag: mtable
  variables:
  - IsColumnSilent: "false()"
  - NumColumns: "count(*[1]/*) - IfThenElse(*/self::m:mlabeledtr, 1, 0)"
  match: "."
  replace:
  - t: "table with"      # phrase(the 'table with' 3 rows)
  - x: count(*)
  - test:
      if: count(*)=1
      then: [t: "row"]      # phrase(the table with 1 'row')
      else: [t: "rows"]      # phrase(the table with 3 'rows')
  - t: "and"      # phrase(the table with 3 rows 'and' 4 columns)
  - x: "$NumColumns"
  - test:
      if: "NumColumns=1"
      then: [t: "column"]      # phrase(the table with 3 rows and 1 'column')
      else: [t: "columns"]      # phrase(the table with 3 rows and 4 'columns')
  - pause: long
  - x: "*"

- name: default
  # callers/context should do that.
  # this may get called from navigation -- in that case, there is no context to speak the row #, so don't do it
  tag: [mtr, mlabeledtr]
  match: "."
  replace:
  - pause: medium
  - t: "row"      # phrase(the first 'row' of a matrix)
  - x: "count(preceding-sibling::*)+1"
  - test:
      if: "self::m:mlabeledtr"
      then:
      - t: "with label"      # phrase(the line 'with label' first equation)
      - x: "*[1]/*"
      - pause: short
  - pause: medium
  - test:
      if: "self::m:mlabeledtr"
      then: [x: "*[position()>1]"]
      else: {x: "*"}

- name: default
  tag: mtd
  match: "."
  replace:
  - test:
      #  ClearSpeak normally speaks "column 1" even though it says the row number, which is a waste...
      #  The following is commented out but the count(...)!=0 probably belongs in other rule sets
      #   if: not($IsColumnSilent) and ($ClearSpeak_Matrix = 'SpeakColNum' or count(preceding-sibling::*) != 0)
      if: "not($IsColumnSilent)"
      then:
      - t: "column"      # phrase(the first 'column' of the matrix)
      - x: "count(preceding-sibling::*)+IfThenElse(parent::m:mlabeledtr, 0, 1)"
      - pause: medium
  - x: "*"
  - test:
    # short pause after each element; medium pause if last element in a row; long pause for last element in matrix
    - if: count(following-sibling::*) > 0
      then: [pause: short]
    - else_if: count(../following-sibling::*) > 0
      then: [pause: medium]
      else: [pause: long]


- name: empty-box
  # The ordering below is the order in which words come out when there is more than one value
  # Note: @notation can contain more than one value
  tag: menclose
  match: "@notation='box' and *[self::m:mtext and .=' ']"
  replace:
  - t: "empty box"      # phrase(the 'empty box' contains no values)

- name: default
  # The ordering below is the order in which words come out when there is more than one value
  # Note: @notation can contain more than one value
  tag: menclose
  match: "."
  replace:
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' box ')]"
      then: [t: "box", pause: short]      # phrase(the 'box' around the expression)
  - test:
      if: ".[contains(@notation,'roundedbox')]"
      then: [t: "round box", pause: short]      # phrase(the 'round box' around the expression)
  - test:
      if: ".[contains(@notation,'circle')]"
      then: [t: "circle", pause: short]      # phrase(the 'circle' around the expression)
  - test:
      if: ".[ contains(concat(' ', normalize-space(@notation), ' '), ' left ') or contains(concat(' ', normalize-space(@notation), ' '), ' right ') or contains(@notation,'top') or contains(@notation,'bottom') ]"
      then:
      - t: "line on"      # phrase(draw a straight 'line' on the page)
      - test:
          if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' left ')]"
          then: [t: "left", pause: short]      # phrase(line on 'left' of the expression)
      - test:
          if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' right ')]"
          then: [t: "right", pause: short]      # phrase(line on 'right' of the expression)
      - test:
          if: ".[contains(@notation,'top')]"
          then: [t: "top", pause: short]      # phrase(line on 'top' of the expression)
      - test:
          if: ".[contains(@notation,'bottom')]"
          then: [t: "bottom", pause: short]      # phrase(line on the 'bottom' of the expression)
  - test:
      if: ".[ contains(@notation,'updiagonalstrike') or contains(@notation,'downdiagonalstrike') or contains(@notation,'verticalstrike') or contains(@notation,'horizontalstrike') ]"
      then:
      - test:
          if: ".[contains(@notation,'updiagonalstrike') and contains(@notation,'downdiagonalstrike')]"
          then: [spell: "'x'", pause: short] # seems better to say 'x cross out' than 'up diagonal, down diagonal cross out'
          else:
          - test:
              if: ".[contains(@notation,'updiagonalstrike')]"
              then: [t: "up diagonal", pause: short]      # phrase(the line runs 'up diagonal')
          - test:
              if: ".[contains(@notation,'downdiagonalstrike')]"
              then: [t: "down diagonal", pause: short]      # phrase(the line runs 'down diagonal')
      - test:
          if: ".[contains(@notation,'verticalstrike')]"
          then: [t: "vertical", pause: short]      # phrase(the line is  'vertical')
      - test:
          if: ".[contains(@notation,'horizontalstrike')]"
          then: [t: "horizontal", pause: short]      # phrase(the line is 'horizontal')
      - t: "cross out"      # phrase(please 'cross out' the incorrect answer)
      - pause: short
  - test:
      if: ".[contains(@notation,'uparrow')]"
      then: [t: "up arrow", pause: short]      # phrase(direction is shown by the 'up arrow')
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' downarrow ')]"
      then: [t: "down arrow", pause: short]      # phrase(the trend is shown by the 'down arrow')
  - test:
      if: ".[contains(@notation,'leftarrow')]"
      then: [t: "left arrow", pause: short]      # phrase(the 'left arrow' indicates going back)
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' rightarrow ')]"
      then: [t: "right arrow", pause: short]      # phrase(the 'right arrow' indicates moving forward)
  - test:
      if: ".[contains(@notation,'northeastarrow')]"
      then: [t: "northeast arrow", pause: short]      # phrase(direction is indicated by the 'northeast arrow')
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' southeastarrow ')]"
      then: [t: "southeast arrow", pause: short]      # phrase(direction is shown by the 'southeast arrow')
  - test:
      if: ".[contains(concat(' ', normalize-space(@notation), ' '), ' southwestarrow ')]"
      then: [t: "southwest arrow", pause: short]      # phrase(direction is shown by the 'southwest arrow')
  - test:
      if: ".[contains(@notation,'northwestarrow')]"
      then: [t: "northwest arrow", pause: short]      # phrase(direction is shown by the 'northwest arrow')
  - test:
      if: ".[contains(@notation,'updownarrow')]"
      then: [t: "double ended vertical arrow", pause: short]      # phrase(upward movement is indicated by the 'double ended vertical arrow')
  - test:
      if: ".[contains(@notation,'leftrightarrow')]"
      then: [t: "double ended horizontal arrow", pause: short]      # phrase(progress is indicated by the 'double ended horizontal arrow')
  - test:
      if: ".[contains(@notation,'northeastsouthwestarrow')]"
      then: [t: "double ended up diagonal arrow", pause: short]      # phrase(trend is indicated by the 'double ended up diagonal arrow')
  - test:
      if: ".[contains(@notation,'northwestsoutheastarrow')]"
      then: [t: "double ended down diagonal arrow", pause: short]      # phrase(trend is indicated by the 'double ended down diagonal arrow')
  - test:
      if: ".[contains(@notation,'actuarial')]"
      then: [t: "actuarial symbol", pause: short]      # phrase(the 'actuarial symbol' represents a specific quantity)
  - test:
      if: ".[contains(@notation,'madrub')]"
      then: [t: "arabic factorial symbol", pause: short]      # phrase(the 'arabic factorial symbol' represents a factorial operation)
  - test:
      if: ".[contains(@notation,'phasorangle')]"
      then: [t: "phasor angle", pause: short]      # phrase(the 'phasor angle' is used to measure electrical current)
  - test:
      if: ".[contains(@notation,'longdiv') or not(@notation) or normalize-space(@notation) ='']" # default
      then: [t: "long division symbol", pause: short]      # phrase(the 'long division symbol' indicates  a long division calculation)
  - test:
      if: ".[contains(@notation,'radical')]"
      then: [t: "square root", pause: short]      # phrase(5 is the 'square root' of 25)
  - t: "enclosing"      # phrase(parentheses are 'enclosing' part of the equation)
  - test:
      if: "*[self::m:mtext and .=' ']"
      then: [t: "space"]     # otherwise there is complete silence      # phrase(there is a 'space' between the words)
      else: [x: "*"]
  - test:
      if: "$Impairment = 'Blindness' and ( $SpeechStyle != 'SimpleSpeak' or not(IsNode(*[1], 'leaf')) )"
      then: [t: "end enclosure"]      # phrase(reached the 'end enclosure' point)
  - pause: short

- name: semantics
  tag: "semantics"
  match: "*[@encoding='MathML-Presentation']"
  replace:
  - x: "*[@encoding='MathML-Presentation']/*[1]"

- name: semantics-default
  tag: "semantics"
  match: .
  replace:
  - x: "*[1]"

- name: apply-function
  tag: "apply-function"
  match: .
  replace:
  - x: "*[1]"
  - t: "applied to"      # phrase(the function sine 'applied to' x plus y)
  - x: "*[2]"


# Here are the intent hints that need to be handled: 'prefix' | 'infix' | 'postfix' | 'function' | 'silent'
- name: silent-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':silent:')"
  replace:
  - x: "*"
  - test:
      if: "IsNode(., '2D')"
      then: [pause: short]
      else: [pause: auto]

- name: prefix-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':prefix:')"
  replace:
  - x: "SpeakIntentName(name(.), $Verbosity, 'prefix')"
  - x: "*"
  - test:
      if: "not( IsBracketed(., '', '') or IsNode(*[last()], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'prefix', 'end')"]
  - test:
      if: "IsNode(., '2D')"
      then: [pause: short]
      else: [pause: auto]

- name: postfix-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':postfix:')"
  replace:
  - test:
      if: "$Impairment = 'Blindness' and not( IsBracketed(., '', '') or IsNode(*[1], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'postfix', 'start')"]
  - x: "*"
  - x: "SpeakIntentName(name(.), $Verbosity, 'postfix')"

- name: infix-intent
  # uncaught intent -- the args have been inserted in the order of speech 
  tag: "*"
  match: "count(*)>0 and contains(@data-intent-property, ':infix:')"
  replace:
  - test:
      if: "$Impairment = 'Blindness' and not( IsBracketed(., '', '') or IsNode(*[1], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'infix', 'start')"]
  - test:
      if: "count(*) = 1"  # in cases such as continued-row, plus/minus might have just one child
      then:
      - x: "SpeakIntentName(name(.), $Verbosity, 'infix')"
      - pause: auto
      - x: "*[1]"
      else:
      - insert:
          nodes: "*"
          replace: [x: "SpeakIntentName(name(.), $Verbosity, 'infix')", pause: auto]
  - test:
      if: "$Impairment = 'Blindness' and not( IsBracketed(., '', '') or IsNode(*[last()], 'simple') )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'infix', 'end')"]
  - test:
      if: "IsNode(., '2D')"   # add (probably) a slightly longer pause if this came from a 2D node
      then: [pause: short]
      else: [pause: auto]

- name: function-intent
  # uncaught intent -- speak as foo of arg1 comma arg2 .... The MathML spec requires arguments to functions
  tag: "*"
  match: "count(*)>0"
  replace:
  - x: "SpeakIntentName(name(.), $Verbosity, 'function')"
  - test:
      if: "$Verbosity != 'Terse' and not(contains(@data-intent-property, ':literal:')) and
           not(count(*)=2 and (IsInDefinition(*[1], 'TrigFunctionNames') or IsInDefinition(name(.), 'TerseFunctionNames')) and IsNode(*[2], 'simple'))"
      then: [t: "of", pause: auto]      # phrase(sine 'of' 5)
  - insert:
      nodes: "*"
      replace:
      - test:
          if: "not(contains(@data-intent-property, ':literal:'))"
          then: [x: "','"]
      - pause: auto
  - test:
      # speak "end ..." if not bracketed or last child is not simple and not last node
      if: "$Impairment = 'Blindness' and not(*[last()][IsBracketed(., '', '') or IsNode(., 'simple')] )"
      then: [x: "GetBracketingIntentName(name(.), $Verbosity, 'function', 'end')"]
  - test:
      if: "IsNode(., '2D')"
      then: [pause: short]
      else: [pause: auto]


- name: default-text
  # unknown leaf -- just speak the text -- could be a literal intent
  tag: "*"
  match: "."
  replace:
  - x: "translate(name(), '-_', ' ')"
