Advertisement
rccharles

ASC adjust clipboard June 1, 2019

Jun 1st, 2019
1,125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (*
  2.  
  3.   This applescript converts clipboard input into a format suited for pasting into an ASC
  4.   reply.  I observed that my copies into an ASC reply were not formated that well.  
  5.   I observed that copies from a web browser were formated much better.  I went about
  6.    adjusting the clipboard copy to the format expected by a web browser for best results.
  7.  
  8.  This applescript accepts the clipboard in either
  9.  -- plain text upon which the text is converted to HTML.  Conversion is limitted to inserting paragraph tags for blank lines and inserting links where http or https text appears. The page title is substituted for the link.  
  10.  -- HTML source code identified by text containing HTML markup.  
  11.          Caveat emptor.  
  12.  
  13. run with copy from Waterfox. List of main routines.
  14.   --- run ---
  15.   --- common ---
  16.   --- adjustCharacters() ---
  17.   --- adjustBrowserHTML ---
  18.   --- adjustURLs ---
  19.   --- adjustToAscHtml ---
  20.   --- adjustLF() ---
  21.   --- convertToHTML ---
  22.  
  23. run with HTML as text from TextWrangler. List of main routines.
  24.   --- run ---
  25.   --- common ---
  26.   --- adjustCharacters() ---
  27.   --- adjustBrowserHTML ---
  28.   --- adjustURLs ---
  29.   --- adjustToAscHtml ---
  30.   --- adjustLF() ---
  31.   --- chompLeftAndTag ---
  32.   --- chompLeftAndTag ---
  33.   --- adjustLF() ---
  34.   --- chompLeftAndTag ---
  35.   --- chompLeftAndTag ---
  36.   --- adjustLF() ---
  37.   --- convertToHTML
  38.  
  39. run with plain text from TextWrangler. List of main routines
  40.   --- run ---
  41.   --- common ---
  42.   --- adjustCharacters ---
  43.   --- adjustURLs ---
  44.   --- chompLeftAndTag ---
  45.   --- chompLeftAndTag ---
  46.   --- chompLeftAndTag ---
  47.   --- chompLeftAndTag ---
  48.   --- addParagraphs ---
  49.   --- convertToHTML ---
  50.  
  51.  to use:
  52.  1) copy command + c what data you want to convert
  53.  2) run this applascript by double clicking on the app.
  54.  3) paste command + V into an ASC reply
  55.  
  56.  I have tested in Waterfox 56.2.9 in Yosemite.  I assume the process will work with other web browsers and other versions of macOS.
  57.  
  58.  Save as an Application Bundle.  Don't check any of the boxes.
  59.  
  60. Should you experience a problem, run in the Script Editor.
  61.    Shows how to debug via on run path. Shows items added to folder. Shows log statement.
  62.    It is easier to diagnose problems with debug information. I suggest adding log statements to your script to see what is going on.  Here is an example.  
  63.    
  64.   For testing, run in the Script Editor.
  65.          1) Click on the Event Log tab to see the output from the log statement
  66.       2) Click on Run
  67.    
  68. change log
  69. may 1, 2019   -- skip 403 forbidding title
  70. may 2, 2019   -- convert \" to ".  the \" mysteriously appears in HTML source code input.  Probably some TextEdit artifact.
  71.                 copy to TextEdit copy out of TextEdit.
  72. may 7, 2019   -- regressed May 2nd update.  Applescript was inserting \" for display purposes into output.
  73. may 8, 2019   -- special processing for html class on clipboard
  74.                          https://pastebin.com/raw/Yg138YqT
  75. may 16,2019  -- fixed hexDumpFormatOne bugs and improved output
  76. may 16,2019  -- added hexDumpFormatZero
  77. may 19,2019  -- eliminate line breaks outside the <pre>...</pre> tags in HTML. ASC intrepreting line
  78.                          breaks as meaningful <br>
  79.                          instead of white space.simplified line break code.
  80.                        https://pastebin.com/raw/Nq08cFYH
  81. may 23, 2019 -- squash leading blanks in a line. #4
  82. may 27, 2019 -- Horizontal Ellipsis. #7
  83.                          8230   U+2026  E2 80 A6    … Horizontal Ellipsis
  84.                  https://www.charset.org/utf-8/9
  85. may 28, 2019 -- decide what to do with tabs. #6
  86. may 29, 2019 -- filter titles. #1
  87.                          https://pastebin.com/raw/3xRYMXtd
  88.  
  89.          
  90.  
  91. enhancements:
  92.   -- get pdf title
  93.  
  94.  
  95. Author: rccharles
  96.  
  97.  Copyright 2019 rccharles  
  98.      
  99.        Permission is hereby granted, free of charge, to any person obtaining a copy  
  100.        of this software and associated documentation files (the "Software"), to deal  
  101.        in the Software without restriction, including without limitation the rights  
  102.        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
  103.        copies of the Software, and to permit persons to whom the Software is  
  104.        furnished to do so, subject to the following conditions:  
  105.        
  106.        The above copyright notice and this permission notice shall be included in all  
  107.        copies or substantial portions of the Software.  
  108.        
  109.        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
  110.        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
  111.        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
  112.        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
  113.        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
  114.        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
  115.        SOFTWARE.  
  116.  
  117.  
  118.    
  119.  
  120.  *)
  121.  
  122.  
  123. -- Gets invoked here when you run in AppleScript editor or double click on the app icon.
  124. on run
  125.     global debug
  126.    
  127.     -- Write a message into the event log.
  128.     log "  --- Starting on " & ((current date) as string) & " --- "
  129.    
  130.     -- 3 and 6 are good to use
  131.     set debug to 6
  132.     -- 0 no debugging
  133.     -- 1 displays input and output to this routine
  134.     -- 2 moderate
  135.     -- 3 display important "on" blocks
  136.     -- 4 display end of important "on" blocks
  137.     -- 5 display minor "on" blocks
  138.     -- 6 intense
  139.     -- 7 include replaceCharacter and hexDumpFormatOne debuging
  140.     set lf to character id 10
  141.    
  142.     if debug ≥ 3 then log "in --- run ---"
  143.    
  144.     --set the clipboard to wrapupClipboardDataSelector()
  145.    
  146.     set theList to clipboard info
  147.     if debug ≥ 2 then printClipboardInfo(theList)
  148.    
  149.     set cbInfo to get (clipboard info) as string
  150.    
  151.     -- Most likely, if we have HTML data in the clipboard it will be from a web browser or Word.
  152.     if cbInfo contains "HTML" then
  153.        
  154.         if debug ≥ 2 then log "Working with HTML Class data from clipboard."
  155.         set theBoard to the clipboard as «class HTML»
  156.        
  157.         set normalHtml to do shell script "osascript -e 'try' -e 'get the clipboard as «class HTML»' -e 'end try' | awk '{sub(/«data HTML/, \"\") sub(/»/, \"\")} {print}' | xxd -r -p "
  158.         if debug ≥ 1 then
  159.             log "...Print out plain text version of inputed HTML data from the clipboard..." & return & normalHtml
  160.             hexDumpFormatOne("after converting to printable, normalHtml", normalHtml)
  161.         end if
  162.        
  163.         set normalHtml to adjustCharacters(normalHtml)
  164.        
  165.         set returnedData to adjustBrowserHTML(normalHtml)
  166.         if debug ≥ 2 then
  167.             log "...Print out plain text version of adjusted HTML data ..." & return & returnedData
  168.             log "...just printed plain text version"
  169.             log "printed in hex"
  170.             hexDumpFormatOne("returnedData", returnedData)
  171.         end if
  172.        
  173.         set returnedData to convertToHTML(returnedData)
  174.         try
  175.             if debug ≥ 2 then log "returnedData is " & returnedData
  176.         on error errStr number errorNumber
  177.             log "===> We didn't find HTML data.   errStr is " & errStr & " errorNumber is " & errorNumber
  178.             return 1
  179.         end try
  180.     else
  181.         -- will work with a plain html or plain text.
  182.         try
  183.             if debug ≥ 2 then log "Working with plain html or plain text"
  184.             set clipboardData to (the clipboard as text)
  185.             if debug ≥ 2 then
  186.                 log "class clipboardData is " & class of clipboardData
  187.                 log "continuing plain html or plain text"
  188.             end if
  189.            
  190.             if debug ≥ 1 then
  191.                 log "inputted clipboardData is " & clipboardData
  192.                 hexDumpFormatOne("inputted clipboardData", clipboardData)
  193.             end if
  194.         on error errStr number errorNumber
  195.             log "===> We didn't find data on the clipboard.   errStr is " & errStr & " errorNumber is " & errorNumber
  196.             display dialog "We didn't find HTML source code nor plain text on the clipboard." & return & "Please copy from a different source." giving up after 15
  197.             return 1
  198.         end try
  199.         if debug ≥ 2 then log "calling common"
  200.         set returnedData to common(clipboardData)
  201.     end if
  202.     if debug ≥ 2 then log "place on the clipboard returnedData is " & returnedData
  203.     postToCLipboard(returnedData)
  204.     -- return code
  205.     return 0
  206.    
  207. end run
  208.  
  209. -- Folder actions.
  210. -- Gets invoked here when something is dropped on the folder that this script is monitoring.
  211. -- Right click on the folder to be monitored. services > Folder Action Settup...
  212. on adding folder items to this_folder after receiving added_items
  213.     -- Write a message into the event log.
  214.     log "  --- Starting on " & ((current date) as string) & " --- "
  215.     display dialog "TBD, some assembly required."
  216. end adding folder items to
  217.  
  218.  
  219.  
  220. -- Gets invoked here when something is dropped on this AppleScript icon
  221. on open dropped_items
  222.     global debug
  223.     set debug to 2
  224.     -- Write a message into the event log.
  225.     log "  --- Starting on " & ((current date) as string) & " --- "
  226.     if debug ≥ 3 then log "in --- open ---"
  227.    
  228.     (*
  229.     -- Debug code.
  230.       set fileName to choose file with prompt "get file"
  231.       set dropped_items to {fileName}
  232.     *)
  233.     if debug ≥ 2 then log "class of dropped_items is " & class of dropped_items
  234.     display dialog "You dropped " & (count of dropped_items) & " item or items." & return & "  Caveat emptor. You have been warned." giving up after 6
  235.    
  236.     set totalFileData to ""
  237.     repeat with droppedItem in dropped_items
  238.         if debug ≥ 2 then
  239.             log "The droppedItem is "
  240.             -- display dialog "processing file " & (droppedItem as string) giving up after 3
  241.             log droppedItem
  242.             log "class = " & class of droppedItem
  243.         end if
  244.         set extIs to findExtension(droppedItem)
  245.         set extIsU to makeCaseUpper(extIs)
  246.         if extIsU is "HTML" or extIsU is "HTM" or extIsU is "TEXT" or extIsU is "TXT" then
  247.             try
  248.                 set theFile to droppedItem as string
  249.                 set theFile to open for access file theFile
  250.                 set allOfFile to read theFile
  251.                 close access theFile
  252.             on error theErrorMessage number theErrorNumber
  253.                 log "==> " & theErrorMessage & "error number " & theErrorNumber
  254.                 close access theFile
  255.             end try
  256.             if debug ≥ 2 then printHeader("read from file ( allOfFile )", allOfFile)
  257.             set totalFileData to totalFileData & common(allOfFile)
  258.         else
  259.             -- we do not support this extension
  260.             display dialog "We only support files with extenstion of html, htm, text or txt in either case. Your file had a " & extIs & " extention. Skipping" giving up after 10
  261.         end if
  262.     end repeat
  263.    
  264.     postToCLipboard(totalFileData)
  265.     -- return code
  266.     return 0
  267.    
  268. end open
  269.  
  270.  
  271. -- ------------------------------------------------------
  272. on common(clipboardData)
  273.     global debug
  274.     if debug ≥ 3 then log "in --- common ---"
  275.     set ht to character id 9
  276.     set lf to character id 10
  277.    
  278.     set cbInfo to get (clipboard info) as string
  279.    
  280.     set clipboardData to adjustCharacters(clipboardData)
  281.     (*
  282.     -- for some crazy reason, I found hex "090a" (HT LF) in a html file.
  283.     set clipboardData to alterString(clipboardData, ht & lf, lf)
  284.     -- don't let Windoze confuse us. convert Return LineFeed to lf
  285.     set clipboardData to alterString(clipboardData, return & lf, lf)
  286.     -- might as will convert classic macOS return to lf. We will have to look for less things.
  287.     set clipboardData to alterString(clipboardData, return, lf)
  288.     if debug ≥ 2 then hexDumpFormatOne("change various line ends to a LF. clipboardData", clipboardData)
  289.     *)
  290.    
  291.     -- figure out what type of data we have: plain text or html source code text.
  292.     set paraCount to count of textToList(clipboardData, "<p")
  293.     set endparaCount to count of textToList(clipboardData, "</p>")
  294.     set titleCount to count of textToList(clipboardData, "<title")
  295.     set endTitleCount to count of textToList(clipboardData, "</title>")
  296.     set aLinkCount to count of textToList(clipboardData, "href=\"http")
  297.     -- mangled href="http
  298.     set mangledLinkCount to count of textToList(clipboardData, "href=\\\"http")
  299.     set brCount to count of textToList(clipboardData, "<br>")
  300.     if debug ≥ 2 then
  301.         log "Values used to distinguis HTML source code from plain text."
  302.         log "paraCount  is " & paraCount
  303.         log "endparaCount is " & endparaCount
  304.         log "titleCount is " & titleCount
  305.         log "endTitleCount is " & endTitleCount
  306.         log "aLinkCount is " & aLinkCount
  307.         log "brCount is " & brCount
  308.         log "mangledLinkCount is " & mangledLinkCount
  309.     end if
  310.    
  311.     -- note, textToList returns a count one greater than the actual because item one is the data before the first found entry.
  312.     if paraCount ≥ 4 and endparaCount ≥ 3 or brCount ≥ 4 or ((titleCount is endTitleCount) and titleCount ≥ 2) or aLinkCount ≥ 3 or mangledLinkCount ≥ 3 then
  313.         -- ASC tends to convert line-ends to either <p></p> or <p><br></p>. Isn't desireable for HTML input
  314.         if debug ≥ 2 then log "... found HTML input ... (in plain text format )."
  315.         set clipboardData to adjustBrowserHTML(clipboardData)
  316.        
  317.     else
  318.         if debug ≥ 2 then log "... found plain Text input ..."
  319.         set clipboardData to typeText(clipboardData)
  320.     end if
  321.     set readyData to convertToHTML(clipboardData)
  322.     if debug ≥ 4 then log "bye from  -.- common -.-"
  323.     return readyData
  324. end common
  325.  
  326. -- ------------------------------------------------------  
  327. (* add paragraphs *)
  328. on addParagraphs(theOutputBuffer)
  329.     global debug
  330.     if debug ≥ 3 then log "in --- addParagraphs ---"
  331.     set lf to character id 10
  332.    
  333.     -- start the theOutputBuffer with a paragraph tag.  We are taking a simple approach at this time.
  334.     set theOutputBuffer to "<p>" & theOutputBuffer
  335.     --  LF
  336.     -- Remember CRLF was changed to LF above and CR was chanaged to LF above.
  337.     -- we don't want no Windoze problems
  338.     set theOutputBuffer to alterString(theOutputBuffer, lf & lf, "</p><p> </p><p>")
  339.    
  340.     -- Does the string end with a dangling paragraph?  
  341.     if debug ≥ 5 then
  342.         log "length of theOutputBuffer is " & length of theOutputBuffer
  343.     end if
  344.     if (length of theOutputBuffer) > (length of "</p>") then
  345.         if text ((length of theOutputBuffer) - 2) thru (length of theOutputBuffer) of theOutputBuffer is "<p>" then
  346.             set theOutputBuffer to text 1 thru ((length of theOutputBuffer) - 3) of theOutputBuffer
  347.         else if text ((length of theOutputBuffer) - 2) thru (length of theOutputBuffer) of theOutputBuffer is not "</p>" then
  348.             set theOutputBuffer to theOutputBuffer & "</p>"
  349.         end if
  350.     end if
  351.     if debug ≥ 4 then log "bye from  -.- addParagraphs -.-"
  352.     return theOutputBuffer
  353. end addParagraphs
  354.  
  355. -- ------------------------------------------------------
  356. (*
  357.   We received HTML class data on the clipboard.  This is the manager.
  358.   At this point, we expect only LFs in the text.
  359.  *)
  360. on adjustBrowserHTML(normalHtml)
  361.     global debug
  362.     if debug ≥ 3 then log "in --- adjustBrowserHTML ---"
  363.     set lf to character id 10
  364.    
  365.     set alteredHTML to adjustURLs(normalHtml)
  366.     set alteredHTML to adjustToAscHTML(alteredHTML)
  367.     if debug ≥ 4 then log "bye from  -.- adjustBrowserHTML -.-"
  368.     return alteredHTML
  369. end adjustBrowserHTML
  370.  
  371. -- ------------------------------------------------------
  372. (*
  373.     Symbol  Meaning                 Hex     Used
  374.         CR      Carriage Return         0d      classic Macintosh
  375.         LF      Line Feed                       0a      UNIX
  376.         CR/LF   Carriage Return/Line Feed   0d0a    MS-DOS, Windows, OS/2
  377.        
  378.     8230    U+2026  E2 80 A6    … Horizontal Ellipsis
  379.         https://www.charset.org/utf-8/9
  380.        &hellip;
  381.         https://www.toptal.com/designers/htmlarrows/punctuation/horizontal-ellipsis/
  382.  
  383.     *)
  384. on adjustCharacters(normalHtml)
  385.     global debug
  386.     set ht to character id 9 -- horizontal tab
  387.     set lf to character id 10
  388.     set ellipsis1 to character id 226
  389.     set ellipsis2 to character id 128
  390.     set ellipsis3 to character id 166
  391.    
  392.     if debug ≥ 3 then log "in --- adjustCharacters() ---"
  393.    
  394.     -- for some reason web broswers are having difficulty with utf-8 E2 80 A6
  395.     -- so convert to a HTML entity.  does work in <pre>
  396.     set normalHtml to alterString(normalHtml, ellipsis1 & ellipsis2 & ellipsis3, "&hellip;")
  397.    
  398.     -- don't let Windoze confuse us. convert Return LineFeed to lf
  399.     set normalHtml to alterString(normalHtml, return & lf, lf)
  400.     -- might as will convert classic macOS return to lf. We will have to look for less things.
  401.     set normalHtml to alterString(normalHtml, return, lf)
  402.     if debug ≥ 3 then hexDumpFormatOne("after altering characters normalHtml", normalHtml)
  403.     return normalHtml
  404. end adjustCharacters
  405.  
  406. -- ------------------------------------------------------
  407. -- called for HTML processing
  408. on adjustLF(theBuffer)
  409.     global debug
  410.     set ht to character id 9
  411.     set lf to character id 10
  412.     if debug ≥ 3 then log "in --- adjustLF() ---"
  413.     if debug ≥ 2 then hexDumpFormatOne("  adjustLF: input from theBuffer", theBuffer)
  414.     set numberOfLf to 1 -- for debuggin so we can display loop count
  415.    
  416.     set inputLfBuffer to theBuffer -- now, input data
  417.     set outputBuildLf to "" -- output data
  418.     -- copy & change
  419.     -- ditch leading LFs
  420.     repeat while length of inputLfBuffer ≥ 2 and text 1 thru 1 of inputLfBuffer is lf
  421.         if debug ≥ 2 then log "  adjustLF: found leading lf. current length of inputLfBuffer is " & getIntegerAndHex(length of inputLfBuffer)
  422.         -- just lob off LF
  423.         set inputLfBuffer to text 2 thru -1 of inputLfBuffer
  424.        
  425.         log "  adjustLF: next text character is " & text 1 thru 1 of inputLfBuffer
  426.     end repeat
  427.     -- for some crazy reason, I found hex "090a" (HT LF) in a html file.
  428.     set inputLfBuffer to alterString(inputLfBuffer, ht & lf, lf)
  429.     repeat until inputLfBuffer is ""
  430.        
  431.         set whereLfOffset to offset of lf in inputLfBuffer
  432.         if debug ≥ 2 then log "  adjustLF: whereLfOffset is " & whereLfOffset & " in hex " & integerToHex(whereLfOffset)
  433.        
  434.         -- get before and after characters if present.
  435.         if whereLfOffset ≥ 2 then
  436.             set priorCharacter to (text (whereLfOffset - 1) thru (whereLfOffset - 1) in inputLfBuffer)
  437.         else
  438.             set priorCharacter to ""
  439.         end if
  440.         if whereLfOffset ≥ (length of inputLfBuffer) then
  441.             -- no following character
  442.             set followingCharacter to ""
  443.         else
  444.             set followingCharacter to (text (whereLfOffset + 1) thru (whereLfOffset + 1) in inputLfBuffer)
  445.         end if
  446.         if debug ≥ 2 then log "  adjustLF: priorCharacter is >" & priorCharacter & "< followingCharacter is >" & followingCharacter & "<"
  447.        
  448.         -- process the LF. 
  449.         if (whereLfOffset is 1) and ((length of inputLfBuffer)2) then
  450.             set inputLfBuffer to text 2 thru -1 of inputLfBuffer
  451.             if debug ≥ 2 then log "  adjustLF: leading lf.  Got rid of it."
  452.             -- nothing to move to outputBuildLf            
  453.         else if (whereLfOffset is 1) and ((length of inputLfBuffer) is 1) then
  454.             -- we have found all theLFs to find.
  455.             set inputLfBuffer to ""
  456.             if debug ≥ 2 then log "  adjustLF: only one character left.  Got rid of it."
  457.         else if followingCharacter is "" then
  458.             if debug ≥ 2 then log "null"
  459.             -- didn't we just check this? Yes, but we need to iterate somehow.
  460.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, " ")
  461.             -- just skip it, so we don't have to put anything on outputBuildLf
  462.         else if priorCharacter is not ">" and priorCharacter is not " " and followingCharacter is lf then
  463.             -- reduce a series of LFs to one blank
  464.             -- the next time around the next LF will be comparing to the prior character
  465.             -- as a blank
  466.             if debug ≥ 2 then log "  adjustLF: series of LFs"
  467.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, " ")
  468.         else if priorCharacter is " " and followingCharacter is tab then
  469.             -- reduce a series of LFs to one blank
  470.             -- the next time around the next LF will be comparing to the prior character
  471.             -- as a blank
  472.             if debug ≥ 2 then log "  adjustLF: series of LFs"
  473.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, "")
  474.             set {inputLfBuffer, outputBuildLf} to trimCharacters(inputLfBuffer, outputBuildLf, tab)
  475.         else if priorCharacter is ">" and followingCharacter is not " " then
  476.             --  LF after HTML tag. no real need for lf here.  asc tends to make these into <p></p>
  477.             if debug ≥ 2 then log "  adjustLF: found a tag"
  478.             -- copy prior stuff
  479.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, "")
  480.         else if followingCharacter is lf then
  481.             -- prevent double LFs.
  482.             if debug ≥ 2 then log "  adjustLF: prevent double LFs at" & getIntegerAndHex(whereLfOffset)
  483.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, "")
  484.             -- middle of text
  485.         else if (whereLfOffset < (length of inputLfBuffer)) and followingCharacter is " " then
  486.             -- we need to avoid double blanks
  487.             -- purge
  488.             if debug ≥ 2 then log "  adjustLF: getting rid of lf at " & getIntegerAndHex(whereLfOffset)
  489.             -- skip lf.
  490.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, " ")
  491.             -- get read of leading spaces.  That is the spaces after the lf
  492.             set {inputLfBuffer, outputBuildLf} to trimCharacters(inputLfBuffer, outputBuildLf, " ")
  493.         else
  494.             -- assume there are character before and after the LF.
  495.             if debug ≥ 2 then log "  adjustLF: punt."
  496.             -- replace with blank
  497.             set {inputLfBuffer, outputBuildLf} to trimOneChar(inputLfBuffer, outputBuildLf, whereLfOffset, " ")
  498.         end if
  499.        
  500.         if debug ≥ 2 then
  501.             hexDumpFormatOne("  adjustLF: outputBuildLf of " & numberOfLf, outputBuildLf)
  502.             hexDumpFormatOne("  adjustLF: inputLfBuffer of " & numberOfLf, inputLfBuffer)
  503.         end if
  504.         -- next pass will be
  505.         set numberOfLf to numberOfLf + 1
  506.     end repeat
  507.     if debug ≥ 4 then log "bye from  -.- adjustLF() -.-"
  508.     return outputBuildLf
  509. end adjustLF
  510.  
  511. -- ------------------------------------------------------
  512. (* ASC likes to insert lots of white space into a page.
  513.   This routine attempt to fix up the html to avoid
  514.   all the extra white-space.
  515.  
  516.    Minimize the amount of white space inserted.
  517.  *)
  518.  
  519. on adjustToAscHTML(ascHtml)
  520.     global debug
  521.     if debug ≥ 3 then log "in --- adjustToAscHtml ---"
  522.     set lf to character id 10
  523.     set numberOfPres to 1
  524.     -- In the context of HTML, LF should mostly be insignificant.
  525.     -- Would be bad to change a LF inside the <pre>  tag.
  526.     --skip changing lf in "<pre>.  
  527.     set buildHtml to "" -- will contain the output
  528.     if debug ≥ 2 then log "find <pre>s"
  529.     -- copy & change
  530.     if (offset of "</pre>" in ascHtml) is not 0 then
  531.         repeat while (offset of "</pre>" in ascHtml) is not 0
  532.             -- get text before "<pre" tag
  533.             set splitString to item 1 of splitTextToList(ascHtml, "<pre")
  534.             if debug ≥ 2 then
  535.                 log "splitString is " & splitString
  536.                 hexDumpFormatOne("buildHtml *before* adjustLF()", buildHtml)
  537.             end if
  538.             set buildHtml to buildHtml & adjustLF(splitString)
  539.             hexDumpFormatOne("buildHtml after adjustLF()", buildHtml)
  540.            
  541.             -- lob off header text we processed
  542.             -- while we found the text before "<pre", we still need to get it out
  543.             -- of ascHtml
  544.             --  & gets rid of the token ("<pre"), so fix
  545.             set ascHtml to "<pre" & chompLeftAndTag(ascHtml, "<pre")
  546.            
  547.             -- any more <pre> tags?
  548.             if ascHtml is "" then
  549.                 display dialog "HTML missing </pre> tag. possible logic error." giving up after 10
  550.                 -- none. We have already adjusted buildHtml
  551.                 exit repeat -- ------ done processing ascHtml ------>
  552.             end if
  553.             if debug ≥ 2 then hexDumpFormatOne("remaining ascHtml is ", ascHtml)
  554.            
  555.             -- tack on the unaltered <pre>..</pre> stuff
  556.             set buildHtml to buildHtml & (item 1 of splitTextToList(ascHtml, "</pre>")) & "</pre>"
  557.             if debug ≥ 2 then hexDumpFormatOne("buildHtml after finding </pre>", buildHtml)
  558.            
  559.             set ascHtml to chompLeftAndTag(ascHtml, "</pre>")
  560.             if debug ≥ 2 then hexDumpFormatOne("ascHtml end of " & numberOfPres & " pass", ascHtml)
  561.             set numberOfPres to numberOfPres + 1
  562.            
  563.         end repeat
  564.         -- remainder
  565.         set buildHtml to buildHtml & adjustLF(ascHtml)
  566.         set ascHtml to ""
  567.     else
  568.         -- lf's are only signigicant in <pre>...</pre>
  569.         if debug ≥ 2 then log "didn't find a <pre>"
  570.         -- all others are white space.
  571.         set buildHtml to adjustLF(ascHtml)
  572.         set ascHtml to "" -- input text processed
  573.     end if
  574.    
  575.    
  576.     (*
  577.     Hack about to fix ASC interpretation of HTML.
  578.    
  579.     ASC alters the definition of a paragraph to have not space before or after the paragraph.
  580.     A paragraph like <p></p> works like a <br>.
  581.    
  582.     Consequently, ASC converts <p> </p> to <p><br></p>, that is a
  583.     space only paragraph to a paragraph with a <br> in it.
  584.    
  585.     the code converts one tag on a line to a line of tags.
  586.     </ol>
  587.     </p>
  588.     <p>
  589.     converted form
  590.     </ol></p><p>
  591.    
  592.     so that means a change on </ol></p><p> converts both the multi-lines form and the single line form.
  593.    
  594.     *)
  595.     set buildHtml to alterString(buildHtml, "<br> ", "<br>")
  596.     -------------------- failure???
  597.     --set buildHtml to alterString(buildHtml, "<p> ", "<p>")
  598.    
  599.     -- asc paragraphs don't generate space before and after the paragraph.
  600.     set buildHtml to alterString(buildHtml, "</p><p></p><p></p>", "</p><p> </p><p></p>")
  601.    
  602.     set buildHtml to alterString(buildHtml, "</p><p></p><p></p>", "</p><p> </p><p></p>")
  603.    
  604.     set buildHtml to alterString(buildHtml, "</ol></p><p>", "</ol><p> </p></p><p>")
  605.     (*
  606.     surprisingly ASC converts <p> </p> to <p><br></p>, that is a
  607.     space only paragraph to a paragraph with a <br> in it.
  608.    
  609.     the code converts one tag on a line to a line of tags.
  610.     </ol>
  611.     </p>
  612.     <p>
  613.     converted form
  614.     </ol></p><p>
  615.    
  616.     so that means a change on </ol></p><p> converts both the multi-lines form and the single line form.
  617.    
  618.     *)
  619.     --set buildHtml to alterString(buildHtml, "<p> </p>", "<p></p>")
  620.     if debug ≥ 2 then hexDumpFormatOne("complete buildHtml ", buildHtml)
  621.     if debug ≥ 4 then log "bye from  -.- adjustToAscHTML -.-"
  622.     return buildHtml
  623. end adjustToAscHTML
  624.  
  625. -- ------------------------------------------------------
  626. (*
  627. example:
  628.   Free version of Parallels for individual use:</p><p><br></p>
  629.   <p>https://itunes.apple.com/us/app/parallels-desktop-lite/id1085114709?mt=12</p>
  630.   <p><br></p>
  631.   <p>Full version</p><p><a href="http://www.parallels.com/en/products/desktop/" target="_blank">
  632.      http://www.parallels.com/en/products/desktop/</a>
  633.      
  634. If asc find a URL outside of an a tag, it will place blank lines around the URL. No, it will not go the
  635. full nine yards and place an a tag around the url.
  636.  
  637. *)
  638. on adjustURLs(theOriginalInputBuffer)
  639.     global debug
  640.     if debug ≥ 3 then log "in --- adjustURLs ---"
  641.     set alteredBuffer to false
  642.     set lf to character id 10
  643.     set theInputBuffer to theOriginalInputBuffer
  644.     if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: theInputBuffer", theInputBuffer)
  645.    
  646.     -- we end up in a lot of grief when the buffer ends without
  647.     -- a line-end
  648.     if text (length of theInputBuffer) thru (length of theInputBuffer) of theInputBuffer is not lf then
  649.         -- tack LF at the end
  650.         set alteredBuffer to true
  651.         set theInputBuffer to theInputBuffer & lf
  652.         if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: theInputBuffer", theInputBuffer)
  653.     end if
  654.    
  655.     set buildHtml to ""
  656.     if debug ≥ 5 then log "  adjustURLs: buildHTML [ should be empty string ] is " & buildHtml
  657.     set countI to 1 -- variable is used for debuging.
  658.     -- do until we have processed theInputBuffer
  659.     repeat until theInputBuffer is ""
  660.         if debug ≥ 2 then log "  adjustURLs: at the top of theInputBuffer ........."
  661.        
  662.         set foundWhere to {}
  663.         repeat with lookCharacters in {"https://", "http://", "<a "}
  664.             copy (offset of lookCharacters in theInputBuffer) to the end of the foundWhere
  665.             try
  666.                 set tempLoc to (offset of lookCharacters in theInputBuffer)
  667.                 if debug ≥ 2 then log "  adjustURLs: searching for " & lookCharacters & " found at offset  " & tempLoc & " contains " & text tempLoc thru (tempLoc + ((length of lookCharacters) - 1)) of theInputBuffer
  668.             end try
  669.         end repeat
  670.         if debug ≥ 2 then log foundWhere
  671.         set foundMarkerOffset to (minimumPositiveNumber from foundWhere)
  672.         -- figure out what type of marker we got?
  673.        
  674.         -- None.  Reached the end of the data without finding one.
  675.         if foundMarkerOffset ≤ 0 then
  676.             -- we are done
  677.             if debug ≥ 2 then log "  adjustURLs: Found all links."
  678.             set buildHtml to buildHtml & theInputBuffer
  679.             if debug ≥ 2 then printHeader("  adjustURLs: buildHTML", buildHtml)
  680.             set theInputBuffer to ""
  681.             exit repeat -- ------ done processing theInputBuffer ------>
  682.         end if
  683.        
  684.         -- find which of three markers we found.
  685.         if (text foundMarkerOffset thru (foundMarkerOffset + 2) of theInputBuffer) is "<a " then
  686.             set actualMarker to "<a "
  687.         else if text foundMarkerOffset thru (foundMarkerOffset + 6) of theInputBuffer is "http://" then
  688.             set actualMarker to "http://"
  689.         else
  690.             -- just assume it's the remaining "https://" since we looked for just three.
  691.             set actualMarker to "https://"
  692.         end if
  693.         set actualMarkerOffsetLength to ((length of actualMarker) - 1)
  694.         if debug ≥ 2 then
  695.             log "  adjustURLs: actualMarker is " & actualMarker & " actualMarkerOffsetLength is " & actualMarkerOffsetLength
  696.             log "  adjustURLs: foundMarkerOffset is " & getIntegerAndHex(foundMarkerOffset) & "  verify marker text is " & text foundMarkerOffset thru (foundMarkerOffset + actualMarkerOffsetLength) of theInputBuffer
  697.         end if
  698.        
  699.        
  700.         if foundMarkerOffset ≥ 2 then
  701.             -- collect and strip off characters that are before the marker.
  702.             if debug ≥ 2 then
  703.                 log "  adjustURLs: buildHTML is " & buildHtml & " length is " & getIntegerAndHex(length of buildHtml)
  704.                 hexDumpFormatOne("  adjustURLs: theInputBuffer", theInputBuffer)
  705.                 log "  adjustURLs:  (foundMarkerOffset - 1) is " & getIntegerAndHex((foundMarkerOffset - 1))
  706.             end if
  707.             -- get the proceding text
  708.             set buildHtml to buildHtml & text 1 thru (foundMarkerOffset - 1) of theInputBuffer
  709.             if debug ≥ 2 then
  710.                 log "  adjustURLs: buildHTML is " & buildHtml
  711.                 hexDumpFormatOne("  adjustURLs: buildHTML", buildHtml)
  712.             end if
  713.            
  714.             -- https://apple.stackexchange.com/a/20135/44531
  715.            
  716.             set theInputBuffer to text foundMarkerOffset thru -1 of theInputBuffer --trim off character before what we found
  717.             if debug ≥ 2 then
  718.                 printHeader("  adjustURLs: theInputBuffer", theInputBuffer)
  719.                 hexDumpFormatOne("  adjustURLs: theInputBuffer", theInputBuffer)
  720.             end if
  721.         else
  722.             log "  adjustURLs: ==> no proceeding data."
  723.         end if
  724.        
  725.         repeat 1 times -- interate loop
  726.            
  727.             -- example" the url is also the display text
  728.             -- <a href="https://discussions.apple.com/docs/DOC-8841" target="_blank">https://discussions.apple.com/docs/DOC-8841</a>
  729.             if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: theInputBuffer", theInputBuffer)
  730.            
  731.             -- check for the <a> tag
  732.             if text 1 thru (length of "<a ") of theInputBuffer is "<a " then
  733.                 -- found <a> tag
  734.                 if debug ≥ 2 then log "  adjustURLs: processing <a> tag"
  735.                 -- ASC consider a line-end as a <br> when when firefox considers it a blank
  736.                 -- change a possible line-end before an <a> tag to a " "
  737.                 if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: before lf check buildHTML", buildHtml)
  738.                 if text (length of buildHtml) thru (length of buildHtml) of buildHtml is lf then
  739.                     if debug ≥ 2 then log "  adjustURLs: we need to delete a line-end before the <a> tag"
  740.                     set buildHtml to text 1 thru ((length of buildHtml) - 1) of buildHtml
  741.                     set buildHtml to buildHtml & " "
  742.                     if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: after lf deletion buildHTML", buildHtml)
  743.                 end if
  744.                 -- find ending </a> tag
  745.                 set whereEnds to offset of "</a>" in theInputBuffer
  746.                 if whereEnds ≤ 0 then
  747.                     if debug ≥ 2 then log "  adjustURLs: ==> found an error in the HTML.  no ending </a>"
  748.                     set buildHtml to buildHtml & theInputBuffer
  749.                     printHeader("  adjustURLs: buildHTML", buildHtml)
  750.                     set theInputBuffer to ""
  751.                     display dialog "  adjustURLs: Found an error in the HTML.  No ending </a>.  Will skip." giving up after 10
  752.                     exit repeat -- ------ next ------>
  753.                 end if
  754.                 set lastOffsetLength to ((length of "</a>") - 1)
  755.                 if debug ≥ 2 then log "  adjustURLs: lastOffsetLength is " & lastOffsetLength
  756.                 set lastCharacterOffset to whereEnds + lastOffsetLength
  757.                 if debug ≥ 2 then log "  adjustURLs: lastCharacterOffset is " & lastCharacterOffset
  758.                 -- needs to copy the ending ">"
  759.                 set anchorString to text 1 thru lastCharacterOffset of theInputBuffer
  760.                 -- don't let Windoze confuse us. convert Return LineFeed to lf
  761.                 -- Correct absure ASC bug where there is a line-end in the <a> text.
  762.                 if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: before adjusting anchorString", anchorString)
  763.                 set anchorString to alterString(anchorString, lf, " ")
  764.                 if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: anchorString", anchorString)
  765.                 --
  766.                 -- fix up mangled url
  767.                 -- be a nice guy for RW -???-
  768.                 -- Waterfox fixes up!
  769.                 --  
  770.                 set buildHtml to buildHtml & anchorString
  771.                 if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: buildHTML", buildHtml)
  772.                 -- https://apple.stackexchange.com/a/20135/44531
  773.                 -- We want first character of the "next" portion of theInputBuffer so add one
  774.                 set theInputBuffer to text (lastCharacterOffset + 1) thru -1 of theInputBuffer --trim out <a>
  775.                 if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: theInputBuffer", theInputBuffer)
  776.                 -- Web Browsers like Firefox convert a line-end in text to a space.
  777.                 if text 1 thru 1 of theInputBuffer is lf then
  778.                     if (length of theInputBuffer) is 1 then
  779.                         set theInputBuffer to " "
  780.                     else
  781.                         set theInputBuffer to " " & (text 2 thru (length of theInputBuffer) of theInputBuffer)
  782.                         if debug ≥ 2 then hexDumpFormatOne("  adjustURLs: after lf deletion; theInputBuffer", theInputBuffer)
  783.                     end if
  784.                 end if
  785.                 exit repeat -- ------ next ------>
  786.             end if
  787.            
  788.             -- find the end of the HTML URL by splitting on blank or return
  789.             -- unsafe characters  <blank> " < > # % { } | \ ^ ~ [ ] `
  790.             -- and line-end
  791.             -- while # is listed as unsafe, it does appear in a url as a marker of some sort.
  792.             -- leave it out as an ending character.
  793.             -- https://perishablepress.com/stop-using-unsafe-characters-in-urls/
  794.             -- the end of the clipboard string my end after the url, hence no " ", LF or CR
  795.             -- Rember, CRLF was converted to LF above
  796.             set endsWhere to {}
  797.             -- the end of the url ends with one of the not allowed characters + line-end
  798.             repeat with unsafeCharacter in {" ", "\"", lf, "<", ">", "%", "{", "}", "|", "\\", "^", "~", "[", "]"}
  799.                 copy (offset of unsafeCharacter in theInputBuffer) to the end of the endsWhere
  800.             end repeat
  801.             if debug ≥ 2 then log endsWhere
  802.             set endOfURL to (minimumPositiveNumber from endsWhere) - 1
  803.            
  804.             if debug ≥ 2 then log "  adjustURLs: endOfURL is " & endOfURL
  805.            
  806.             if endOfURL ≤ 0 then
  807.                 -- We have reached the end of the input
  808.                 set theURL to theInputBuffer
  809.                 set theInputBuffer to ""
  810.             else
  811.                 set theURL to text 1 thru endOfURL of theInputBuffer
  812.                 if debug ≥ 2 then log "  adjustURLs: from middle theURL is " & theURL
  813.                
  814.                 set theInputBuffer to text (endOfURL + 1) thru -1 of theInputBuffer -- trim off url in front.
  815.             end if
  816.             if debug ≥ 2 then printHeader("  adjustURLs: printHeader", theInputBuffer)
  817.             if debug ≥ 1 then log "  adjustURLs: ----------------------- " & theURL & " -----------------------"
  818.             (*
  819.             retrieve the file pointed to by the URL so we can
  820.             get the title. Note: <title> can have attributes.  Example:
  821.                
  822.             <title data-test-page-title="Parallels Desktop Lite on the Mac App Store"
  823.             >‎Parallels Desktop Lite on the Mac App Store</title>
  824.            
  825.             *)
  826.            
  827.             -- Example:
  828.             -- curl --silent --location --max-time 10 <URL>
  829.             set toUnix to "curl --silent --location --max-time 10 " & quoted form of theURL
  830.             if debug ≥ 2 then log "  adjustURLs: what we will use to retrieve the Url. toUnix  is " & return & "  " & toUnix
  831.             try
  832.                 if debug ≥ 2 then log "  adjustURLs: reading link file to get title"
  833.                 set fromUnix to do shell script toUnix
  834.                 --log "fromUnix:"
  835.                 if debug ≥ 2 then
  836.                     printHeader("  adjustURLs: fromUnix", fromUnix)
  837.                     -- may not be working with an HTLM document, so thefound title may be too long or confused.
  838.                     log "  adjustURLs: how far?..."
  839.                 end if
  840.                 -- there could be some bagage with the <title
  841.                 set actualTagData to tagContent(fromUnix, "<title", "</title>")
  842.                 -- Find what we will actually display in the title.
  843.                 -- Fix up gotchas.             
  844.                 if debug ≥ 2 then log "  adjustURLs: actualTagData  is " & printHeader("actualTagData", actualTagData)
  845.                 if actualTagData is "" then
  846.                     set actualTagData to theURL
  847.                 else if length of actualTagData > 140 then
  848.                     if debug ≥ 2 then log "  adjustURLs: length of actualTagData is " & length of actualTagData & "which is too long.  Truncated."
  849.                     set actualTagData to theURL
  850.                     -- curl https://appleid.apple.com returns <title>403 Forbidden</title>
  851.                     -- which is misleading.
  852.                 else if actualTagData contains "403" and actualTagData contains "Forbidden" then
  853.                     log "  adjustURLs:  found 403 web page."
  854.                     set actualTagData to theURL
  855.                 else
  856.                     -- there could be some attributes within the <title> tag.
  857.                     -- or there could not be
  858.                     -- an attribute could have a > in it. ignoring that for now.
  859.                     try
  860.                         -- find where <title ends
  861.                         set whereToEnd to (offset of ">" in actualTagData)
  862.                         if debug ≥ 2 then log "  adjustURLs: whereToEnd is " & whereToEnd
  863.                         set whereToBegin to whereToEnd + (length of ">")
  864.                         if debug ≥ 2 then log "  adjustURLs: whereToBegin is " & whereToBegin
  865.                         hexDumpFormatOne("  adjustURLs: actualTagData", actualTagData)
  866.                         set actualTagData to text whereToBegin thru (length of actualTagData) of actualTagData
  867.                         if debug ≥ 2 then log "  adjustURLs: actualTagData is " & actualTagData
  868.                     on error theErrorMessage number theErrorNumber
  869.                         log "  adjustURLs: ==>No ending greater than (>) for title. Badly contructed html." & return & "message is " & theErrorMessage & "error number " & theErrorNumber
  870.                         set actualTagData to actualTagData
  871.                         -- no need to repair.  It's not our page.
  872.                     end try
  873.                    
  874.                     -- found line-end in title.  caused confustion.
  875.                     -- note: this is new data and the multiple line-ends have not been
  876.                     -- filtered out.
  877.                     -- some joker had a line-end in the title!
  878.                     if debug ≥ 3 then
  879.                         log "  adjustURLs: actualTagData (title) has been chanaged which is  " & actualTagData
  880.                         hexDumpFormatOne("  adjustURLs: actualTagData (title)", actualTagData)
  881.                     end if
  882.                     set actualTagData to alterString(actualTagData, return & lf, lf)
  883.                     set actualTagData to alterString(actualTagData, return, lf)
  884.                     set actualTagData to adjustLF(actualTagData)
  885.                     if debug ≥ 2 then
  886.                         log "  adjustURLs: actualTagData (title) has been chanaged which is  " & actualTagData
  887.                         hexDumpFormatOne("  adjustURLs: actualTagData (title)", actualTagData)
  888.                     end if
  889.                    
  890.                 end if
  891.             on error errMsg number n
  892.                 display dialog "  adjustURLs: ==> Error occured when looking for title. " & errMsg & " with number " & n giving up after 10
  893.                 log "  adjustURLs: ==> Error occured when looking for title. " & errMsg & " with number " & n
  894.                 set actualTagData to theURL
  895.             end try
  896.             -- why the _blank in the <a>?
  897.             set assembled to "<a href=\"" & theURL & "\" target=\"_blank\">" & actualTagData & "</a>"
  898.             if debug ≥ 2 then log "  adjustURLs: assembled  is " & assembled
  899.            
  900.             if (length of theInputBuffer)0 then
  901.                 -- We have reached the end of the input
  902.                 if debug ≥ 2 then log "  adjustURLs: we have reached the end of the input."
  903.                 set buildHtml to buildHtml & assembled
  904.             else
  905.                 if debug ≥ 2 then log "  adjustURLs: more input to process"
  906.                 set buildHtml to buildHtml & assembled
  907.             end if
  908.            
  909.             -- wrap up
  910.             --log "transformed text from buildHTML is  " & return & buildHTML
  911.             if debug ≥ 2 then log "  adjustURLs: #" & countI & " transformed text from buildHTML is  " & return & buildHtml
  912.             -- number of links found
  913.             set countI to countI + 1
  914.            
  915.         end repeat -- used to interate
  916.     end repeat -- processing links in the input text
  917.     if alteredBuffer is true then
  918.         -- chop off the lf we added above.
  919.         set buildHtml to text 1 thru ((length of buildHtml) - 1) of buildHtml
  920.         set alteredBuffer to false -- somewhat redundant
  921.     end if
  922.     if debug ≥ 4 then log "bye from  -.- adjustURLs -.-"
  923.     return the buildHtml
  924.    
  925. end adjustURLs
  926.  
  927. -- ------------------------------------------------------
  928. (*
  929. alterString
  930.   thisText is the input string to change
  931.   delim is what string to change.  It doesn't have to be a single character.
  932.   replacement is the new string
  933.  
  934.   returns the changed string.
  935. *)
  936.  
  937. on alterString(thisText, delim, replacement)
  938.     global debug
  939.     if debug ≥ 5 then log "in ~~~ alterString ~~~"
  940.     set resultList to {}
  941.     set {tid, my text item delimiters} to {my text item delimiters, delim}
  942.     try
  943.         set resultList to every text item of thisText
  944.         set text item delimiters to replacement
  945.         set resultString to resultList as string
  946.         set my text item delimiters to tid
  947.     on error
  948.         set my text item delimiters to tid
  949.     end try
  950.     return resultString
  951. end alterString
  952.  
  953. -- ------------------------------------------------------
  954. (*
  955.   Return the text to the right of theToken.
  956. *)
  957. on answerAndChomp(theString, theToken)
  958.     global debug
  959.     if debug ≥ 5 then log "in ~~~ answerAndChomp ~~~"
  960.     set debugging to false
  961.     set theOffset to offset of theToken in theString
  962.     if debug ≥ 6 then log "theOffset is " & theOffset
  963.     set theLength to length of theString
  964.     if theOffset > 0 then
  965.         set beginningPart to text 1 thru (theOffset - 1) of theString
  966.         if debug ≥ 6 then log "beginningPart is " & beginningPart
  967.        
  968.         set chompped to text theOffset thru theLength of theString
  969.         if debug ≥ 6 then log "chompped is " & chompped
  970.         return {chompped, beginningPart}
  971.     else
  972.         set beginningPart to ""
  973.         return {theString, beginningPart}
  974.     end if
  975.    
  976. end answerAndChomp
  977.  
  978. -- ------------------------------------------------------
  979. (*
  980.   Delete the leading part of the string until and including theToken.
  981. *)
  982. on chompLeftAndTag(theString, theToken)
  983.     global debug
  984.     if debug ≥ 6 then log "in --- chompLeftAndTag ---"
  985.     if debug ≥ 5 then
  986.         log "theToken is " & theToken
  987.         hexDumpFormatOne("theString", theString)
  988.     end if
  989.     set theOffset to offset of theToken in theString
  990.     if debug ≥ 5 then log "theOffset is " & theOffset & " in hex is " & integerToHex(theOffset)
  991.     set theLength to length of theString
  992.     if debug ≥ 5 then log "theLength is " & theLength & " in hex is " & integerToHex(theLength)
  993.    
  994.     if theOffset > 0 then
  995.         -- Do we have any more of the string to return?
  996.         if (theOffset + (length of theToken)) ≤ length of theString then
  997.             set chompped to text (theOffset + (length of theToken)) thru theLength of theString
  998.         else
  999.             set chompped to ""
  1000.         end if
  1001.         if debug ≥ 5 then log "length of chompped is " & length of chompped & "chompped is " & chompped
  1002.         return chompped
  1003.     else
  1004.         return ""
  1005.     end if
  1006. end chompLeftAndTag
  1007.  
  1008. -- ------------------------------------------------------
  1009. on convertToHTML(theData)
  1010.     global debug
  1011.     if debug ≥ 3 then log "in --- convertToHTML ---" & return & "  Try to send back HTML. the processed data in variable theData is " & theData
  1012.     try
  1013.         set clipboardDataQuoted to quoted form of theData
  1014.        
  1015.         if debug ≥ 1 then
  1016.             log "  convertToHTMLz: .... data soon to be returned ...." & return & "clipboardDataQuoted is " & return & clipboardDataQuoted
  1017.             hexDumpFormatOne("clipboardDataQuoted", clipboardDataQuoted)
  1018.         end if
  1019.         -- make hex string as required for HTML data on the clipboard
  1020.         set toUnix to "/bin/echo -n " & clipboardDataQuoted & " | hexdump -ve '1/1 \"%.2x\"'"
  1021.         if debug ≥ 5 then printHeader("  convertToHTMLz: toUnix to convert to hex", toUnix)
  1022.         set fromUnix to do shell script toUnix
  1023.        
  1024.         if debug ≥ 5 then printHeader("  convertToHTMLz: fromUnix", fromUnix)
  1025.        
  1026.         if debug ≥ 5 then
  1027.             log "  convertToHTMLz: displaying original string -- so we can tell if it converted successfully. "
  1028.             --hexDumpFormatOne("fromUnix", fromUnix)
  1029.         end if
  1030.     on error errMsg number n
  1031.         log "  convertToHTMLz: ==> convert to hex string failed. " & errMsg & " with number " & n
  1032.         set fromUnix to ""
  1033.     end try
  1034.     if debug ≥ 4 then log "bye from  -.- convertToHTML -.-"
  1035.     return fromUnix
  1036. end convertToHTML
  1037.  
  1038. -- ------------------------------------------------------  
  1039. (*
  1040. Yvan Koenig
  1041. https://macscripter.net/viewtopic.php?id=43133
  1042. *)
  1043. on findExtension(inputFileName)
  1044.     global debug
  1045.     if debug ≥ 5 then log "in ~~~ indExtension ~~~"
  1046.     set fileName to inputFileName as string
  1047.     set saveTID to AppleScript's text item delimiters
  1048.     set AppleScript's text item delimiters to {"."}
  1049.     set theExt to last text item of fileName
  1050.     set AppleScript's text item delimiters to saveTID
  1051.     --log "theExt is " & theExt
  1052.     if theExt ends with ":" then set theExt to text 1 thru -2 of theExt
  1053.     if debug ≥ 5 then log "theExt is " & theExt
  1054.     return theExt
  1055. end findExtension
  1056.  
  1057. -- ------------------------------------------------------
  1058. (*
  1059. length of inputLfBuffer & " in hex " & integerToHex(length of inputLfBuffer)
  1060. *)
  1061. on getIntegerAndHex(aNumber)
  1062.     global debug
  1063.     if debug ≥ 5 then log "in ~~~ getIntegerAndHex ~~~"
  1064.    
  1065.     return aNumber & " in Hex " & integerToHex(aNumber)
  1066. end getIntegerAndHex
  1067.  
  1068. -- ------------------------------------------------------
  1069. (*
  1070.   http://krypted.com/mac-os-x/to-hex-and-back/
  1071.                0    2    4    6    8    a    c    e     0 2 4 6 8 a c e
  1072. 0000000:   3c 703e 5369 6d70 6c65 2070 7574 2c20   <p>Simple put,
  1073.             *)
  1074. on hexDumpFormatOne(textMessage, hex)
  1075.     global debug
  1076.    
  1077.     set aNul to character id 1
  1078.    
  1079.     if debug ≥ 5 then log "in ~~~ hexDumpFormatOne ~~~"
  1080.     if debug ≥ 7 then log "    hexDumpFormatOne: input string is " & return & hex
  1081.    
  1082.     -- -r -p
  1083.     set displayValue to aNul & hex
  1084.     set toUnix to "/bin/echo -n " & (quoted form of displayValue) & " | xxd  "
  1085.     if debug ≥ 7 then log "    hexDumpFormatOne: toUnix is " & toUnix
  1086.    
  1087.     try
  1088.         set fromUnix to do shell script toUnix
  1089.        
  1090.         -- two hex digits
  1091.         set displayText to replaceCharacter(fromUnix, 10, "  ")
  1092.         if debug ≥ 7 then
  1093.             log "    hexDumpFormatOne: " & return & displayText
  1094.             log "    hexDumpFormatOne: length of displayText is " & length of displayText
  1095.         end if
  1096.         -- one character
  1097.         set displayText to replaceCharacter(displayText, 51, " ")
  1098.         if debug ≥ 7 then
  1099.             log "    hexDumpFormatOne: " & return & displayText
  1100.             log "    hexDumpFormatOne: almost there ..... length of displayText is " & length of displayText
  1101.         end if
  1102.         log "variable " & textMessage & " in hex is " & return & "         0    2    4    6    8    a    c    e     0 2 4 6 8 a c e" & return & displayText
  1103.     on error errMsg number n
  1104.         log "    hexDumpFormatOne: ==> convert hex string to string failed. " & errMsg & " with number " & n
  1105.     end try
  1106.     if debug ≥ 7 then
  1107.         log "leaving ~.~ hexDumpFormatOne ~.~"
  1108.     end if
  1109. end hexDumpFormatOne
  1110.  
  1111. -- ------------------------------------------------------
  1112. on hexDumpFormatZero(textMessage, hex)
  1113.     global debug
  1114.     if debug ≥ 5 then log "in ~~~ hexDumpFormatZero ~~~"
  1115.     if debug ≥ 5 then log "input string is " & hex
  1116.     -- -r -p
  1117.     set toUnix to "/bin/echo -n " & (quoted form of hex) & " | xxd  "
  1118.     if debug ≥ 5 then log "toUnix is " & toUnix
  1119.     try
  1120.         set displayText to do shell script toUnix
  1121.        
  1122.         log "variable " & textMessage & " in hex is " & return & "         0    2    4    6    8    a    c    e     0 2 4 6 8 a c e" & return & displayText
  1123.     on error errMsg number n
  1124.         log "==> convert hex string to string failed. " & errMsg & " with number " & n
  1125.     end try
  1126. end hexDumpFormatZero
  1127.  
  1128. -- ------------------------------------------------------
  1129. (*
  1130. https://macscripter.net/viewtopic.php?id=43713
  1131.   *)
  1132. on integerToHex(nDec)
  1133.     global debug
  1134.     if debug ≥ 5 then log "in ~~~ integerToHex ~~~"
  1135.     try
  1136.         set nHex to do shell script "perl -e 'printf(\"%X\", " & nDec & ")'" --> "F0"
  1137.     on error errMsg number n
  1138.         log "==> convert integer to hex. " & errMsg & " with number " & n
  1139.         set nHex to ""
  1140.     end try
  1141.     return nHex
  1142. end integerToHex
  1143.  
  1144. -- ------------------------------------------------------
  1145. (*
  1146.  
  1147. https://stackoverflow.com/questions/55838252/minimum-value-that-not-zero
  1148.        set m to get minimumPositiveNumber from {10, 2, 0, 2, 4}
  1149.     log "m is " & m
  1150.     set m to minimumPositiveNumber from {0, 0, 0}
  1151.     log "m is " & m
  1152. *)
  1153. on minimumPositiveNumber from L
  1154.     global debug
  1155.     if debug ≥ 5 then log "in ~~~ minimumPositiveNumber ~~~"
  1156.     local L
  1157.    
  1158.     if L = {} then return null
  1159.    
  1160.     set |ξ| to 0
  1161.    
  1162.     repeat with x in L
  1163.         set x to x's contents
  1164.         if (x < |ξ| and x ≠ 0) ¬
  1165.             or |ξ| = 0 then ¬
  1166.             set |ξ| to x
  1167.     end repeat
  1168.    
  1169.     |ξ|
  1170. end minimumPositiveNumber
  1171.  
  1172. -- ------------------------------------------------------
  1173. (*
  1174.   makeCaseUpper("Now is the time, perhaps, for all good men")
  1175. *)
  1176. on makeCaseUpper(theString)
  1177.     global debug
  1178.     if debug ≥ 5 then log "in ~~~ makeCaseUpper ~~~"
  1179.     set UC to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  1180.     set LC to "abcdefghijklmnopqrstuvwxyz"
  1181.     set C to characters of theString
  1182.     repeat with ch in C
  1183.         if ch is in LC then set contents of ch to item (offset of ch in LC) of UC
  1184.     end repeat
  1185.     return C as string
  1186. end makeCaseUpper
  1187.  
  1188. -- ------------------------------------------------------
  1189. on postToCLipboard(pleasePost)
  1190.     global debug
  1191.     if debug ≥ 5 then log "in ~~~ postToCLipboard ~~~"
  1192.     try
  1193.         -- osascript -e "set the clipboard to «data HTML${hex}»"     
  1194.         set toUnixSet to "osascript -e \"set the clipboard to «data HTML" & pleasePost & \""
  1195.         if debug ≥ 5 then log "  postToCLipboard: toUnixSet is " & printHeader("toUnixSet", toUnixSet)
  1196.        
  1197.         set fromUnixSet to do shell script toUnixSet
  1198.         if debug ≥ 5 then log "  postToCLipboard: fromUnixSet is " & fromUnixSet
  1199.        
  1200.     on error errMsg number n
  1201.         log "  postToCLipboard: ==> We tried to send back HTML data, but failed. " & errMsg & " with number " & n
  1202.     end try
  1203.     -- see what ended up on the clipboard
  1204.     set theList2 to clipboard info
  1205.     if debug ≥ 2 then printClipboardInfo(theList2)
  1206. end postToCLipboard
  1207.  
  1208. -- ------------------------------------------------------
  1209. on printClipboardInfo(theList)
  1210.     global debug
  1211.     if debug ≥ 5 then log "in ~~~ printClipboardInfo ~~~"
  1212.     log (clipboard info)
  1213.     log class of theList
  1214.     log "Data types on the clipboard ... "
  1215.     printList("", theList)
  1216.     log "... "
  1217. end printClipboardInfo
  1218.  
  1219. -- ------------------------------------------------------
  1220. (* Pump out the beginning of theString *)
  1221. on printHeader(theName, theString)
  1222.     global debug
  1223.     if debug ≥ 5 then
  1224.         log "in ~~~ printHeader ~~~"
  1225.         log "theName is " & theName
  1226.         log theString
  1227.         log "length of theString is " & length of theString
  1228.     end if
  1229.     if length of theString ≤ 0 then
  1230.         log "==> no string to print"
  1231.     else
  1232.         log theName & " is " & return & text 1 thru (minimumPositiveNumber from {400, length of theString}) of theString & "<+++++++++"
  1233.     end if
  1234. end printHeader
  1235.  
  1236. -- ------------------------------------------------------
  1237. (*
  1238. print out the items in a list
  1239.  
  1240. *)
  1241.  
  1242. on printList(theName, splits)
  1243.     global debug
  1244.     if debug ≥ 5 then log "in ~~~ printList ~~~"
  1245.     try
  1246.         set theCount to 1
  1247.         repeat with theEntry in splits
  1248.             --log "class of theEntry is " & class of theEntry
  1249.             set classDisplay to class of theEntry as text
  1250.             --log "classDisplay is " & classDisplay as text
  1251.             --log "class of classDisplay is " & class of classDisplay
  1252.             if classDisplay is "list" then
  1253.                 log "    " & theName & theCount & " is " & item 1 of theEntry & "; " & item 2 of theEntry
  1254.             else
  1255.                 log "    " & theName & theCount & " is " & theEntry
  1256.             end if
  1257.             set theCount to theCount + 1
  1258.         end repeat
  1259.     on error errMsg number n
  1260.         log "==> No go in printList. " & errMsg & " with number " & n
  1261.     end try
  1262. end printList
  1263.  
  1264. -- ------------------------------------------------------
  1265. (*
  1266. StefanK in https://macscripter.net/viewtopic.php?id=43852
  1267. Replaces one or more characters based on the length of theCharacter.
  1268.  
  1269.   Big Warning!!!
  1270.   ==============
  1271.     This on block is called by hexDumpFormatOne().  
  1272.     Therefor, you may not call hexDumpFormatOne() from this on block.
  1273.     If you so so, you get yourself into an endless loop.
  1274.     Use hexDumpFormatZero() instead.
  1275.    
  1276.     script -k <output file name>
  1277.     osascript /Applications/applescriptFiles/workwithclipboardV13-HTML.app
  1278.     use Activity Monito to stop osascript
  1279.    
  1280. *)
  1281.  
  1282. on replaceCharacter(theText, theOffset, theCharacter)
  1283.     global debug
  1284.     if debug ≥ 7 then log "in ~~~ replaceCharacter ~~~"
  1285.     if debug ≥ 7 then
  1286.         log "  theOffset is " & getIntegerAndHex(theOffset) & " with theCharacter >" & theCharacter & "<  length of theText is " & getIntegerAndHex(length of theText)
  1287.         log "theText is " & theText
  1288.     end if
  1289.    
  1290.     set theOutput to theText -- ready to return if need be.
  1291.     repeat 1 times
  1292.         -- sanity checks
  1293.         if theOffset ≤ 0 then
  1294.             display dialog "No character to replace at " & theOffset & " with character " & theCharacter & " in " & theText giving up after 10
  1295.             log "==> Adjust theOffset to be wihin the string."
  1296.             exit repeat -------------- return ---------->                  
  1297.         end if
  1298.         if (theOffset - (length of theCharacter))0 then
  1299.             display dialog "Too near the front of the buffer.  " & theOffset & " with character " & theCharacter & " in " & theText giving up after 10
  1300.             log "==> Too near the front of the buffer. "
  1301.             exit repeat -------------- return ---------->
  1302.         end if
  1303.         if (theOffset + (length of theCharacter) - 1) > (length of theText) then
  1304.             display dialog "To near the end of the buffer. " & theOffset & " with character " & theCharacter & " in " & theText giving up after 10
  1305.             log "==> Too near the end of the buffer. "
  1306.             log "  " & "theOffset is " & theOffset & " with theCharacter >" & theCharacter & "<  in " & theText
  1307.             log "length of buffer is " & getIntegerAndHex(length of theText)
  1308.             exit repeat -------------- return ---------->                  
  1309.         end if
  1310.        
  1311.         if debug ≥ 7 then
  1312.             log "theOffset is " & getIntegerAndHex(theOffset)
  1313.             log "theCharacter is " & theCharacter
  1314.         end if
  1315.        
  1316.         try
  1317.             -- what if we are at the end of the buffer.  We cannot get any remainder text.
  1318.             if theOffset ≥ (length of theText) then
  1319.                 set theOutput to (text 1 thru (theOffset - 1) of theText) & theCharacter
  1320.             else
  1321.                 set theOutput to (text 1 thru (theOffset - 1) of theText) & theCharacter & (text (theOffset + (length of theCharacter)) thru -1 of theText)
  1322.             end if
  1323.         on error errMsg number n
  1324.             log "==> No go. " & errMsg & " with number " & n
  1325.             exit repeat -------------- return ---------->
  1326.         end try
  1327.     end repeat
  1328.     return theOutput
  1329. end replaceCharacter
  1330.  
  1331. -- ------------------------------------------------------
  1332. (*
  1333. splitTextToList seems to be what you are trying to do
  1334.   thisText is the input string
  1335.   delim is what to split on
  1336.  
  1337.   results returned in a list
  1338.  
  1339.   Total hack. We know splitTextToList strips of delim so add it back.
  1340. *)
  1341.  
  1342. on splitTextToList(thisText, delim)
  1343.     global debug
  1344.     if debug ≥ 5 then log "in ~~~ splitTextToList ~~~"
  1345.    
  1346.     set returnedList to textToList(thisText, delim)
  1347.     set resultArray to {}
  1348.     copy item 1 of returnedList to the end of the resultArray
  1349.    
  1350.     repeat with i from 2 to (count of returnedList) in returnedList
  1351.         set newElement to delim & item i of returnedList
  1352.         copy newElement to the end of the resultArray
  1353.     end repeat
  1354.    
  1355.     return resultArray
  1356. end splitTextToList
  1357.  
  1358. -- ------------------------------------------------------
  1359. (*
  1360.   Retrieved data between "begin" and "end" tag. Whatever is between the strings.
  1361. *)
  1362. on tagContent(theString, startTag, endTag)
  1363.     global debug
  1364.     if debug ≥ 5 then log "in ~~~ tagContent ~~~"
  1365.     try
  1366.         if debug ≥ 5 then log "in tabContent. " & return & "    startTag is " & startTag & " endTag is " & endTag
  1367.         set beginningOfTag to chompLeftAndTag(theString, startTag)
  1368.         if length of beginningOfTag ≤ 0 then
  1369.             set middleText to ""
  1370.         else
  1371.             printHeader("beginningOfTag", beginningOfTag)
  1372.             set endingOffset to (offset of endTag in beginningOfTag)
  1373.            
  1374.             if endingOffset ≤ (length of endTag) then
  1375.                 set middleText to ""
  1376.             else
  1377.                 set middleText to text 1 thru (endingOffset - 1) of beginningOfTag
  1378.                 printHeader("middleText is ", middleText)
  1379.             end if
  1380.         end if
  1381.     on error errMsg number n
  1382.         log "==> finding contained text failed. " & errMsg & " with number " & n
  1383.         set middleText to ""
  1384.     end try
  1385.     if debug ≥ 5 then log "returning with middleText is " & middleText
  1386.     return middleText
  1387. end tagContent
  1388. -- ------------------------------------------------------
  1389. (*
  1390. textToList seems to be what you are trying to do
  1391.   thisText is the input string
  1392.   delim is what to split on
  1393.  
  1394.   returns a list of strings.  
  1395.  
  1396. - textToList was found here:
  1397. - http://macscripter.net/viewtopic.php?id=15423
  1398.  
  1399. *)
  1400.  
  1401. on textToList(thisText, delim)
  1402.     global debug
  1403.     if debug ≥ 5 then log "in ~~~ textToList ~~~"
  1404.     set resultList to {}
  1405.     set {tid, my text item delimiters} to {my text item delimiters, delim}
  1406.    
  1407.     try
  1408.         set resultList to every text item of thisText
  1409.         set my text item delimiters to tid
  1410.     on error
  1411.         set my text item delimiters to tid
  1412.     end try
  1413.     return resultList
  1414. end textToList
  1415.  
  1416. -- ------------------------------------------------------
  1417. on trimCharacters(inputTrim, outputTrim, reduce)
  1418.     global debug
  1419.     if debug ≥ 3 then
  1420.         log "in ~~~ trimCharacters ~~~"
  1421.         log "  trimCharacters: length of inputTrim is" & getIntegerAndHex(length of inputTrim)
  1422.         hexDumpFormatOne("  trimCharacters: inputTrim", inputTrim)
  1423.         log "  trimCharacters: length of outputTrim is " & getIntegerAndHex(length of outputTrim)
  1424.         hexDumpFormatOne("  trimCharacters: outputTrim", outputTrim)
  1425.         log "  trimCharacters: with reduce >" & reduce & "<  "
  1426.     end if
  1427.     set repCount to 1
  1428.    
  1429.     repeat while length of inputTrim ≥ 1 and text 1 thru 1 of inputTrim is " "
  1430.         set {inputTrim, outputTrim} to trimOneChar(inputTrim, outputTrim, 1, "")
  1431.         if debug ≥ 6 then
  1432.             log "  trimCharacters: repCount is " & repCount
  1433.             set repCount to repCount + 1
  1434.             log "  trimCharacters: length of inputTrim is" & getIntegerAndHex(length of inputTrim)
  1435.             hexDumpFormatOne("  trimCharacters: cycling inputTrim", inputTrim)
  1436.             log "  trimCharacters: length of outputTrim is " & getIntegerAndHex(length of outputTrim)
  1437.             hexDumpFormatOne("  trimCharacters: cycling outputTrim", outputTrim)
  1438.            
  1439.         end if
  1440.     end repeat
  1441.    
  1442.     if debug ≥ 3 then
  1443.         log "  trimCharacters: length of inputTrim is" & getIntegerAndHex(length of inputTrim)
  1444.         hexDumpFormatOne("  trimCharacters: completed inputTrim", inputTrim)
  1445.         log "  trimCharacters: length of outputTrim is " & getIntegerAndHex(length of outputTrim)
  1446.         hexDumpFormatOne("  trimCharacters: completed outputTrim", outputTrim)
  1447.         log "bye from  ~.~ trimCharacters ~.~"
  1448.     end if
  1449.     return {inputTrim, outputTrim}
  1450. end trimCharacters
  1451.  
  1452. -- ------------------------------------------------------
  1453. on trimOneChar(inputLf, outputTrimmed, theLfOffset, substitueCharacter)
  1454.     global debug
  1455.    
  1456.     if debug ≥ 3 then
  1457.         log "in ~~~ trimOneChar ~~~"
  1458.         hexDumpFormatOne("inputLf", inputLf)
  1459.         hexDumpFormatOne("outputTrimmed", outputTrimmed)
  1460.         log "theLfOffset, is " & getIntegerAndHex(theLfOffset)
  1461.         log "with substitueCharacter >" & substitueCharacter & "<  "
  1462.     end if
  1463.    
  1464.     -- check boundaries
  1465.     if theLfOffset ≤ 0 or (theLfOffset > (length of inputLf)) then
  1466.         -- We are almost done.
  1467.         log "no LF found."
  1468.         -- tack on any trialing stuff
  1469.         set outputTrimmed to outputTrimmed & inputLf
  1470.         set inputLf to ""
  1471.         if debug ≥ 3 then
  1472.             hexDumpFormatOne("inputLf", inputLf)
  1473.             hexDumpFormatOne("outputTrimmed", outputTrimmed)
  1474.         end if
  1475.         return {inputLf, outputTrimmed} ------------ return ------------>
  1476.     end if
  1477.    
  1478.     -- We need to deal with output first, so we haven't trimmed the input we need.
  1479.     if theLfOffset ≥ 2 then
  1480.         if debug ≥ 6 then log "  theLfOffset ≥ 2"
  1481.         set outputTrimmed to outputTrimmed & (text 1 thru (theLfOffset - 1) of inputLf) & substitueCharacter
  1482.     else if theLfOffset = 1 then
  1483.         if debug ≥ 6 then log "  theLfOffset = 1"
  1484.         -- no stuff before the lf
  1485.         set outputTrimmed to outputTrimmed & substitueCharacter
  1486.     end if
  1487.    
  1488.     -- deal with inputLf.
  1489.     if theLfOffset < (length of inputLf) then
  1490.         if debug ≥ 6 then log "  theLfOffset < (length of inputLf) "
  1491.         -- trailing stuff
  1492.         set inputLf to text (theLfOffset + 1) thru -1 of inputLf
  1493.     else if theLfOffset is (length of inputLf) then
  1494.         if debug ≥ 6 then log "  theLfOffset is (length of inputLf) "
  1495.         set inputLf to ""
  1496.     end if
  1497.    
  1498.     if debug ≥ 3 then
  1499.         hexDumpFormatOne("inputLf", inputLf)
  1500.         hexDumpFormatOne("outputTrimmed", outputTrimmed)
  1501.     end if
  1502.     if debug ≥ 4 then log "bye from  ~.~ trimOneChar ~.~"
  1503.     return {inputLf, outputTrimmed}
  1504.    
  1505. end trimOneChar
  1506.  
  1507. -- ------------------------------------------------------
  1508. (*
  1509.          Unix-like systems      LF      0A      \n
  1510.             (Linux, macOS)
  1511.                Microsoft Windows    CRLF    0D 0A   \r\n
  1512.                classic Mac OS       CR      0D          \r   Applescript return
  1513.   *)
  1514. on typeText(theData)
  1515.    
  1516.     global debug
  1517.     if debug ≥ 5 then log "in ~~~ typeText ~~~"
  1518.     set lf to character id 1
  1519.    
  1520.     if debug ≥ 2 then printHeader("the input  ( theData )", theData)
  1521.     -- Example: -- https://discussions.apple.com/docs/DOC-8841
  1522.     -- locate links
  1523.    
  1524.     set theOutputBuffer to adjustURLs(theData)
  1525.    
  1526.     -- add paragraphs
  1527.     set theOutputBuffer to addParagraphs(theOutputBuffer)
  1528.    
  1529.     if debug ≥ 2 then log "theOutputBuffer is " & return & theOutputBuffer
  1530.     if debug ≥ 4 then log "bye from  -.- typeText -.-"
  1531.     return theOutputBuffer
  1532. end typeText
  1533.  
  1534. -- ------------------------------------------------------
  1535. (* 
  1536.  place debuging data on cipboard
  1537.  has a big side effect.  
  1538. *)
  1539. on wrapupClipboardDataSelector()
  1540.     return "Global Lyme Alliance Reveals Several Drugs and Drug Combinations That Show Success in Treating Lyme Disease
  1541. https://globallymealliance.org/press-releases/global-lyme-alliance-reveals-several-drugs-drug-combinations-show-success-treating-lyme-disease/?utm_source=Newsletter&utm_campaign=220eebaf84-EMAIL_CAMPAIGN_2019_04_18_03_43&utm_medium=email&utm_term=0_2eb359dd6a-220eebaf84-37014111
  1542.  
  1543. https://www.omf.ngo/community-symposium-2/
  1544. Saturday, September 7, 2019
  1545. Live streamed
  1546. https://www.omf.ngo/community-symposium-2/
  1547.  
  1548.  
  1549. New OMF-funded Research Publication: A Nanoelectronics-blood-based diagnostic biomarker for ME/CFS
  1550.  
  1551. Dr. Ron Davis, OMF Scientific Advisory Board Director, explains the PNAS publication on the nanoneedle (April 29, 2019)
  1552.  
  1553. A paper describing the nanoneedle was published in the Proceedings of the National Academy of Sciences. Ronald W. Davis, PhD, is the senior author. Rahim Esfandyarpour, PhD, is the lead author. The nanoneedle is a test that measures changes in immune cells with their blood plasma as a result of salt stress. Inside the nanoneedle, the immune cells interfere with a small electric current. The change in electrical activity is directly correlated with the health of the sample. The test, which is still in a pilot phase, is based on how a person’s immune cells respond to stress. With blood samples from 40 people — 20 with ME/CFS and 20 without — the test yielded precise results, accurately flagging all patients and none of the healthy individuals.
  1554.  
  1555.  
  1556. https://www.youtube.com/watch?v=6Qn0fIV8SbE&feature=youtu.be"
  1557.    
  1558. end wrapupClipboardDataSelector
  1559. (*
  1560.     return "<p> </p><p> </p><p>If you are unable to set up \"two-factor authentication,\" you should set up \"2-step.\"
  1561.    
  1562.    
  1563.  
  1564.  
  1565. Run etrecheck.  The
  1566. first five runs are free.</p> "
  1567. *)
  1568.  
  1569. (* 
  1570. set the clipboard to "<html><p>As you are using a non-Apple app to access your email or other  facilities, you are now required to use an 'app-specific' password in place of your normal iCloud password. In order to do this you need to set up two-factor authentication for your Apple ID, and for this you need to have either a Mac running El Capitan or above, or an iOS device running iOS9 or above.</p><p> </p><p><a href=\"https://support.apple.com/HT204915\" target=\"_blank\">Two-factor authentication for Apple ID - Apple Support</a></p><p> </p><p><a href=\"https://support.apple.com/HT204397\" target=\"_blank\">Using app-specific passwords - Apple Support</a></p><p> </p><p>If you are unable to set up \"two-factor authentication,\" you should set up \"2-step.\"
  1571.    
  1572.    
  1573.  
  1574.  
  1575. Run etrecheck.  The
  1576. first five runs are free. Provided a report on your
  1577. machines hardware and software.  Great for diagnosing your system.  Click on the download
  1578. link at the bottom of the screen.
  1579. <a href=\"http://etrecheck.com/\" target=\"_blank\">EtreCheck</a></p><p></p>
  1580. <p></p><p>
  1581. <ol>
  1582. <li>point 1</li>
  1583. <li>point 2</li>
  1584. <li>point 3</li>
  1585. </ol>
  1586. </p>
  1587. <p>the end</p>
  1588.  
  1589. </ol></p><p>
  1590. "
  1591. *)
  1592. (*
  1593. https://www.oreilly.com/library/view/applescript-the-definitive/0596102119/re89.html
  1594.  
  1595. https://stackoverflow.com/questions/11085654/apple-script-how-can-i-copy-html-content-to-the-clipboard
  1596.  
  1597. -- user has copied a file's icon in the Finder
  1598. clipboard info
  1599. -- {{string, 20}, {«class ut16», 44}, {«class hfs », 80}, {«class
  1600.  utf8», 20}, {Unicode text, 42}, {picture, 2616}, {«class icns», 43336},
  1601. {«class furl», 62}}
  1602.  
  1603. textutil -convert html foo.rtf
  1604.  
  1605. if ((clipboard info) as string) contains "«class furl»" then
  1606.         log "the clipboard contains a file named " & (the clipboard as string)
  1607.     else
  1608.         log "the clipboard does not contain a file"
  1609.     end if
  1610.    
  1611. the clipboard       required
  1612. as  class   optional
  1613.  
  1614. tell application "Script Editor"
  1615.         activate
  1616.     end tell
  1617.    
  1618. textutil has a simplistic text to html conversion
  1619.     set clipboardDataQuoted to quoted form of theData
  1620.     log "quoted form is " & clipboardDataQuoted
  1621.    
  1622.     set toUnix to "/bin/echo -n " & clipboardDataQuoted
  1623.     set toUnix to toUnix & " | textutil -convert html -noload -nostore -stdin -stdout "
  1624.     log "toUnix is " & toUnix
  1625.     set fromUnix to do shell script toUnix
  1626.     log "fromUnix  is " & fromUnix
  1627.    
  1628.    
  1629. set s to "Today is my birthday"
  1630. log text 1 thru ((offset of "my" in s) - 1) of s
  1631. --> "Today is "
  1632.             -- text 1 thru ((offset of "my" in s) - 1) of s
  1633.             -- -1 since offset return the first character "m" position count
  1634.            
  1635. log "beginningOfTag is " & text 1 thru (minimumPositiveNumber from {200, length of beginningOfTag}) of beginningOfTag & "<+++++++++++++++++++++++"
  1636.  
  1637. https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html
  1638.  
  1639. *)
  1640.  
  1641. --mac $ hex=`echo -n "<p>your html code here</>" | hexdump -ve '1/1 "%.2x"'`
  1642. --mac $ echo $hex
  1643. --3c703e796f75722068746d6c20636f646520686572653c2f3e
  1644. --mac $ osascript -e "set the clipboard to «data HTML${hex}»"
  1645. --mac $
  1646. (*  
  1647. A sub-routine for encoding ASCII characters.  
  1648.  
  1649. encode_char("$")  
  1650. --> returns: "%24"  
  1651.  
  1652. based on:  
  1653. https://www.macosxautomation.com/applescript/sbrt/sbrt-08.html  
  1654.  
  1655. *)
  1656. (*
  1657. Lowest Numeric Value in a List
  1658.  
  1659. This sub-routine will return the lowest numeric value in a list of items. The passed list can contain non-numeric data as well as lists within lists. For example:
  1660.  
  1661. lowest_number({-3.25, 23, 2345, "sid", 3, 67})
  1662. --> returns: -3.25
  1663. lowest_number({-3.25, 23, {-22, 78695, "bob"}, 2345, true, "sid", 3, 67})
  1664. --> returns: -22
  1665.  
  1666. If there is no numeric data in the passed list, the sub-routine will return a null string ("")
  1667.  
  1668. lowest_number({"this", "list", "contains", "only", "text"})
  1669. --> returns: ""
  1670.  
  1671. https://macosxautomation.com/applescript/sbrt/sbrt-03.html
  1672.  
  1673. Here's the sub-routine:
  1674.  
  1675. *)
  1676. (*
  1677. on lowestNumber(values_list)
  1678.     set the low_amount to ""
  1679.     repeat with i from 1 to the count of the values_list
  1680.         set this_item to item i of the values_list
  1681.         set the item_class to the class of this_item
  1682.         if the item_class is in {integer, real} then
  1683.             if the low_amount is "" then
  1684.                 set the low_amount to this_item
  1685.             else if this_item is less than the low_amount then
  1686.                 set the low_amount to item i of the values_list
  1687.             end if
  1688.         else if the item_class is list then
  1689.             set the low_value to lowest_number(this_item)
  1690.             if the the low_value is less than the low_amount then ¬
  1691.                 set the low_amount to the low_value
  1692.         end if
  1693.     end repeat
  1694.     return the low_amount
  1695. end lowestNumber
  1696.  
  1697. https://lists.apple.com/archives/applescript-users/2010/Sep/msg00139.html
  1698. set list_of_values to {10, 20, 30, 40, 50, 60, 2000, 9, 3000, 4}
  1699.  
  1700. set minimum to 9.9999999999E+12
  1701. set maximum to 0
  1702. repeat with ref_to_value in list_of_values
  1703.     set the_value to contents of ref_to_value
  1704.     if the_value > maximum then set maximum to the_value
  1705.     if the_value < minimum then set minimum to the_value
  1706. end repeat
  1707.  
  1708. {minimum, maximum}
  1709.  
  1710. may do the trick.
  1711.  
  1712. Yvan KOENIG (VALLAURIS, France) lundi 13 septembre 2010 22:32:41
  1713. *)
  1714. (* https://lists.apple.com/archives/applescript-users/2010/Sep/msg00139.html
  1715. set list_of_values to {10, 20, 30, 40, 50, 60, 2000, 9, 3000, 4}
  1716.  
  1717. set minimum to 9.9999999999E+12
  1718.  
  1719. assume it's limited to positive values
  1720.  
  1721.  
  1722. on maxValue(list_of_values)
  1723.     global debug
  1724.     if debug ≥ 5 then log "in maxValue " & return & list_of_values
  1725.     set maximum to 0
  1726.     repeat with ref_to_value in list_of_values
  1727.         set the_value to contents of ref_to_value
  1728.         if the_value > maximum then set maximum to the_value
  1729.     end repeat
  1730.     if debug ≥ 5 then log maximum
  1731.     return maximum
  1732. end maxValue
  1733. *)
  1734. -- ------------------------------------------------------
  1735. (*
  1736. http://harvey.nu/applescript_url_encode_routine.html
  1737.  
  1738. on urlencode(theText)
  1739.     set theTextEnc to ""
  1740.     repeat with eachChar in characters of theText
  1741.         set useChar to eachChar
  1742.         set eachCharNum to ASCII number of eachChar
  1743.         if eachCharNum = 32 then
  1744.             set useChar to "+"
  1745.         else if (eachCharNum ≠ 42) and (eachCharNum ≠ 95) and (eachCharNum < 45 or eachCharNum > 46) and (eachCharNum < 48 or eachCharNum > 57) and (eachCharNum < 65 or eachCharNum > 90) and (eachCharNum < 97 or eachCharNum > 122) then
  1746.             set firstDig to round (eachCharNum / 16) rounding down
  1747.             set secondDig to eachCharNum mod 16
  1748.             if firstDig > 9 then
  1749.                 set aNum to firstDig + 55
  1750.                 set firstDig to ASCII character aNum
  1751.             end if
  1752.             if secondDig > 9 then
  1753.                 set aNum to secondDig + 55
  1754.                 set secondDig to ASCII character aNum
  1755.             end if
  1756.             set numHex to ("%" & (firstDig as string) & (secondDig as string)) as string
  1757.             set useChar to numHex
  1758.         end if
  1759.         set theTextEnc to theTextEnc & useChar as string
  1760.     end repeat
  1761.     return theTextEnc
  1762. end urlencode
  1763.  
  1764. Clipboard classes after a copy from the application.
  1765. from waterfox
  1766. (*«class HTML», 13876, «class utf8», 505, «class ut16», 1012, string, 505, Unicode text, 1010*)
  1767.  
  1768. from chrome
  1769. (*«class HTML», 748, «class utf8», 204, «class ut16», 410, string, 204, Unicode text, 408*)
  1770.  
  1771. from safari
  1772. (*«class weba», 120785, «class RTF », 70255, «class HTML», 122811, «class utf8», 3370, «class ut16», 6772, uniform styles, 47132, string, 3385, scrap styles, 8122, Unicode text, 6732, uniform styles, 47132, scrap styles, 8122*)
  1773.  
  1774. iCab
  1775. (*«class weba», 1665, «class RTF », 763, «class utf8», 121, «class ut16», 244, uniform styles, 376, string, 121, scrap styles, 62, Unicode text, 242, uniform styles, 376, scrap styles, 62*)
  1776.  
  1777. Opera
  1778. (*«class HTML», 5767, «class utf8», 150, «class ut16», 302, string, 150, Unicode text, 300*)
  1779.  
  1780. Textedit
  1781. (*«class RTF », 1136, «class utf8», 138, «class ut16», 278, uniform styles, 148, string, 138, scrap styles, 22, Unicode text, 276, uniform styles, 148, scrap styles, 22*)
  1782.  
  1783. Word
  1784. (*«class DSIG», 4, «class DOBJ», 56, «class OBJD», 244, «class RTF », 30573, «class HTML», 21160, scrap styles, 22, uniform styles, 136, string, 210, Unicode text, 420, «class PDF », 13197, picture, 154058, «class EMBS», 33280, «class LNKS», 909, «class LKSD», 244, «class OJLK», 93, «class HLNK», 1387, «class OFSC», 232, «class ut16», 422, «class DSIG», 4, «class DOBJ», 56, «class OBJD», 244, scrap styles, 22, uniform styles, 136, «class EMBS», 33280, «class LNKS», 909, «class LKSD», 244, «class OJLK», 93, «class HLNK», 1387, «class OFSC», 232*)
  1785.  
  1786. TextWrangler
  1787. (*«class utf8», 185, «class BBLM», 4, «class ut16», 372, string, 185, Unicode text, 370, «class BBLM», 4*)
  1788.  
  1789. *)
  1790.  
  1791.  
  1792.  
  1793. (*
  1794.     set the clipboard to "<html><p>As you are using a non-Apple app to access your email or other  facilities, you are now required to use an 'app-specific' password in place of your normal iCloud password. In order to do this you need to set up two-factor authentication for your Apple ID, and for this you need to have either a Mac running El Capitan or above, or an iOS device running iOS9 or above.</p><p> </p><p><a href=\"https://support.apple.com/HT204915\" target=\"_blank\">Two-factor authentication for Apple ID - Apple Support</a></p><p> </p><p><a href=\"https://support.apple.com/HT204397\" target=\"_blank\">Using app-specific passwords - Apple Support</a></p><p> </p><p>If you are unable to set up two-factor authentication you should set up 2-step \"
  1795.    
  1796.    
  1797.  
  1798.  
  1799. Run etrecheck.  The
  1800. first five runs are free. Provided a report on your
  1801. machines hardware and software.  Great for diagnosing your system.  Click on the download
  1802. link at the bottom of the screen.
  1803. <a href=\"http://etrecheck.com/\" target=\"_blank\">EtreCheck</a></p><p></p>
  1804. <p></p><p>
  1805. <ol>
  1806. <li>point 1</li>
  1807. <li>point 2</li>
  1808. <li>point 3</li>
  1809. </ol>
  1810.  </p>
  1811. <p>the end</p>
  1812. "
  1813.     *)
  1814. (*  set the clipboard to "<p>Simple put, Apple attempts
  1815. to provide all the
  1816. malware detection and removal you need in Mac OS X.</p>
  1817. <p></p><p></p><p></p>
  1818. <p>\"Effective defenses against malware and other threats\" by John Galt
  1819. <a href=\"https://discussions.apple.com/docs/DOC-8841\" target=\"_blank\">Effective
  1820. defenses against malware and ot… - Apple Community</a>
  1821. </p><pre>
  1822. code line #a
  1823. code line #b
  1824. code line #c
  1825. </pre><p> </p><p>\"Avoid phishing emails, fake 'virus' alerts, phony support calls, and other scams\"
  1826. <a href=\"https://support.apple.com/en-ca/HT204759\">Avoid phishing emails, fake
  1827. 'virus' alerts, phony support calls, and other scams - Apple Support</a>
  1828. <pre>
  1829. code line #1
  1830. code line #2
  1831. code line #3
  1832. </pre>"
  1833. *)
  1834. (*
  1835.     set the clipboard to "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
  1836. <html>
  1837.   <head>
  1838.  
  1839.     <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">
  1840.     <title>asc roger's help text</title>
  1841.   </head>
  1842.   <body>
  1843.     <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">
  1844.     <span style=\"font-weight: bold; font-family: Lucida Grande;\">App-Specific
  1845.       passwords</span> (copy direct,
  1846.     clean up returns)<br>
  1847.     <br>
  1848.     There are apps in the Play Store to sync calendars and contacts -
  1849.     search on
  1850.     Smoothsync for two of the best. <br>
  1851.     <br>
  1852.     iCloud mail is standard IMAP and you
  1853.     can access it in the mail application using the settings here:<br>
  1854.     <br>
  1855.     <a href=\"https://support.apple.com/HT202304\">https://support.apple.com/HT202304</a><br>
  1856.     <br>
  1857.     As you are using a non-Apple app to access your email or other&nbsp;
  1858.     facilities, you are now required to use an 'app-specific' password
  1859.     in
  1860.     place of your normal iCloud password. In order to do this you need
  1861.     to
  1862.     set up two-factor authentication for your Apple ID, and for this you
  1863.     need to have either a Mac running El Capitan or above, or an iOS
  1864.     device
  1865.     running iOS9 or above.<br>
  1866.     <br>
  1867.     <a href=\"https://support.apple.com/HT204915\">https://support.apple.com/HT204915</a><br>
  1868.     <br>
  1869.     <a href=\"https://support.apple.com/HT204397\">https://support.apple.com/HT204397</a><br>
  1870.     <br>
  1871.     If you are unable to set up two-factor authentication you should set
  1872.     up
  1873.     2-step verification and use that to create an app-specific password
  1874.     (see link below) . Then go
  1875.     to https://appleid.apple.com , select 'Password and Security'; click
  1876.     'Generate an App-Specific
  1877.     Password' and follow the instructions. Once you have the password,
  1878.     copy
  1879.     it and paste it into the password field in the application instead
  1880.     of
  1881.     your usual iCloud password. You should also keep a note of it
  1882.     (though
  1883.     you can generate a new one if required).<br>
  1884.     <br>
  1885.     <a href=\"https://support.apple.com/kb/HT204152\">https://support.apple.com/kb/HT204152</a><br>
  1886.     <br>
  1887.     You will need to nominate a 'trusted device' - any phone capable of
  1888.     receiving SMS messages. There will be a 2-day wait before you can
  1889.     complete the process.<br>
  1890.     (A particular caveat (about 2-step only) - you will be issued with a
  1891.     'Recovery Key' in case you lose your 'trusted device'. Make sure to
  1892.     write this down and keep it in a safe place; if you lose both it and
  1893.     your trusted device you will be permanently locked out of your ID.
  1894.     You'd be surprised at the number of people who've posted here that
  1895.     they've got themselves into just that position.)<br>
  1896.     <br>
  1897.     Incidentally, Mail on Snow Leopard and earlier is not recognized as
  1898.     an
  1899.     Apple application because it's pre-iCloud and doesn't have the
  1900.     necessary facilities, so it will be necessary to obtain an
  1901.     app-specific
  1902.     password for that.
  1903.   </body>
  1904. </html>
  1905.  
  1906. <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
  1907. <html>
  1908.   <head>
  1909.  
  1910.     <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">
  1911.     <title>asc roger's help text</title>
  1912.   </head>
  1913.   <body>
  1914.     <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">
  1915.     <span style=\"font-weight: bold; font-family: Lucida Grande;\">App-Specific
  1916.       passwords</span> (copy direct,
  1917.     clean up returns)<br>
  1918.     <br>
  1919.     There are apps in the Play Store to sync calendars and contacts -
  1920.     search on
  1921.     Smoothsync for two of the best. <br>
  1922.     <br>
  1923.     iCloud mail is standard IMAP and you
  1924.     can access it in the mail application using the settings here:<br>
  1925.     <br>
  1926.     <a href=\"https://support.apple.com/HT202304\">https://support.apple.com/HT202304</a><br>
  1927.     <br>
  1928.     As you are using a non-Apple app to access your email or other&nbsp;
  1929.     facilities, you are now required to use an 'app-specific' password
  1930.     in
  1931.     place of your normal iCloud password. In order to do this you need
  1932.     to
  1933.     set up two-factor authentication for your Apple ID, and for this you
  1934.     need to have either a Mac running El Capitan or above, or an iOS
  1935.     device
  1936.     running iOS9 or above.<br>
  1937.     <br>
  1938.     <a href=\"https://support.apple.com/HT204915\">https://support.apple.com/HT204915</a><br>
  1939.     <br>
  1940.     <a href=\"https://support.apple.com/HT204397\">https://support.apple.com/HT204397</a><br>
  1941.     <br>
  1942.     If you are unable to set up two-factor authentication you should set
  1943.     up
  1944.     2-step verification and use that to create an app-specific password
  1945.     (see link below) . Then go
  1946.     to https://appleid.apple.com , select 'Password and Security'; click
  1947.     'Generate an App-Specific
  1948.     Password' and follow the instructions. Once you have the password,
  1949.     copy
  1950.     it and paste it into the password field in the application instead
  1951.     of
  1952.     your usual iCloud password. You should also keep a note of it
  1953.     (though
  1954.     you can generate a new one if required).<br>
  1955.     <br>
  1956.     <a href=\"https://support.apple.com/kb/HT204152\">https://support.apple.com/kb/HT204152</a><br>
  1957.     <br>
  1958.     You will need to nominate a 'trusted device' - any phone capable of
  1959.     receiving SMS messages. There will be a 2-day wait before you can
  1960.     complete the process.<br>
  1961.     (A particular caveat (about 2-step only) - you will be issued with a
  1962.     'Recovery Key' in case you lose your 'trusted device'. Make sure to
  1963.     write this down and keep it in a safe place; if you lose both it and
  1964.     your trusted device you will be permanently locked out of your ID.
  1965.     You'd be surprised at the number of people who've posted here that
  1966.     they've got themselves into just that position.)<br>
  1967.     <br>
  1968.     Incidentally, Mail on Snow Leopard and earlier is not recognized as
  1969.     an
  1970.     Apple application because it's pre-iCloud and doesn't have the
  1971.     necessary facilities, so it will be necessary to obtain an
  1972.     app-specific
  1973.     password for that.
  1974.   </body>
  1975. </html>
  1976. "
  1977. *)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement