Fix to Dates.HttpDate

Fix to Dates.HttpDate

:Namespace Dates

    (⎕ML ⎕IO)←1

    ∇ r←CookieFmt date;day;date;mon
         ⍝ Format date for cookie expiry
         ⍝ "expires Mon, 09-Dec-2002 13:46:00 GMT"

      day←(7 3⍴'MonTueWedThuFriSatSun')[WeekDay date;]
      mon←(12 3⍴'janfebmaraprmayjunjulaugsepoctnovdec')[2⊃date;]
      r←,('<',day,', >,ZI2,<-',mon,'->,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴(6↑date)[3 1 4 5 6]
    ∇

    ∇ r←{minOffset}HttpDate ts;sign;day;mon;ver;⎕USING;t
    ⍝ return RCF 1123/822 compliant date
    ⍝ minOffset is option number of minutes to offset time with (used for HTTP caching expirations)
      minOffset←{0::0 ⋄ minOffset}''
      ts←6↑ts
      :If 0=⎕NC'_UtcOffset'
          :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
              :Hold '_UtcOffset'
                  ⎕USING←,⊂''
                  _UtcOffset←¯60×(System.TimeZone.CurrentTimeZone.GetUtcOffset ⎕NEW System.DateTime(ts)).Hours
              :EndHold
          :Else
              :If (⊂ver)∊'Lin' 'AIX' 'Sol'
                  _UtcOffset←¯60×⍎¯2↓{⍵↑⍨-' '⍳⍨⌽⍵}⊃⎕SH'date -R'
              :Else
                  _UtcOffset←0 ⍝ otherwise, assume GMT
              :EndIf
          :EndIf
      :EndIf
      ts←IDNToDate((_UtcOffset+minOffset)÷24×60)+t←DateToIDN ts
      day←(7 3⍴'MonTueWedThuFriSatSun')[1+7|(⌊t)-1;]
      mon←(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[2⊃ts;]
      r←,('<',day,', >,ZI2,< ',mon,' >,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴ts[3 1 4 5 6]
    ∇

    ∇ SM←DateToIDN TS                  ⍝ Convert date format
      SM←2 ⎕NQ'.' 'DateToIDN'(3↑TS)
      :If 3<⍴TS
          SM+←(24 60 60 1000⊥4↑3↓TS)÷86400000
      :EndIf
    ∇

    ∇ TS←IDNToDate SM                ⍝ Convert IDN to date format : 3↑⎕TS ← IDN (akd TS_SM)
      TS←3↑2 ⎕NQ'.' 'IDNToDate'(⌊SM)
      TS,←⌊0.5+24 60 60 1000⊤86400000×1|SM
    ∇

    ∇ new←ts IdnAdd t
    ⍝ T is D HH MM SS
      new←ts+(0 24 60 60 1000⊥¯5↑t,0)÷86400000
    ∇

    ∇ r←Now
      r←DateToIDN ⎕TS
    ∇

    ∇ r←TSFmt ts
      r←,'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2'⎕FMT 1 5⍴ts
    ∇

    ∇ r←TSFmtNice ts;now;yday;today;z;i;m;idn;s
    ⍝ Format a vector of IDN's nicely
      s←⍴ts
      yday←¯1+today←⌊now←DateToIDN ⎕TS
      r←↑IDNToDate¨,ts←,ts ⍝ Make matrix
      r←'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2'⎕FMT 5↑[2]r
      :If 0≠⍴i←((ts≥yday)∧~m←ts≥today)/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Yesterday'
      :EndIf
      :If 0≠⍴i←m/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Today'
      :EndIf
      :If 0≠⍴i←(100>z←⌊(now-ts)×24×60)/⍳⍴ts
          r[i;]←16↑[2]↑(⍕¨⌊z[i]),¨(' minutes ago' ' minute ago')[1+1=z[i]]
      :EndIf
      :If 0≠⍴i←(z<1)/⍳⍴ts
          r[i;]←((⍴i),16)⍴16↑'Now'
      :EndIf
      r←(s,¯1↑⍴r)⍴r
    ∇

    ∇ r←WeekDay Date
    ⍝ Return weekday (Monday=1, Sunday=7)
      r←1+7|(DateToIDN 3↑Date)-1
    ∇

    ∇ r←LogFmtNow;ver
    ⍝ returns now UTC adjusted, and formatted for log files (Common Log Format)
      :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
          r←((⍎⎕NA'kernel32|GetSystemTime >{U2 U2 U2 U2 U2 U2 U2 U2}')⊂8⍴0)[4 2 1 5 6 7]
          r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
          r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
      :Else
          r←1⊃⎕SH'date +" [%d/%b/%Y:%T %z] "'
      :EndIf
    ∇

    ∇ r←LogFmt ymdhms
      r←ymdhms[3 2 1 4 5 6]
      r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
      r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
    ∇

    ∇ ts←FTT fts;md;shape;tmp;yr;z;⎕IO
     ⍝ *** convert ⎕FRDCI/⎕FHIST timestamp(s) to ⎕ts-format for Dyalog/W ***
     ⍝ right argument: ⎕FRDCI-type timestamp(s) of any shape
     ⍝ result: ⎕ts-type timestamp(s) with shape <(⍴argument),7>
      ⎕IO←0 ⋄ shape←⍴fts ⋄ ts←,fts+18626112000
      md←365.2501|1+1461|yr←⌊ts÷5184000
      tmp←31 61 92 122 153 184 214 245 275 306 337 366
      z←(,⍉<⍀tmp∘.≥md)/,((⍴md),12)⍴⍳12
      md←(1+12|z+2),[0.1]⌈md-(0,tmp)[z]
      ts←(1960+⌊(yr+60)÷365.25),md,⍉24 60 60 60⊤ts
      ts[;6]←⌊0.5+ts[;6]×100÷6
      ts←(shape,7)⍴ts
    ∇

    ∇ r←TTF ts;l;h;d;m;y
       ⍝ convert a ⎕TS style timestamp into 60ths of a second since 1st January 1970 a la ⎕FRDCI
      l←⌈60×ts[7]÷1000                                         ⍝ convert milliseconds to 60ths
      h←3600 60 60⊥ts[4 5 6]                                   ⍝ hours minutes seconds to to the nearest seconds total
      d←ts[3]-1                                                ⍝ days since start of month
      m←(2⊃ts)⊃++\0 31,(28+0=4|⊃ts),31 30 31 30 31 31 30 31 30 ⍝ days in completed months
      y←{{(365×⍵)+⌈4÷⍨⍵-2}⍵-1970}⊃ts                           ⍝ days in years since 1970, leap years since 1972
      r←l+60×h+86400×y+m+d                                     ⍝ sum, convert to seconds, add seconds in the day convert to 60ths, add on 60ths
    ∇

:EndNamespace

:Namespace Dates

    (⎕ML ⎕IO)←1

    ∇ r←CookieFmt date;day;date;mon
         ⍝ Format date for cookie expiry
         ⍝ "expires Mon, 09-Dec-2002 13:46:00 GMT"

      day←(7 3⍴'MonTueWedThuFriSatSun')[WeekDay date;]
      mon←(12 3⍴'janfebmaraprmayjunjulaugsepoctnovdec')[2⊃date;]
      r←,('<',day,', >,ZI2,<-',mon,'->,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴(6↑date)[3 1 4 5 6]
    ∇

    ∇ r←{minOffset}HttpDate ts;sign;day;mon;ver;⎕USING;t
    ⍝ return RCF 1123/822 compliant date
    ⍝ minOffset is option number of minutes to offset time with (used for HTTP caching expirations)
      minOffset←{0::0 ⋄ minOffset}''
      ts←6↑ts
      :If 0=⎕NC'_UtcOffset'
          :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
              ⎕USING←,⊂''
              _UtcOffset←¯60×(System.TimeZone.CurrentTimeZone.GetUtcOffset ⎕NEW System.DateTime(ts)).Hours
          :Else
              :If (⊂ver)∊'Lin' 'AIX' 'Sol'
                  _UtcOffset←¯60×⍎¯2↓{⍵↑⍨-' '⍳⍨⌽⍵}⊃⎕SH'date -R'
              :Else
                  _UtcOffset←0 ⍝ otherwise, assume GMT
              :EndIf
          :EndIf
      :EndIf
      ts←IDNToDate((_UtcOffset+minOffset)÷24×60)+t←DateToIDN ts
      day←(7 3⍴'MonTueWedThuFriSatSun')[1+7|(⌊t)-1;]
      mon←(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[2⊃ts;]
      r←,('<',day,', >,ZI2,< ',mon,' >,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴ts[3 1 4 5 6]
    ∇

    ∇ SM←DateToIDN TS                  ⍝ Convert date format
      SM←2 ⎕NQ'.' 'DateToIDN'(3↑TS)
      :If 3<⍴TS
          SM+←(24 60 60 1000⊥4↑3↓TS)÷86400000
      :EndIf
    ∇

    ∇ TS←IDNToDate SM                ⍝ Convert IDN to date format : 3↑⎕TS ← IDN (akd TS_SM)
      TS←3↑2 ⎕NQ'.' 'IDNToDate'(⌊SM)
      TS,←⌊0.5+24 60 60 1000⊤86400000×1|SM
    ∇

    ∇ new←ts IdnAdd t
    ⍝ T is D HH MM SS
      new←ts+(0 24 60 60 1000⊥¯5↑t,0)÷86400000
    ∇

    ∇ r←Now
      r←DateToIDN ⎕TS
    ∇

    ∇ r←TSFmt ts
      r←,'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2'⎕FMT 1 5⍴ts
    ∇

    ∇ r←TSFmtNice ts;now;yday;today;z;i;m;idn;s
    ⍝ Format a vector of IDN's nicely
      s←⍴ts
      yday←¯1+today←⌊now←DateToIDN ⎕TS
      r←↑IDNToDate¨,ts←,ts ⍝ Make matrix
      r←'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2'⎕FMT 5↑[2]r
      :If 0≠⍴i←((ts≥yday)∧~m←ts≥today)/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Yesterday'
      :EndIf
      :If 0≠⍴i←m/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Today'
      :EndIf
      :If 0≠⍴i←(100>z←⌊(now-ts)×24×60)/⍳⍴ts
          r[i;]←16↑[2]↑(⍕¨⌊z[i]),¨(' minutes ago' ' minute ago')[1+1=z[i]]
      :EndIf
      :If 0≠⍴i←(z<1)/⍳⍴ts
          r[i;]←((⍴i),16)⍴16↑'Now'
      :EndIf
      r←(s,¯1↑⍴r)⍴r
    ∇

    ∇ r←WeekDay Date
    ⍝ Return weekday (Monday=1, Sunday=7)
      r←1+7|(DateToIDN 3↑Date)-1
    ∇

    ∇ r←LogFmtNow;ver
    ⍝ returns now UTC adjusted, and formatted for log files (Common Log Format)
      :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
          r←((⍎⎕NA'kernel32|GetSystemTime >{U2 U2 U2 U2 U2 U2 U2 U2}')⊂8⍴0)[4 2 1 5 6 7]
          r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
          r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
      :Else
          r←1⊃⎕SH'date +" [%d/%b/%Y:%T %z] "'
      :EndIf
    ∇

    ∇ r←LogFmt ymdhms
      r←ymdhms[3 2 1 4 5 6]
      r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
      r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
    ∇

    ∇ ts←FTT fts;md;shape;tmp;yr;z;⎕IO
     ⍝ *** convert ⎕FRDCI/⎕FHIST timestamp(s) to ⎕ts-format for Dyalog/W ***
     ⍝ right argument: ⎕FRDCI-type timestamp(s) of any shape
     ⍝ result: ⎕ts-type timestamp(s) with shape <(⍴argument),7>
      ⎕IO←0 ⋄ shape←⍴fts ⋄ ts←,fts+18626112000
      md←365.2501|1+1461|yr←⌊ts÷5184000
      tmp←31 61 92 122 153 184 214 245 275 306 337 366
      z←(,⍉<⍀tmp∘.≥md)/,((⍴md),12)⍴⍳12
      md←(1+12|z+2),[0.1]⌈md-(0,tmp)[z]
      ts←(1960+⌊(yr+60)÷365.25),md,⍉24 60 60 60⊤ts
      ts[;6]←⌊0.5+ts[;6]×100÷6
      ts←(shape,7)⍴ts
    ∇

    ∇ r←TTF ts;l;h;d;m;y
       ⍝ convert a ⎕TS style timestamp into 60ths of a second since 1st January 1970 a la ⎕FRDCI
      l←⌈60×ts[7]÷1000                                         ⍝ convert milliseconds to 60ths
      h←3600 60 60⊥ts[4 5 6]                                   ⍝ hours minutes seconds to to the nearest seconds total
      d←ts[3]-1                                                ⍝ days since start of month
      m←(2⊃ts)⊃++\0 31,(28+0=4|⊃ts),31 30 31 30 31 31 30 31 30 ⍝ days in completed months
      y←{{(365×⍵)+⌈4÷⍨⍵-2}⍵-1970}⊃ts                           ⍝ days in years since 1970, leap years since 1972
      r←l+60×h+86400×y+m+d                                     ⍝ sum, convert to seconds, add seconds in the day convert to 60ths, add on 60ths
    ∇

:EndNamespace


Finish Unicode APL import.

Finish Unicode APL import.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/TieDyedDevil/apl-pkg.git/'


Allow metadata file to end without a trailing newline.


new example

new example

:Class SelectSimple : MiPageSample
⍝ Control::     _.DC.Select
⍝ Description:: This example shows how to use the Select object by creating a form with 2 selections of fruits in it.
⍝ The first single selection is a drop down with no preselection. The second one is a multi selection with 2 items already selected. It occupied a whole window (not drop down). A button at the bottom resets the form to its original state.

    FRUITS←'Apples' 'Bananas' 'Grapes' 'Oranges' 'Pears' 'Pineapples' 'Plums'

    ∇ Render;frm;single;multi;btn
      :Access public

      Add _.title'_.Select Sample'
      Add _.h2'Please pick some fruits'

      (frm←Add _.Form).id←'myform'

      single←frm.Add _.Select(⊂FRUITS)  ⍝ no preselection
      frm.Add¨2/_.br

      multi←frm.Add _.Select(FRUITS(2 5)) ⍝ preselect 2nd and 5th fruit
      multi.Set'multiple' 1       ⍝ Allow multiple selections
      multi.Set'required' 1       ⍝ No post back unless there is a selection
      multi.Set'size'(⊃⍴FRUITS)   ⍝ Show them all
      multi.Set'autofocus' 'true' ⍝ Put the focus here
      frm.Add¨2/_.br

      btn←frm.Add _.button'Reset Selections'
      btn.(id type)←'pressme' 'submit'
    ∇

:EndClass

error: pathspec 'MS3/Examples/DC/SelectAdvanced.dyalog' did not match any file(s) known to git


Allow ~./apl-pkg to define programs for external editing.


Mark one more instance of the use of GNU APL's lambda. These uses should be replaced with code that conforms to ISO 13751 APL.


Add keyof and valof. Correct keys' and vals' use of nl.


new example

new example

:Class ejDateTimePickerAdvanced : MiPageSample
⍝ Control:: _SF.ejDateTimePicker
⍝ Description::  advance functionality.
⍝ Show 2 calendars to select reservation dates.
⍝ Display the time difference as result.

    ∇ Compose;today;fromidn;tbl;tr;td;head;todate;from;now;to
      :Access Public
      today←3↑now←⎕TS
      fromidn←dateToIDN today

      Add _.h2'R.U. Inn'_.br'Motel reservation system'

    ⍝ The in date
      from←'in'New _SF.ejDateTimePicker now'yyyy/MM/dd HH:mm'
    ⍝ The callback should return the date (value) of the argument for the IN date/time
    ⍝ and the model's value for the OUT date/time
      from.On'change' 'setNewDate',⊂('in' 'argument' 'value')('out' 'eval' '$("#out").ejDateTimePicker("model.value")')

    ⍝ The out date
      todate←IDNToDate fromidn+7
      to←'out'New _SF.ejDateTimePicker todate'yyyy/MM/dd HH:mm'
      to.On'change' 'setNewDate',⊂('out' 'argument' 'value')('in' 'eval' '$("#in").ejDateTimePicker("model.value")')

      Add #._.InputGrid('Check In' 'Check Out',⍪from to)

      'diff'Add _.div
    ∇

    newDate←{'⍎new Date("',(⍕⍵),'")'}
    dateToIDN←{d←2 ⎕NQ'.' 'datetoidn'⍵ ⋄ d+(60⊥3↓6↑⍵)÷86400}
    IDNToDate←{d←3↑2 ⎕NQ'.' 'idntodate'⍵ ⋄ d,0 60 60⊤⌊86400×1|⍵}

    ∇ r←setNewDate;in;out
      :Access public

    ⍝ Find the difference between the dates
      in←dateToIDN stringToDate⍕Get'in'
      out←dateToIDN 6↑{b←~⍵∊'/-:' ⋄ FI b\b/⍵}Get'out'

    ⍝ If the new IN date is not before the OUT date we reset OUT to 1 week after
      :If in>out
          r←'#diff'Replace'Going back in time?'
      :Else
          r←'#diff'Replace'The difference in days is: ',⍕out-in
      :EndIf
    ∇

    MONTHS←↓12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec'

    FI←{(b v)←⎕vfi ⍵ ⋄ b/v}

    ∇ dt←stringToDate str;pos;mon;t;ymd
     ⍝ str is of the genre "Wed Aug 05 2015 07:30:21 GMT-0400 (Eastern Daylight Time)"
     ⍝ We need to weed out the day of the week and the time
      str←(+/∧\' '=str)↓str           ⍝ remove the leading spaces
      :If 0∊⍴t←MONTHS ⎕S 0 3⊢str      ⍝ look for the month as a string. If not found
          ymd←3↑FI str                ⍝ grab the 1st 3 numbers found
          ymd←ymd[⍒(2×31<ymd)+ymd<12] ⍝ put in correct order
      :Else                           ⍝ otherwise (if found)
          (pos mon)←0 1+1⊃t
          :If ~0∊⍴t←FI pos↑str        ⍝ any number before the month? (e.g. 2 May 2021)
              ymd←⌽⍣(31<⍬⍴t)⊢(1↑FI pos↓str),mon,t
          :Else
              ymd←¯1⌽mon,2↑FI pos↓str
          :EndIf
      :EndIf
     ⍝ Now grab the time
      dt←ymd,FI⍕'(\d+):(\d+):(\d+)'⎕S'\1 \2 \3'⊢str
    ∇

:EndClass

error: pathspec 'MS3/Examples/SF/ejDateTimePickerAdvanced.dyalog' did not match any file(s) known to git


Clean up edit-file invocation; add window title.


Correct comment.

Correct comment.


Simple query of the metadata hive.

Simple query of the metadata hive.


First cut at extracting dependencies from metadata. Not quite right.


Added factorial in APL.

Added factorial in APL.

factorial ← {
  ×/1↓⍳⍵+1
}

factorial 100

error: pathspec 'Factorial/APL/jcla1/factorial.apl' did not match any file(s) known to git


Add boilerplate APL script to serve CGI webpages

I can no longer tell if I've gone insane, or I've just become bored with
web development. Probably a collusion of both.

Either way, getting this script working required some changes in the GNU
APL preferences file (interpreter built from source: v1.5 / SVN revision
694). The following settings were changed to the designated values:

  * Welcome:      No
  * Color:        No
  * SharedVars:   Disabled

That last setting is especially critical for running the APL interpreter
as a CGI handler. Since multiple arguments can't be passed to a hashbang
(at least in Apache), we can't set --script and --noSV at the same time.
This leads to an error message being spat to STDOUT when the interpreter
is invoked, screwing with the HTTP headers.

#!/usr/local/bin/apl --script
NEWLINE ← ⎕UCS 10
HEADERS ← 'Content-Type: text/plain', NEWLINE
HEADERS
⍝ ⎕←HEADERS
⍝ ⍕⎕TS
)OFF

⍝ testVars←'FUCKYEAH'
⍝ ≠\~(testVars ∊ 'AEIOU')
⍝ (124 × 4)≠(+/124 124 124)
⍝ testVars ∊ '<>'

error: pathspec 'shell/cgi.apl' did not match any file(s) known to git


A random change of 9317 to personal3.apl

error: pathspec 'personal3.apl' did not match any file(s) known to git


Fix compatibility issue. GNU APL's behavior of enclose was corrected; my code was probably incorrect from the start.


Rework the platform probes, again.

Rework the platform probes, again.


Local variable.

Local variable.


Fixed shell version check failure for shell type not recognized by probe.


Display package prefix in `]pkg packages'; add header to display.


Reorder to eliminate forward reference to fileio. This is really only relevant to a reader; it runs either way.


added pricer benchmark by Martin Dybdal

added pricer benchmark by Martin Dybdal

error: pathspec 'tests/pricer.apl' did not match any file(s) known to git


Add package dependency computation.

Add package dependency computation.


APL UTF-to-UCS conversion: optimize; correct response to empty input.


QA for ejDialogSimple. PLEASE PULL SELENIUM, as this QA relies on a new feature.

 msg←Test dummy;result;output;txt

 ⍝ The dialog should not be visible
 :If 0∊⍴msg←'dialog'WaitFor''

 ⍝ Clicking the button should open it
     Click'show'
 :AndIf 0∊⍴msg←'dialog'WaitFor'This is'

⍝ Closing the window should work too
     Click'dialog_closebutton'
     msg←'dialog'WaitFor''
 :EndIf

error: pathspec 'MS3/QA/Examples/SF/ejDialogSimple.dyalog' did not match any file(s) known to git


CheckBoxSimple QA

CheckBoxSimple QA

 msg←Test dummy;Value;Wrong;cb;ClickDoesNotMake
 Value←{⍵.GetAttribute⊂'value'}

 ClickDoesNotMake←{
     msg⊢←' wrong state',⍨id←cb.GetAttribute⊂'id'
     ⍵≢Value cb⊣Click id
 }

 msg←''

 ⍝ Each If: failure → set msg and quits
 :If 0≡cb←Find'cb1'
     msg←'cb1 not found'
 :ElseIf 'unchecked'≢Value cb
     msg←'cb1 wrong state'
 :ElseIf ClickDoesNotMake'checked'
 :ElseIf ClickDoesNotMake'unchecked'
 :ElseIf 0≡cb←Find'cb2'
     msg←'cb2 not found'
 :ElseIf 'indeterminate'≢Value cb
     msg←'cb2 wrong state'
 :ElseIf ClickDoesNotMake'unchecked'
 :ElseIf ClickDoesNotMake'checked'
 :ElseIf ClickDoesNotMake'indeterminate'
 :Else
     msg←''
 :EndIf

error: pathspec 'MS3/QA/Examples/DC/CheckBoxSimple.dyalog' did not match any file(s) known to git


Add /Utils/HTTPCommand

Add /Utils/HTTPCommand

:Class HTTPCommand
⍝ Issue an HTTP Command
⍝ Public Fields are:
⍝   Command  - the HTTP command to issue, typically 'GET' 'POST' 'PUT etc
⍝   URL      - the URL to direct the command at
⍝              format is:  [HTTP[S]://][user:pass@]url[:port][/page[?params]]
⍝   Params   - the parameters to pass with the command
⍝              for 'GET' you can pass parameters either in the URL or in Params (they will be appended to the URL)
⍝   Headers  - any additional HTTP headers to send with the request (all the obvious headers like 'content-length' are precomputed)
⍝              a vector of 2-element (header-name value) vectors or a matrix of [;1] header-name [;2] values
⍝   Cert     - if using a SSL, this is an instance of the X509Cert class
⍝   SSLFlags - if using SSL, these are the SSL flags as described in the Conga documentation
⍝   Priority - if using SSL, this is the

    ⎕ML←⎕IO←1

    :field public Command←'GET'
    :field public Cert←⍬
    :field public SSLFlags←32
    :field public LocalDRC
    :field public URL←''
    :field public Params←''
    :field public Headers←''
    :field public Priority←'NORMAL:!CTYPE-OPENPGP'
    :field public LDRC←''

    ∇ make
      :Access public
      :Implements constructor
    ∇

    ∇ make1 args
      :Access public
      :Implements constructor
      ⍝ args - [URL Params Headers Command Cert SSLFlags Priority]
      args←eis args
      Command URL Params Headers Cert SSLFlags Priority←7↑args,(⍴args)↓Command URL Params Headers Cert SSLFlags Priority
    ∇

    ∇ r←Run;resp
      :Access public
      r←⎕NS''
      :If 0∊⍴Cert
          resp←(Command HTTPCmd)URL Params Headers
      :Else
          resp←(Cert SSLFlags Priority)(Command HTTPCmd)URL Params Headers
      :EndIf
      r.(rc headers data peercert)←resp
    ∇

    ∇ r←{certs}(cmd HTTPCmd)args;url;parms;hdrs;urlparms;p;b;secure;port;host;page;x509;flags;priority;pars;auth;req;err;chunked;chunk;buffer;chunklength;done;data;datalen;header;wr;headerlen
⍝ issue an HTTP command
⍝ certs - optional [X509Cert [SSLValidation [Priority]]]
⍝ args  - [1] URL in format [HTTP[S]://][user:pass@]url[:port][/page]
⍝         {2} parameters is using POST - either a namespace or URL-encoded string
⍝         {3} HTTP headers in form {↑}(('hdr1' 'val1')('hdr2' 'val2'))
⍝ Makes secure connection if left arg provided or URL begins with https:

⍝ Result: (return code) (HTTP headers) (HTTP body) [PeerCert if secure]
      r←¯1(0 2⍴⊂'')''⍬

      :If 9≠⎕NC'LDRC'
      :AndIf 9=#.⎕NC'DRC'
          LDRC←#.DRC
      :Else
          ⎕←'Conga namespace DRC not found or defined'
          →0
      :EndIf

      {}LDRC.Init''
      args←eis args

      (url parms hdrs)←args,(⍴args)↓''(⎕NS'')''
      urlparms←''
      cmd←uc,cmd

      :If 326=⎕DR parms ⍝ if parms are a namespace, format them
          :If 'POST'≡cmd
              parms←{0∊⍴t←⍵.⎕NL ¯2:'' ⋄ 1↓⊃,/⍵{'&',⍵,'=',(⍕⍺⍎⍵)}¨t}parms
          :Else
              urlparms←{0∊⍴⍵:'' ⋄ '?',⍵}{0∊⍴t←⍵.⎕NL ¯2:'' ⋄ 1↓⊃,/⍵{'&',⍵,'=',(⍕⍺⍎⍵)}¨t}parms
              parms←''
          :EndIf
      :EndIf

     GET:
      p←(∨/b)×1+(b←'//'⍷url)⍳1
      secure←{6::⍵ ⋄ ⍵∨0<⍴,certs}(lc(p-2)↑url)≡'https:'
      port←(1+secure)⊃80 443 ⍝ Default HTTP/HTTPS port
      url←p↓url              ⍝ Remove HTTP[s]:// if present
      (host page)←'/'split url,(~'/'∊url)/'/'    ⍝ Extract host and page from url

      :If 0=⎕NC'certs' ⋄ certs←'' ⋄ :EndIf

      :If secure
          x509 flags priority←3↑certs,(⍴,certs)↓(⎕NEW LDRC.X509Cert)32 'NORMAL:!CTYPE-OPENPGP'  ⍝ 32=Do not validate Certs
          pars←('x509'x509)('SSLValidation'flags)('Priority'priority)
      :Else ⋄ pars←''
      :EndIf

      :If '@'∊host ⍝ Handle user:password@host...
          auth←'Authorization: Basic ',(b64Encode(¯1+p←host⍳'@')↑host),NL
          host←p↓host
      :Else ⋄ auth←''
      :EndIf

      (host port)←port{(⍴⍵)<ind←⍵⍳':':⍵ ⍺ ⋄ (⍵↑⍨ind-1)(1⊃2⊃⎕VFI ind↓⍵)}host ⍝ Check for override of port number

      hdrs←makeHeaders hdrs
      hdrs←'User-Agent'(hdrs addHeader)'Dyalog/Conga'
      hdrs←'Accept'(hdrs addHeader)'*/*'

      :If ~0∊⍴parms
          :If cmd≡'POST'
              hdrs←'Content-Length'(hdrs addHeader)⍴parms
              hdrs←'Content-Type'(hdrs addHeader)'application/x-www-form-urlencoded'
          :EndIf
      :EndIf

      hdrs←'Accept-Encoding'(hdrs addHeader)'gzip, deflate'

      req←cmd,' ',(page,urlparms),' HTTP/1.1',NL,'Host: ',host,NL
      req,←fmtHeaders hdrs
      req,←auth

      :If 0=⊃(err cmd)←2↑r←LDRC.Clt''host port'Text' 100000,pars ⍝ 100,000 is max receive buffer size
      :AndIf 0=⊃r←LDRC.Send cmd(req,NL,parms)

          chunked chunk buffer chunklength←0 '' '' 0
          done data datalen headerlen header←0 ⍬ 0 0 ⍬
          :Repeat
              :If ~done←0≠1⊃wr←LDRC.Wait cmd 5000            ⍝ Wait up to 5 secs
                  :If wr[3]∊'Block' 'BlockLast'             ⍝ If we got some data
                      :If chunked
                          chunk←4⊃wr
                      :ElseIf 0<⍴data,←4⊃wr
                      :AndIf 0=headerlen
                          (headerlen header)←DecodeHeader data
                          :If 0<headerlen
                              data←headerlen↓data
                              :If chunked←∨/'chunked'⍷header getHeader'Transfer-Encoding'
                                  chunk←data
                                  data←''
                              :Else
                                  datalen←⊃(toNum header getHeader'Content-Length'),¯1 ⍝ ¯1 if no content length not specified
                              :EndIf
                          :EndIf
                      :EndIf
                  :Else
                      ⎕←wr ⍝ Error?
                      ∘∘∘
                  :EndIf
                  :If chunked
                      buffer,←chunk
                      :While done<¯1≠⊃(len chunklength)←getchunklen buffer
                          :If (⍴buffer)≥4+len+chunklength
                              data,←chunklength↑(len+2)↓buffer
                              buffer←(chunklength+len+4)↓buffer
                              :If done←0=chunklength ⍝ chunked transfer can add headers at the end of the transmission
                                  header←⊂header⍪2⊃DecodeHeader buffer
                              :EndIf
                          :EndIf
                      :EndWhile
                  :Else
                      done←done∨'BlockLast'≡3⊃wr                        ⍝ Done if socket was closed
                      :If datalen>0
                          done←done∨datalen≤⍴data ⍝ ... or if declared amount of data rcvd
                      :Else
                          done←done∨(∨/''⍷data)∨(∨/''⍷data)
                      :EndIf
                  :EndIf
              :EndIf
          :Until done

          :Trap 0 ⍝ If any errors occur, abandon conversion
              :Select header getHeader'content-encoding' ⍝ was the response compressed?
              :Case 'deflate'
                  data←fromutf8 LDRC.flate.Inflate 120 156{(2×⍺≡2↑⍵)↓⍺,⍵}256|83 ⎕DR data ⍝ append 120 156 signature because web servers strip it out due to IE
              :Case 'gzip'
                  data←fromutf8 256|¯3(219⌶)83 ⎕DR data
              :Else
                  :If ∨/'charset=utf-8'⍷header getHeader'content-type'
                      data←'UTF-8'⎕UCS ⎕UCS data ⍝ Convert from UTF-8
                  :EndIf
              :EndSelect
          :EndTrap

          :If {(⍵[3]∊'12357')∧'30 '≡⍵[1 2 4]}4↑{⍵↓⍨⍵⍳' '}(⊂1 1)⊃header ⍝ redirected? (HTTP status codes 301, 302, 303, 305, 307)
              →GET⍴⍨0<⍴url←'location'{(⍵[;1]⍳⊂⍺)⊃⍵[;2],⊂''}header ⍝ use the "location" header field for the URL
          :EndIf

          r←(1⊃wr)header data ⍬

          :If secure ⋄ r[4]←⊂LDRC.GetProp cmd'PeerCert' ⋄ :EndIf
      :Else
          ⎕←'Connection failed ',,⍕r
          r←(⊂r)'' '' ''
      :EndIf

      {}LDRC.Close cmd
    ∇

    NL←⎕UCS 13 10
    fromutf8←{0::(⎕AV,'?')[⎕AVU⍳⍵] ⋄ 'UTF-8'⎕UCS ⍵} ⍝ Turn raw UTF-8 input into text
    utf8←{3=10|⎕DR ⍵: 256|⍵ ⋄ 'UTF-8' ⎕UCS ⍵}
    sint←{⎕io←0 ⋄ 83=⎕DR ⍵:⍵ ⋄ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 ¯128 ¯127 ¯126 ¯125 ¯124 ¯123 ¯122 ¯121 ¯120 ¯119 ¯118 ¯117 ¯116 ¯115 ¯114 ¯113 ¯112 ¯111 ¯110 ¯109 ¯108 ¯107 ¯106 ¯105 ¯104 ¯103 ¯102 ¯101 ¯100 ¯99 ¯98 ¯97 ¯96 ¯95 ¯94 ¯93 ¯92 ¯91 ¯90 ¯89 ¯88 ¯87 ¯86 ¯85 ¯84 ¯83 ¯82 ¯81 ¯80 ¯79 ¯78 ¯77 ¯76 ¯75 ¯74 ¯73 ¯72 ¯71 ¯70 ¯69 ¯68 ¯67 ¯66 ¯65 ¯64 ¯63 ¯62 ¯61 ¯60 ¯59 ¯58 ¯57 ¯56 ¯55 ¯54 ¯53 ¯52 ¯51 ¯50 ¯49 ¯48 ¯47 ¯46 ¯45 ¯44 ¯43 ¯42 ¯41 ¯40 ¯39 ¯38 ¯37 ¯36 ¯35 ¯34 ¯33 ¯32 ¯31 ¯30 ¯29 ¯28 ¯27 ¯26 ¯25 ¯24 ¯23 ¯22 ¯21 ¯20 ¯19 ¯18 ¯17 ¯16 ¯15 ¯14 ¯13 ¯12 ¯11 ¯10 ¯9 ¯8 ¯7 ¯6 ¯5 ¯4 ¯3 ¯2 ¯1[utf8 ⍵]}
    lc←(819⌶) ⍝ lower case conversion
    uc←1∘lc
    dlb←{(+/∧\' '=⍵)↓⍵} ⍝ delete leading blanks
    split←{(p↑⍵)((p←¯1+⍵⍳⍺)↓⍵)} ⍝ split ⍵ on first occurrence of ⍺
    h2d←{⎕IO←0 ⋄ 16⊥'0123456789abcdef'⍳lc ⍵} ⍝ hex to decimal
    getchunklen←{¯1=len←¯1+⊃(NL⍷⍵)/⍳⍴⍵:¯1 ¯1 ⋄ chunklen←h2d len↑⍵ ⋄ (⍴⍵)<len+chunklen+4:¯1 ¯1 ⋄ len chunklen}
    eis←{⍺←1 ⋄ ,(⊂⍣(⍺=|≡⍵))⍵} ⍝ enclose if simple
    toNum←{0∊⍴⍵:⍬ ⋄ 1⊃2⊃⎕VFI ⍵}
    getHeader←{(⍺[;2],⊂'')⊃⍨⍺[;1]⍳eis lc ⍵}
    addHeader←{0∊⍴⍺⍺ getHeader ⍺:⍺⍺⍪⍺ ⍵ ⋄ ⍺⍺}
    makeHeaders←{⎕ML←1 ⋄ 0∊⍴⍵:0 2⍴⊂'' ⋄ 2=⍴⍴⍵:⍵ ⋄ ↑2 eis ⍵}
    fmtHeaders←{⎕ML←1 ⋄ 0∊⍴⍵:'' ⋄ ∊{NL,⍨(1⊃⍵),': ',⍕2⊃⍵}¨↓⍵}
      b64Encode←{ ⍝ Base64 Encode
          raw←⊃,/11∘⎕DR¨⍵
          cols←6
          rows←⌈(⊃⍴raw)÷cols
          mat←rows cols⍴(rows×cols)↑raw
          'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'[⎕IO+2⊥⍉mat],(4|-rows)⍴'='}

    ∇ r←DecodeHeader buf;len;d;i
      ⍝ Decode HTTP Header
      r←0(0 2⍴⊂'')
      :If 0<i←⊃{((NL,NL)⍷⍵)/⍳⍴⍵}buf
          len←(¯1+⍴NL,NL)+i
          d←(⍴NL)↓¨{(NL⍷⍵)⊂⍵}NL,len↑buf
          d←↑{((p-1)↑⍵)((p←⍵⍳':')↓⍵)}¨d
          d[;1]←lc¨d[;1]
          d[;2]←dlb¨d[;2]
          r←len d
      :EndIf
    ∇
:EndClass

error: pathspec 'Utils/HTTPCommand.dyalog' did not match any file(s) known to git


Suppress display of names having ⎕nc of 0.


Add some more platform probes.

Add some more platform probes.


Remove FIX GNU APL tag; as of svn 778, there are no known remaining stale variables created by apl-packager.


Add names function and command.

Add names function and command.


Fix import_apl: always report function definition error line as-if in origin 1.


Added return value to run_probe.

Added return value to run_probe.


Release name and version.

Release name and version.


Change lookup_metadata_entry to insert placeholder for each unmatched key.


Parameterize version numbers. Add a function to parse version numbers.


Fix metadata extraction for packages having only one keyword/value pair.


Improve metadata API.

Improve metadata API.


Split over-long line.

Split over-long line.


Tweak shell checks.

Tweak shell checks.


Remove references to functions no longer present.


Exported functions use del as break character, not del-underbar.


File info returns access according to current uid/gid.

Added file API to return basic info for object on filesystem path.


Fix some edge conditions in the name function and command.


Visual tweaks in UI's dependencies listing.


Create scaled down FilesAndDirs class so the new version of MarkAPL wll work.

:Class FilesAndDirs
⍝ This class exists solely in support of MarkAPL from APLTeam
⍝ It provides comparable functionality to the FilesAndDirs class from https://github.com/aplteam/filesanddirs
⍝ for 2 methods - NormalizePath and Exists
    (⎕ML ⎕IO)←1 1
    ∇ r←{expand}NormalizePath f
      :Access public shared
      :If 0=⎕NC'expand' ⋄ expand←0 ⋄ :EndIf
      r←∊expand ⎕NPARTS f
    ∇
    ∇ r←Exists f
      :Access public shared
      r←⎕NEXISTS∊⎕NPARTS f
    ∇
:EndClass

error: pathspec 'Utils/FilesAndDirs.dyalog' did not match any file(s) known to git


Unwrap shell output.

Unwrap shell output.


Added basic QA for TubePlanner

Added basic QA for TubePlanner

 msg←Test dummy

 msg←''
 :if 0∊Find¨'inputs' 'city' 'from' 'to'
msg←'Expected page content not found! tube.dws might be missing...'
 :endif

error: pathspec 'MS3/QA/Examples/Applications/Tube_Planner.dyalog' did not match any file(s) known to git


Prevent larger value of pkg⍙wild_key_limit from breaking pkg⍙∆wild_keys.


Update to use newly supported initial characters.


A random change of 25672 to personal2.apl

error: pathspec 'personal2.apl' did not match any file(s) known to git


Recognize optional 'show' argument in ]pkg locate command.


added example sierpinski.apl

added example sierpinski.apl

#!/usr/bin/env apl
f←{(⍵,(⍴⍵)⍴0)⍪⍵,⍵}
⎕←f f f f 1 1 ⍴ 1

error: pathspec 'examples/sierpinski.apl' did not match any file(s) known to git


Wrong idiom.

Wrong idiom.


Fix another missed variable localization.


Add confirmation to rescan command.

Add confirmation to rescan command.


Tweak sys_assign test.

Tweak sys_assign test.


More commentary. Also, added several missed edits to rename append_paths to concatenate_paths.


Let the constant definition function handle numbers and control characters.


Added a sample program

Added a sample program

integer main()
{
	print(1);
	print(2);
	print(3);
	print(4);
	print(5);
	print(6);
	print(7);
	print(8);
	print(9);
	print(10);
	print(11);
	print(12);
	print(13);
	print(14);
	print(15);
	print(16);
	print(17);
	print(18);
	print(19);
	print(20);
	return 0;
}

error: pathspec 'samples/printnum.apl' did not match any file(s) known to git


It turns out that keeping the empty placeholder entry created by parse_metadata is necessary to facilitate later extraction by lookup_metadata_entry in the case that there's only one key/value pair in the entry.


A special "App" that collates all info we have on every control, and stores it in a matrix called #.ALLINFO

:class Info : MiPageSample
⍝ Control:: All Info
⍝ Description:: Collate all info on each control

      Section←{ ⍝ extract section ⍺:: from code ⍵
          regex←'^\s*⍝\s*',⍺,':(:.*?)$((\R^⍝(?!\s*\w+::).*?$)*)'
          opts←('Mode' 'M')('DotAll' 1)
          res←(regex ⎕S'\1\2'⍠opts)⍵
          (1↓⊃res)~'⍝'
      }

    Dread←{0::,⊂'[file read failed]' ⋄ #.UnicodeFile.ReadNestedText #.Boot.AppRoot,⍵,'.dyalog'} ⍝ Read dyalog file

    Comments←{⍵/⍨0,∧\1↓' ⍝'∊⍨⊃¨#.HTMLInput.dtlb¨⍵} ⍝ Get comments from source

    Names←{1↓¨⍵↑¨⍨¯1+⍵⍳¨':'} ⍝ Extract section names from set of several 'name:: description'

    ShortInfo←{(4+⍴⍵)↓(NAMESSHORT⍳⊂⍵)⊃INFOSHORT,⊂''}

    LongInfo←{(4+⍴⍵)↓(NAMESLONG⍳⊂⍵)⊃INFOLONG,⊂''}

    ∇ Compose
      :Access public
      style←''
      style,←'pre {'
      style,←'margin:0;'
      style,←'white-space: pre-wrap;'
      style,←'white-space: -moz-pre-wrap;'
      style,←'white-space: -pre-wrap;'
      style,←'white-space: -o-pre-wrap;'
      style,←'word-wrap: break-word;'
      style,←'}'
      Add _.Style style

      INFOSHORT←'⍝',¨Dread'Examples/Data/infoShort'
      INFOLONG←'⍝',¨Dread'Examples/Data/infoLong'
      NAMESSHORT←Names INFOSHORT
      NAMESLONG←Names INFOLONG

      #.ALLINFO←0 3⍴'Control' 'Source' 'Text'
      :For space :In _DC _SF _JQ _html

          :For control :In (space.⎕NL ¯9)~⊂'SALT_Data'
              name←(⍕space),'.',control
              #.ALLINFO⍪←name'infoShort'(ShortInfo control)
              #.ALLINFO⍪←'' 'infoLong'(LongInfo control)
              #.ALLINFO⍪←'' 'Comments'(Comments ⎕SRC⍎name)
          :EndFor
      :EndFor
      Add _.h2'The below table has been assigned to the matrix #.ALLINFO'
      Add _.Table(#.ALLINFO[;1 2],{'
','
',⍨4↓∊'
'∘,¨eis ⍵}¨#.ALLINFO[;3])
    ∇

:endclass

error: pathspec 'MS3/Examples/Apps/Info.dyalog' did not match any file(s) known to git


Fix ]pkg ident command.

Fix ]pkg ident command.


Fix import_apl: stringify expression before execute; suppress execute result.

Return from import_apl: count of definitions and count of expressions.


Implement load; this loads a package and its dependencies or signals an error.


Check for akt presence before attempting to edit.


Update comments. Add parse_external_version to parse external version number strings into our internal format.


Checkpoint: still working on local_dependencies; not yet functional.


Local variable.

Local variable.


Replace one of the GNU APL lambdas with a map operator.


Add the start of a really simple user interface.


Execute may not return a value.

Execute may not return a value.


Correct octal_to_bv32 to fill the two MSBs.


Support completion of ]pkg unload command.


Added Euclidean distance in APL

Added Euclidean distance in APL

⍝ Standard way to calculate the Euclidean distance
⍝ (As the sqrt of the sum of the square difference)
euclidean_distance ← {
   (+/(⍺ - ⍵) * 2) * ÷ 2
}

error: pathspec 'Euclidean_distance/APL/jcla1/euclidean_distance.apl' did not match any file(s) known to git


TimerSimple Sample

TimerSimple Sample

:Class TimerSimple : MiPageSample
⍝ Control:: _DC.Timer
⍝ Description:: Signal timed events to the server

    ∇ Compose
      :Access public
      Add _.h4'Timer Sample - will append timestamp every 5 seconds'
      Add _.Timer
      'result'Add _.div
      On'tick' 'cb'
    ∇

    ∇ r←cb
      :Access public
      r←'#result'Append'<br/>',⍕⎕TS
    ∇

:EndClass

error: pathspec 'MS3/Examples/DC/TimerSimple.dyalog' did not match any file(s) known to git


Restoring proper TogglePopup.dyalog

Restoring proper TogglePopup.dyalog

To resolve strange Git behavior, as per BPB.

:Class TogglePopup : MiPageSample ⍝ EAWC : MiPage : HtmlPage
    ∇ Render;ct
      :Access Public
      :If _Request.IsPost
          Add'You clicked me!'
      :Else
          ct←⎕NEW p
          ct.Add'Click ',(bn←⎕NEW ejToggleButton),' to toggle status.'
          bn.On'click' 'myCallback'('mybutt' 'ejModel')
          Add ct
          Wp←Add ejWaitingPopup'' 'Waiting...'
          'showOnInit'Wp.Option _false
      :EndIf
    ∇

    ∇ r←myCallback;active
      :Access public
      r←⍬
      active←_true≡_PageData.mybutt.model.showOnInit
      'showOnInit'Wp.Update _true _false[1+active] ⍝ Need Brian's post-render option setting mechanism
    ∇

:EndClass

error: pathspec 'MS3/Examples/TogglePopup.dyalog' did not match any file(s) known to git


Add zsh probe.

Add zsh probe.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/TieDyedDevil/apl-pkg.git/'


Fixed file_info to report open error.

Fixed file_info to report open error.


Correct comment.

Correct comment.


Changed get_load_paths to return only package directory paths.


Add uid and gid inquiries. We'll use these while examining file modes.


ScriptSimple

ScriptSimple

:Class ScriptSimple : MiPageSample
⍝ Control:: _DC.Script
⍝ Description::

    ∇ Compose
      :Access Public

      'p1'Add _.p ScriptFollows
      ⍝ The Dyalog Control Script enhances the base HTML script element in a number of ways.

      ⍝ The first argument, if nonempty, is treated as inline content for the script.
      ⍝ The second argument, specifies the type of input field.  HTML5 specifies a wide variety of
      ⍝ input type; however if nonempty, it treated a file name to link to.

      ⍝ Note: the first and second arguments are mutually exclusive.

      Add _.Script ScriptFollows
      ⍝ function bgChange(){$("#p1").css("background-color","orange")}

      'onclick="bgChange()"'Add _.Button'Click Me!'
    ∇

    ∇ r←myCallback;content
      :Access public
      r←('#out',3↓_what)Replace'You entered ',_value
    ∇

:EndClass

error: pathspec 'MS3/Examples/DC/ScriptSimple.dyalog' did not match any file(s) known to git


Clean up package dependency generation. Fix package loading report.


Add sample .dyalog file for file type APL

Taken from
https://github.com/Gianfrancoalongi/APLUnit/blob/master/UT.dyalog

:NameSpace UT

    sac ← 0
    expect_orig ← expect ← ⎕NS⍬
    exception ← ⍬
    nexpect_orig ← nexpect ← ⎕NS⍬

    ∇ {Z}←{Conf}run Argument;PRE_test;POST_test;TEST_step;COVER_step;FromSpace

      load_display_if_not_already_loaded
      load_salt_scripts_into_current_namespace_if_configured

      FromSpace←1⊃⎕RSI

      PRE_test←{}
      POST_test←{}
      COVER_step←{}
      :If 0≠⎕NC'Conf'
          :If Conf has'cover_target'
              PRE_test←{{}⎕PROFILE'start'}
              POST_test←{{}⎕PROFILE'stop'}
          :EndIf
      :EndIf

      :If is_function Argument
          TEST_step←single_function_test_function
          COVER_file←Argument,'_coverage.html'

      :ElseIf is_list_of_functions Argument
          TEST_step←list_of_functions_test_function
          COVER_file←'list_coverage.html'

      :ElseIf is_file Argument
          TEST_step←file_test_function
          COVER_file←(get_file_name Argument),'_coverage.html'

      :ElseIf is_dir Argument
          test_files←test_files_in_dir Argument
          TEST_step←test_dir_function
          Argument←test_files
      :EndIf

      :If 0≠⎕NC'Conf'
          :If Conf has'cover_target'
              COVER_step←{Conf,←⊂('cover_file'COVER_file)
                  generate_coverage_page Conf}
          :EndIf
      :EndIf

      PRE_test ⍬
      Z←FromSpace TEST_step Argument
      POST_test ⍬
      COVER_step ⍬
    ∇

    ∇ load_display_if_not_already_loaded
      :If 0=⎕NC'#.DISPLAY'
          'DISPLAY'#.⎕CY'display'
      :EndIf
    ∇

    ∇ load_salt_scripts_into_current_namespace_if_configured
      :If 0≠⎕NC'#.UT.appdir'
          :If ⍬≢#.UT.appdir
              ⎕SE.SALT.Load #.UT.appdir,'src/*.dyalog -target=#'
              ⎕SE.SALT.Load #.UT.appdir,'test/*.dyalog -target=#'
          :EndIf
      :EndIf
    ∇

    ∇ Z←FromSpace single_function_test_function TestName
      Z←run_ut FromSpace TestName
    ∇

    ∇ Z←FromSpace list_of_functions_test_function ListOfNames;t
      t←⎕TS
      Z←run_ut¨{FromSpace ⍵}¨ListOfNames
      t←⎕TS-t
      ('Test execution report')print_passed_crashed_failed Z t
    ∇

    ∇ Z←FromSpace file_test_function FilePath;FileNS;Functions;TestFunctions;t
      FileNS←⎕SE.SALT.Load FilePath,' -target=#'
      Functions←↓FileNS.⎕NL 3
      TestFunctions←(is_test¨Functions)/Functions
      :If (0/⍬,⊂0/'')≡TestFunctions
          ⎕←'No test functions found'
          Z←⍬
      :Else
          t←⎕TS
          Z←run_ut¨{FileNS ⍵}¨TestFunctions
          t←⎕TS-t
          (FilePath,' tests')print_passed_crashed_failed Z t
      :EndIf
    ∇

    ∇ Z←FromSpace test_dir_function Test_files
      :If Test_files≡⍬/⍬,⊂''
          ⎕←'No test files found'
          Z←⍬
      :Else
          Z←#.UT.run¨Test_files
      :EndIf
    ∇

    ∇ Z←get_file_name Argument;separator
      separator←⊃⌽(Argument∊'/\')/⍳⍴Argument
      Z←¯7↓separator↓Argument
    ∇

    ∇ generate_coverage_page Conf;ProfileData;CoverResults;HTML
      ProfileData←⎕PROFILE'data'
      ToCover←retrieve_coverables¨(⊃'cover_target'in Conf)
      :If (⍴ToCover)≡(⍴⊂1)
          ToCover←⊃ToCover
      :EndIf
      Representations←get_representation¨ToCover
      CoverResults←ProfileData∘generate_cover_result¨↓ToCover,[1.5]Representations
      HTML←generate_html CoverResults
      Conf write_html_to_page HTML
      ⎕PROFILE'clear'
    ∇

    ∇ Z←retrieve_coverables Something;nc;functions
      nc←⎕NC Something
      :If nc=3
          Z←Something
      :ElseIf nc=9
          functions←strip¨↓⍎Something,'.⎕NL 3'
          Z←{(Something,'.',⍵)}¨functions
      :EndIf
    ∇

    ∇ Z←strip input
      Z←(input≠' ')/input
    ∇

    ∇ Z←get_representation Function;nc;rep
      nc←⎕NC⊂Function
      :If nc=3.1
          rep←↓⎕CR Function
          rep[1]←⊂'∇',⊃rep[1]
          rep,←⊂'∇'
          rep←↑rep
      :Else
          rep←⎕CR Function
      :EndIf
      Z←rep
    ∇

    ∇ Z←ProfileData generate_cover_result(name representation);Indices;lines;functionlines;covered_lines
      Indices←({name≡⍵}¨ProfileData[;1])/⍳⍴ProfileData[;1]
      lines←ProfileData[Indices;2]
      nc←⎕NC⊂name
      :If 3.1=nc
          functionlines←¯2+⍴↓representation
      :Else
          functionlines←⊃⍴↓representation
      :EndIf
      covered_lines←(⍬∘≢¨lines)/lines
      Z←(nc lines functionlines covered_lines representation)
    ∇

    ∇ Z←generate_html CoverResults;Covered;Total;Percentage;CoverageText;ColorizedCode;Timestamp;Page
      Covered←⊃⊃+/{⍴4⊃⍵}¨CoverResults
      Total←⊃⊃+/{3⊃⍵}¨CoverResults
      Percentage←100×Covered÷Total
      CoverageText←'Coverage: ',Percentage,'% (',Covered,'/',Total,')'
      ColorizedCode←⊃,/{colorize_code_by_coverage ⍵}¨CoverResults
      Timestamp←generate_timestamp_text
      Page←⍬
      Page,←⊂⍬,''
      Page,←⊂⍬,'<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>'
      Page,←⊂⍬,''
      Page,←⊂⍬,CoverageText
      Page,←⊂⍬,'
'
      Page,←ColorizedCode
      Page,←⊂⍬,'
'
      Page,←Timestamp
      Page,←⊂⍬,''
      Z←Page
    ∇

    ∇ Z←colorize_code_by_coverage CoverResult;Colors;Ends;Code
      :If 3.1=⊃CoverResult
          Colors←(2+3⊃CoverResult)⍴⊂'<uncov>'
          Colors[1]←⊂''
          Colors[⍴Colors]←⊂''
          Ends←(2+3⊃CoverResult)⍴⊂'</uncov>'
          Ends[1]←⊂''
          Ends[⍴Ends]←⊂''
      :Else
          Colors←(3⊃CoverResult)⍴⊂'<uncov>'
          Ends←(3⊃CoverResult)⍴⊂'</uncov>'
      :EndIf
      Colors[1+4⊃CoverResult]←⊂'<cov>'
      Ends[1+4⊃CoverResult]←⊂'</cov>'
      Code←↓5⊃CoverResult
      Z←Colors,[1.5]Code
      Z←{⍺,(⎕UCS 13),⍵}/Z,Ends
    ∇

    ∇ Z←generate_timestamp_text;TS;YYMMDD;HHMMSS
      TS←⎕TS
      YYMMDD←⊃{⍺,'-',⍵}/3↑TS
      HHMMSS←⊃{⍺,':',⍵}/3↑3↓TS
      Z←'Page generated: ',YYMMDD,'|',HHMMSS
    ∇

    ∇ Conf write_html_to_page Page;tie;filename
      filename←(⊃'cover_out'in Conf),(⊃'cover_file'in Conf)
      :Trap 22
          tie←filename ⎕NTIE 0
          filename ⎕NERASE tie
          filename ⎕NCREATE tie
      :Else
          tie←filename ⎕NCREATE 0
      :EndTrap
      Simple_array←⍕⊃,/Page
      (⎕UCS'UTF-8'⎕UCS Simple_array)⎕NAPPEND tie
    ∇

    ∇ Z←is_function Argument
      Z←'_TEST'≡¯5↑Argument
    ∇

    ∇ Z←is_list_of_functions Argument
      Z←2=≡Argument
    ∇

    ∇ Z←is_file Argument
      Z←'.dyalog'≡¯7↑Argument
    ∇

    ∇ Z←is_dir Argument;attr
      :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
          Z←'yes'≡⊃⎕CMD'test -d ',Argument,' && echo yes || echo no'
      :Else
          'gfa'⎕NA'I kernel32|GetFileAttributes* <0t'
          :If Z←¯1≠attr←gfa⊂Argument ⍝ If file exists
              Z←⊃2 16⊤attr           ⍝ Return bit 4
          :EndIf
      :EndIf
    ∇

    ∇ Z←test_files_in_dir Argument
      :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
          Z←⎕SH'find ',Argument,' -name \*_tests.dyalog'
      :Else
          #.⎕CY'files'
          Z←#.Files.Dir Argument,'\*_tests.dyalog'
          Z←(Argument,'\')∘,¨Z
      :EndIf
    ∇

    ∇ Z←run_ut ut_data;returned;crashed;pass;crash;fail;message
      (returned crashed time)←execute_function ut_data
      (pass crash fail)←determine_pass_crash_or_fail returned crashed
      message←determine_message pass fail crashed(2⊃ut_data)returned time
      print_message_to_screen message
      Z←(pass crash fail)
    ∇

    ∇ Z←execute_function ut_data;function;t
      reset_UT_globals
      function←(⍕(⊃ut_data[1])),'.',⊃ut_data[2]
      :Trap sac
          :If 3.2≡⎕NC⊂function
              t←⎕TS
              Z←(⍎function,' ⍬')0
              t←⎕TS-t
          :Else
              t←⎕TS
              Z←(⍎function)0
              t←⎕TS-t
          :EndIf

      :Else
          Z←(↑⎕DM)1
          :If exception≢⍬
              expect←exception
              Z[2]←0
              t←⎕TS-t
          :EndIf
      :EndTrap
      Z,←⊂t
    ∇

    ∇ reset_UT_globals
      expect_orig ← expect← ⎕NS⍬
      exception←⍬
      nexpect_orig ← nexpect← ⎕NS⍬
    ∇

    ∇ Z←is_test FunctionName;wsIndex
      wsIndex←FunctionName⍳' '
      FunctionName←(wsIndex-1)↑FunctionName
      Z←'_TEST'≡¯5↑FunctionName
    ∇

    ∇ Heading print_passed_crashed_failed(ArrayRes time)
      ⎕←'-----------------------------------------'
      ⎕←Heading
      ⎕←'    ⍋  Passed: ',+/{1⊃⍵}¨ArrayRes
      ⎕←'    ⍟ Crashed: ',+/{2⊃⍵}¨ArrayRes
      ⎕←'    ⍒  Failed: ',+/{3⊃⍵}¨ArrayRes
      ⎕←'    ○ Runtime: ',time[5],'m',time[6],'s',time[7],'ms'
    ∇

    determine_pass_crash_or_fail←{
      r c←⍵ ⋄ 0≠c:0 1 0 ⋄ z←(0 0 1)(1 0 0)
      expect_orig≢expect:(⎕IO+expect≡r)⊃z ⋄ (⎕IO+nexpect≢r)⊃z
    }

    ∇ Z←determine_message(pass fail crashed name returned time)
      :If crashed
          Z←'CRASHED: 'failure_message name returned
      :ElseIf pass
          Z←'Passed ',time[5],'m',time[6],'s',time[7],'ms'
      :Else
          Z←'FAILED: 'failure_message name returned
      :EndIf
    ∇

    ∇ print_message_to_screen message
      ⎕←message
    ∇

    ∇ Z←term_to_text Term;Text;Rows
      Text←#.DISPLAY Term
      Rows←1⊃⍴Text
      Z←(Rows 4⍴''),Text
    ∇

    ∇ Z←Cause failure_message(name returned);hdr;exp;expterm;got;gotterm
      hdr←Cause,name
      exp←'Expected'
      expterm←term_to_text #.UT.expect
      got←'Got'
      gotterm←term_to_text returned
      Z←align_and_join_message_parts hdr exp expterm got gotterm
    ∇

    ∇ Z←align_and_join_message_parts Parts;hdr;exp;expterm;got;gotterm;R1;C1;R2;C2;W
      (hdr exp expterm got gotterm)←Parts
      (R1 C1)←⍴expterm
      (R2 C2)←⍴gotterm
      W←⊃⊃⌈/C1 C2(⍴hdr)(⍴exp)(⍴got)
      Z←(W↑hdr),[0.5](W↑exp)
      Z←Z⍪(R1 W↑expterm)
      Z←Z⍪(W↑got)
      Z←Z⍪(R2 W↑gotterm)
    ∇

    ∇ Z←confparam in config
      Z←1↓⊃({confparam≡⊃⍵}¨config)/config
    ∇

    ∇ Z←config has confparam
      Z←∨/{confparam≡⊃⍵}¨config
    ∇

:EndNameSpace

error: pathspec 'samples/APL/UT.dyalog' did not match any file(s) known to git


Added header to `]pkg names' listing.

Added header to `]pkg names' listing.


Now import_apl allows file not terminated by newline.


Add sh_in_pkg_wd.

Add sh_in_pkg_wd.


Fix edge cases w.r.t. empty and one-element key/value lists.


Fix (commented-out) GNU APL UTF-to-UCS converter. Update comments.


added example: Langton's ant

added example: Langton's ant

#!/usr/bin/env apl

# Langton's ant

# It lives in an infinite boolean matrix and has a position and a direction
# (north, south, east, or west).  At every step the ant:
#   * turns left or right depending on whether the occupied cell is true or false
#   * inverts the value of the occupied cell
#   * moves one cell forward

# In this program, we use a finite matrix with torus topology, and we keep the
# ant in the centre, pointing upwards (north), rotating the whole matrix
# instead.

m ← 5
n ← 1+2×m

A0 ← (−m) ⊖ (−m) ⌽ n n ↑ 1 1 ⍴ 1
next ← {0≠A0−¯1⊖⌽[⍵[m;m]]⍉⍵}

next10 ← {next next next next next next next next next next ⍵}
next100 ← {next10 next10 next10 next10 next10 next10 next10 next10 next10 next10 ⍵}
⎕ ← ' X'[next100 next100 next100 A0]

error: pathspec 'examples/langton.apl' did not match any file(s) known to git


QA for ejDigitalGaugeAdvanced

QA for ejDigitalGaugeAdvanced

 msg←Test dummy;canvases
 canvases←⌷'TagNames'Find'canvas'
 :If 0=⍴msg←'canvases not found'/⍨5≢≢canvases
 :AndIf 0=⍴msg←'canvas with wrong role'/⍨∨/'presentation'∘≢¨canvases.GetAttribute 5/⊂⊂'role'
 :EndIf

error: pathspec 'MS3/QA/Examples/SF/ejDigitalGaugeAdvanced.dyalog' did not match any file(s) known to git


Checkpoint: Still working on dependency-list collection.


Accept SVN version identifier flag as separator when parsing.


Better message from unloaded package manager.


First APL example

First APL example

error: pathspec 'apl/primes_to_50.apl' did not match any file(s) known to git


Correct top-level execute in import_apl.


Abstract out the package loading check.

Abstract out the package loading check.


Add a probe for GNU APL version.

Add a probe for GNU APL version.


Add UnicodeFile

Add UnicodeFile

:Class UnicodeFile
⍝ clone of ⎕SE.UnicodeFile
⍝ Version 12 compatible version

    ⎕ML ⎕IO←0 1
    ⎕avu[4]←13      ⍝ make sure CR is here

⍝==============================================================================⍝
⍝     Declaration of Variables                                                 ⍝
⍝     (commented ones are defined later in the file )                          ⍝
⍝==============================================================================⍝

  ⍝ Public Variables :
    ⍝ :Property Public NewLine          ⍝ Vector of Unicode Scalar representing the New Line sequence (empty if auto-detected)
    ⍝ :Property Public Raw              ⍝ Unicode scalars of the file
    ⍝ :Property Public Text             ⍝ Encapsulation of Raw in APL text through the translate table
    ⍝ :Property Public NestedText       ⍝ Encapsulation of NestedText
    ⍝ :Property Public Encoding         ⍝ A string to get or set the current unicode encoding
    ⍝ :Property Public Errors           ⍝ Friendly access to error state (write anything = reset)
    :Field Public Malformed←⍬           ⍝ indices of malformed characters in Raw
    :Field Public Illegal←⍬             ⍝ indices of illegal characters in Raw
    :Field Public Untranslatable←⍬      ⍝ indices of untranslatable characters in Text
    :Field Public Shared UnicodeEN←500  ⍝ ⎕EN of the unicode errors when using the public shared Read/Write functions

  ⍝ Private counterparts of public variables :
    :Field Private _Raw←⍬               ⍝ Data storage for property Raw
    :Field Private _Replacement←'?'     ⍝ Data storage for property Replacement

  ⍝ Private Fields for Errors :
    ⍝ :Field Private _ErrorMessages     ⍝ List of error messages      - See the end
    :Field Private _Errors←⍬            ⍝ Data storage for property Errors

  ⍝ Private Fields for New Lines :
    :Field Private _NewLine←⍬           ⍝ New Line sequence currently in use (will be auto-detected if empty)
    :Field Private _NewLineUser←⍬       ⍝ User-defined new line sequence
    :Field Private _NewLines←,¨(13 10)10 13 133    ⍝ Accepted new line sequences for autodetection

  ⍝ Private Fields for Encoding - See the end
    ⍝ :Field Private _TableBOM
    ⍝ :Field Private _Encoding
    ⍝ :Field Private _EncodingDefault
    ⍝ :Field Private _EncodingUser
    ⍝ :Property Private _EncodingName
    ⍝ :Property Private _EncodingList
    ⍝ :Property Private _Width
    ⍝ :Property Private _Endian
    ⍝ :Property Private _BOM
    ⍝ :Property Private _BOMlist

  ⍝ Misc :
    :Field Private _FileName←''         ⍝ file path
    :Field Private V11←'11.0.'≡5↑2⊃'.' ⎕wg 'APLVersion'

⍝==============================================================================⍝
⍝     Public Methods of Shared Use                                             ⍝
⍝==============================================================================⍝

    ∇ r←ReadRaw arg;u
      :Access Public Shared
    ⍝ ReadRaw 'filename' {'format'}
      :Trap 0                 ⍝ forward errors to user
          r←1 Read arg
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN
      :EndTrap
    ∇

    ∇ r←ReadText arg;u;err
      :Access Public Shared
    ⍝ ReadText 'filename' {'format'}
      :Trap 0                 ⍝ forward errors to user
          r←2 Read arg
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN
      :EndTrap
    ∇

    ∇ r←ReadNestedText arg;u
      :Access Public Shared
    ⍝ ReadNestedText 'filename' {'format'}
      :Trap 0                 ⍝ forward errors to user
          r←3 Read arg
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN
      :EndTrap
    ∇

    ∇ r←type Read arg;u;err
      :Access Private Shared
    ⍝ (type∊1 2 3) Read 'filename' {'format'}
      u←⎕NEW ⎕THIS arg
      :Select type
      :Case 1
          r←u.Raw
      :Case 2
          r←u.Text
      :Case 3
          r←u.NestedText
      :Else
          r←⍬
      :EndSelect
      :If 1=2|⊃u.Errors             ⍝ special case when file does not exist
          'File not found'⎕SIGNAL 22
      :ElseIf 0 4∧.≠1⊃u.Errors      ⍝ signal any error excepted when only unmarked file (correctly read)
          ('UNICODE ERRORS: ',2⊃u.Errors)⎕SIGNAL UnicodeEN
      :EndIf
    ∇

    ∇ Write arg;data;u;msg
      :Access Public Shared
    ⍝ Write 'filename' data {'format'}
      msg←'Usage = Write ''filename'' (data) {''encoding''} {(new line sequence)}'
      :If ~(⊃⍴arg←,arg)∊2 3 4
          ('LENGTH ERROR: ',msg)⎕SIGNAL 5           ⍝ length error
      :EndIf
      data←2⊃arg ⋄ arg←(1↑arg),(2↓arg)  ⍝ separate data from other arguments

      :Trap 0
          :Trap 11                      ⍝ change the usage message if it pops up
              u←⎕NEW ⎕THIS arg
              {}u.Text                  ⍝ trigger auto-detection of NewLine sequence
          :Else
              ('DOMAIN ERROR: ',msg)⎕SIGNAL 11
          :EndTrap
          u.Errors←0                ⍝ reset errors (we don't care whether reading was OK or not)
          :If istext data           ⍝ Text
              u.Text←data
          :ElseIf 1 3∨.=10|⎕DR data ⍝ Integers (can be boolean)
              u.Raw←data
          :ElseIf ∧/istext¨data     ⍝ Nested Text
              u.NestedText←data
          :Else
              msg←'DOMAIN ERROR: Data (the second element) must be either '
              msg,←'Raw (integer vector), Text (character vector), or Nested Text (vector of character vectors)'
              msg ⎕SIGNAL 11        ⍝ domain error
          :EndIf
          :If 0≠1⊃u.Errors          ⍝ check for unicode errors
              ('UNICODE ERRORS: ',2⊃u.Errors)⎕SIGNAL UnicodeEN
          :EndIf
          u.Export                  ⍝ write if no error
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN
      :EndTrap
    ∇

⍝==============================================================================⍝
⍝     Public Methods of Instance Use                                           ⍝
⍝==============================================================================⍝

    ∇ Make arg;filename;format;msg;i;t
      :Access Public
      :Implements Constructor
      msg←'Arguments should be : ''filename'' {''encoding''} {(new line sequence)}'
      ('DOMAIN ERROR: ',msg)⎕SIGNAL(~istext⊃arg)/11     ⍝ check filename is text
      Encoding NewLine←''⍬         ⍝ initialize to default
      :Trap 0
          :Select |≡arg←,arg
          :Case 1
              _FileName←arg
          :Case 2
              :Select ⊃⍴arg
              :Case 1
                  _FileName←(⊃arg)
              :CaseList 2 3
                  _FileName←⊃arg
                  i←⍋t←2|⎕DR¨arg←1↓arg    ⍝ types of arguments
                  :Select t[i]
                  :Case ,0          ⍝ text : enconding
                      Encoding←⊃arg
                  :Case ,1          ⍝ numbers : new line sequence
                      NewLine←⊃arg
                  :Case 0 1         ⍝ both
                      Encoding NewLine←arg[i]
                  :Else
                      ('DOMAIN ERROR: ',msg)⎕SIGNAL 11
                  :EndSelect
              :Else
                  ('LENGTH ERROR: ',msg)⎕SIGNAL 5
              :EndSelect
          :Else
              ('DOMAIN ERROR: ',msg)⎕SIGNAL 11
          :EndSelect
          Import                ⍝ try to import the unicode file
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN     ⍝ file i/o errors
      :EndTrap
    ∇

    ∇ Import;bytestream
      :Access Public
    ⍝ refresh the data from the file
      :Trap 0
          ⍝ first, try to read bytestream from the file
          bytestream←readfile _FileName
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN     ⍝ file i/o error
      :EndTrap
      :If ~ERR_EXIST∊_Errors
          ⍝ then process the bytestream into unicode scalars
          Raw←decode gather removeBOM getencoding bytestream
      :Else
          Raw←⍬
      :EndIf
    ∇

    ∇ Export;bytestream
      :Access Public
    ⍝ refresh the file with the data
    ⍝ be sure to have check for errors before doing this !
      bytestream←addBOM split encode Raw
      :Trap 0
          _FileName writefile bytestream
      :Else
          (⊃⎕DM)⎕SIGNAL ⎕EN     ⍝ file i/o error
      :EndTrap
    ∇

⍝==============================================================================⍝
⍝     Public Properties                                                        ⍝
⍝==============================================================================⍝

    :Property Raw           ⍝ legalized Vector of Unicode scalars
    :Access Public
        ∇ r←Get
          r←_Raw
        ∇
        ∇ set args;bytestream;msg;data
          data←,args.NewValue
          msg←'DOMAIN ERROR: Raw data must be an integer vector'
          msg ⎕SIGNAL(1 3∧.≠10|⎕DR data)/11

          :If 'Import'≢2⊃2↑⎕SI     ⍝ if writing Raw directly, clear Import errors
              _Errors~←ERR_BADBOM∪ERR_NOBOM∪ERR_MALFORMED
          :EndIf
          :If 'set_Text'≢2⊃2↑⎕SI    ⍝ if writing Raw directly, clear text errors
              _Errors~←ERR_NL∪ERR_UNTRANS
          :EndIf
          _Raw←legalize data
        ∇
    :EndProperty

    :Property Text          ⍝ APL Text Vector
    :Access Public
        ∇ r←Get
          r←unicode2apl 1 newlines Raw
        ∇
        ∇ Set args;msg;data
          data←,args.NewValue
          msg←'DOMAIN ERROR: Text must be an character vector'
          msg ⎕SIGNAL(istext data)↓11
          Raw←0 newlines apl2unicode data
        ∇
    :EndProperty

    :Property NestedText    ⍝ APL Nested Text Vector (no newline characters)
    :Access Public
        ∇ r←get;NL;txt
          txt←Text                          ⍝ read text and detect NewLine
          :If ~V11
          :OrIf _NewLine∧.∊⊂_Unicode        ⍝ mappable new line
              NL←,unicode2apl _NewLine
          :Else
              NL←,⎕AV[4]                    ⍝ un-mappable new line
          :EndIf
          r←(⍴NL)↓¨(NL⍷txt)⊂txt←NL,txt
        ∇
        ∇ Set args;data;msg;NL
          data←,args.NewValue
          msg←'DOMAIN ERROR: NestedText must be an vector of character vectors'
          msg ⎕SIGNAL(∧/istext¨data)↓11
          :If 0=⍴,_NewLine
              _NewLine←,⊃_NewLines          ⍝ default new line
          :EndIf
          :If ~V11
          :OrIf _NewLine∧.∊⊂_Unicode        ⍝ mappable new line
              NL←,unicode2apl _NewLine
          :Else
              NL←,⎕AV[4]                    ⍝ un-mappable new line
          :EndIf
          Text←(-⍴NL)↓⊃data,.,⊂NL
        ∇
    :EndProperty

    :Property Encoding      ⍝ string to get or set the current encoding of the file
    :Access Public
        ∇ r←Get
          r←¯1↓⊃_EncodingName,.,'-'
        ∇
        ∇ Set args;name;names;charset;bool;msg
          name←,args.NewValue
          msg←'DOMAIN ERROR: Encoding must be a character vector'
          msg ⎕SIGNAL(istext name)↓11               ⍝ Must be char
          :If 0=⍴name
              _EncodingUser←⍬
              _Encoding←_EncodingDefault
          :Else
              charset←'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 abcdefghijklmnopqrstuvwxyz0123456789'
              name←' ',charset[1+37|¯1+charset⍳name]    ⍝ go uppercase and replace anything not in charset by spaces
              name←1↓¨(' '=name)⊂name                   ⍝ partition on spaces
              name←(0≠(⊃∘⍴)¨name)/name                  ⍝ remove empty partitions
              bool←(⊂name){(,¨⍺)≡(,¨⍵)}¨_EncodingList   ⍝ names that match
              :If ∨/bool
                  _Encoding←_EncodingUser←bool⍳1        ⍝ first name that match
              :Else
                  msg←'DOMAIN ERROR: Accepted Formats are : ',⊃,/{'''',(¯1↓⊃⍵,.,'-'),''' '}¨_EncodingList
                  msg ⎕SIGNAL 11                            ⍝ no match
              :EndIf
          :EndIf
        ∇
    :EndProperty

    :Property Errors         ⍝ friendly access to error state
    :Access Public
        ∇ Set args           ⍝ write anything = reset
          _Errors←ERR_OK
        ∇
        ∇ r←Get;err;n;msg    ⍝ read as a 2-el vector : (scalar error number) (string catenation of error messages)
          err←∪_Errors
          :If 0=+/|err       ⍝ no error (empty or containing zeros)
              r←0 ''
          :Else
              err←err~0
              err←err[⍋err]
              n←2⊥(⌽⍳⍴_ErrorMessages)∊err               ⍝ base-2 encoding of error numbers
              msg←'[',¯2↓⊃_ErrorMessages[err],.,⊂'] ['  ⍝ catenation of the messages
              r←n msg
          :EndIf
        ∇
    :EndProperty

    :Property NewLine
    :Access Public
        ∇ Set args;data
          data←,args.NewValue
          :If 1 3∧.≠10|⎕DR data
              'DOMAIN ERROR: NewLine sequence must be a vector of Unicode scalars'⎕SIGNAL 11
          :EndIf
          _NewLine←_NewLineUser←data
        ∇
        ∇ r←Get
          r←_NewLine
        ∇
    :EndProperty

⍝==============================================================================⍝
⍝     Private Methods                                                          ⍝
⍝==============================================================================⍝

⍝ Private Dataflow of the UnicodeFile Class :
⍝ ┌───────────────────────┬──────────────┬───────────┬──────────────┬───────────────┐
⍝ │ Layer (type of data)  │ Importing    │           │ Exporting    │ Errors        │
⍝ │                       │ process      │           │ process      │ Raised        │
⍝ ├───────────────────────┼──────────────┼───────────┼──────────────┼───────────────┤
⍝ │ File                  │              │           │              │               │
⍝ │                       │ readfile     │           │ writefile    │ ERR_EXIST     │\
⍝ │ Marked Bytestream     │    ↓         │           │    ↑         │               │ |
⍝ │                       │ getencoding  │           │    ↑         │ ERR_NOBOM,ERR_BADBOM
⍝ │                       │    ↓         → _Encoding │    ↑         │               │ |
⍝ │                       │ removeBOM    │           │ addBOM       │               │ | Import/Export
⍝ │ Bytestream            │    ↓         │           │    ↑         │               │ |
⍝ │                       │ gather       │           │ split        │ ERR_ODD       │ |
⍝ │ Coded Wide Characters │    ↓         │           │    ↑         │               │ |
⍝ │                       │ decode       │           │ encode       │ ERR_MALFORMED │/
⍝ │                    /  │    ↓         │ _Raw      ←    ↑         │               │\
⍝ │                   |   │ legalize     │           │ legalize     │ ERR_ILLEGAL   │ | Raw Property
⍝ │ Unicode Scalars   |   │    ↓         → _Raw      │    ↑         │               │/
⍝ │                   |   │ newlines     │           │ newlines     │ ERR_NL        │\
⍝ │                    \  │    ↓         → _NewLine  │    ↑         │               │ |
⍝ │                       │ unicode2apl  │           │ apl2unicode  │ ERR_UNTRANS   │ | Text Property
⍝ │ APL Text              │              → _Text     →              │               │/
⍝ └───────────────────────┴──────────────┴───────────┴──────────────┴───────────────┘
⍝ NB : All functions must accept and then return empty vectors

  ⍝ Importing Nested Text when no newline is set put ⎕AV[4] translated to 13, should be the default
  ⍝ When import text and no newline set, ⎕av[4] alone should be mapped to the default
  ⍝   :AndIf ~(~toquadav)∧(old≡,4⊃_Unicode)  ⍝ when from ⎕AV, ⎕AV[4] is accepted as homogeneous to the chosen sequence => no error (unless _NewLine∊_NewLines)

  ⍝ specific functions for autodetecting newlines,
  ⍝ getting its unicode representation and APL representation

    ∇ r←istext data
    ⍝ Is data text (V12 compatible)
      r←(10|⎕DR data)∊0 2
    ∇

    ∇ bytestream←readfile filename;fic
    ⍝ Read file as positive integers ∊ [0;255]
    ⍝ Will signal on any file i/o error excepted FILE NAME ERROR (22)
      fic←0
      bytestream←⍬
      :Trap 22      ⍝ FILE NAME ERROR = file does not exist
          fic←filename ⎕NTIE 0
          bytestream←256|⎕NREAD fic 83(⎕NSIZE fic)0
          ⎕NUNTIE fic
          _Errors~←ERR_EXIST
      :Else
          _Errors∪←ERR_EXIST
      :EndTrap
    ∇
    ∇ name writefile bytestream;fic
    ⍝ Write byte stream to file, creating it or overwriting it
    ⍝ Will signal any file i/o error
      fic←0
      :Trap 22       ⍝ try to create it
          fic←name ⎕NCREATE 0
      :Else          ⍝ else open it
          fic←name ⎕NTIE 0
      :EndTrap
      0 ⎕NRESIZE fic
      :Trap 11 ⍝ there used to be a bug where NAPPEND 83 would accept >127
          bytestream ⎕NAPPEND fic 83
      :Else
          (bytestream-256×bytestream>127)⎕NAPPEND fic 83
      :EndTrap
      ⎕NUNTIE fic
      _Errors~←ERR_EXIST
    ∇

    ∇ bytestream←getencoding bytestream;header;match
    ⍝ Reads the BOM and deduce the encoding if the user hasn't forced the encoding
      _Errors~←ERR_NOBOM∪ERR_BADBOM      ⍝ clear errors before updating them
      header←(⊃⌈/⍴¨_BOMlist)↑bytestream  ⍝ beginning of the bytestream
      match←⊃¨_BOMlist⍷¨⊂header          ⍝ BOMs that match
      match←match⍳1                      ⍝ first row of table that matches
      :If 0=⍴,_EncodingUser              ⍝ auto-detect
          :If match>⍴_BOMlist            ⍝ nothing detected : default
              _Errors∪←ERR_NOBOM
              _Encoding←_EncodingDefault
          :Else                          ⍝ BOM detected
              _Encoding←match
          :EndIf
      :ElseIf (match≤⍴_BOMlist)∧(match≠_Encoding)  ⍝ user specified one and we detected another
          _Errors∪←ERR_BADBOM
      :EndIf
    ∇
    ∇ bytestream←removeBOM bytestream
    ⍝ Removes the BOM from the bytestream
      :If ⊃_BOM⍷bytestream
          bytestream←(⍴_BOM)↓bytestream
      :EndIf
    ∇
    ∇ bytestream←addBOM bytestream
    ⍝ Adds the BOM to the bytestream
      bytestream←_BOM,bytestream
      _Errors~←ERR_NOBOM∪ERR_BADBOM
    ∇

    ∇ wchars←gather bytestream;width;length;encoding
    ⍝ Depending on the width of the encoding, gather bytes into wide characters
      :If _Width>1
          length←(⍴bytestream)÷_Width
          :If length≠⌊length
              length←⌊length                       ⍝ ignore the last word if it is not complete
              _Errors∪←ERR_ODD                     ⍝ indicate file size is odd
          :Else
              _Errors~←ERR_ODD
          :EndIf
          bytestream←⍉(length,_Width)⍴bytestream
          :If _Endian=1                            ⍝ swap only if little endian
              bytestream←⊖bytestream
          :EndIf
          wchars←256⊥bytestream
      :Else
          wchars←bytestream
      :EndIf
    ∇
    ∇ bytestream←split wchars;width;length;encoding
    ⍝ Depending on the width of the encoding, split wide characters into bytes
      _Errors~←ERR_ODD
      :If _Width>1
          bytestream←(_Width⍴256)⊤wchars   ⍝ split wchars into bytes
          :If _Endian=1                    ⍝ swap only if little endian
              bytestream←⊖bytestream
          :EndIf
          bytestream←,⍉bytestream
      :Else
          bytestream←wchars
      :EndIf
    ∇

    ∇ codes←decode wchars
    ⍝ Depending of the encoding, decodes the wide characters into Unicode scalars
      codes←wchars   ⍝ by default: empty or other encoding
      :If 0≠⍴,wchars
          :Select Encoding
          :Case 'UTF-8'
              codes←readutf8 wchars
          :CaseList 'UTF-16-LE' 'UTF-16-BE'
              codes←readutf16 wchars
          :EndSelect
      :EndIf
    ∇
    ∇ wchars←encode codes
    ⍝ Depending on the encoding, encode the Unicode scalars into wide characters
      wchars←codes   ⍝ by default: empty or other encoding
      :If 0≠⍴,wchars
          :Select Encoding
          :Case 'UTF-8'
              wchars←writeutf8 codes
          :CaseList 'UTF-16-LE' 'UTF-16-BE'
              wchars←writeutf16 codes
          :EndSelect
      :EndIf
    ∇

    ∇ unicode←rdU8 wchars;class;⎕IO;sect;cut;bad;touni;c0;c1;seq;bseq;tmp;todo
      :Access public shared
    ⍝ Get Unicode scalars from UTF-8 characters,
    ⍝ replacing malformed characters by U+FFFD and raising the malformed error flag.
    ⍝ Don't forget to use the legalize function on the output after reading utf
    ⍝          Binary Scalar Value         │                          UTF8 byte sequences [class of byte]                            │
    ⍝                                      │ 1st byte     │ 2nd byte     │ 3rd byte     │ 4th byte     │ 5th byte     │ 6th byte     │
    ⍝ ─────────────────────────────────────┼──────────────┼──────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
    ⍝  00000000 00000000 00000000 0xxxxxxx │ 0xxxxxxx [0] │              │              │              │              │              │
    ⍝  00000000 00000000 00000yyy yyxxxxxx │ 110yyyyy [2] │ 10xxxxxx [1] │              │              │              │              │
    ⍝  00000000 00000000 zzzzyyyy yyxxxxxx │ 1110zzzz [3] │ 10yyyyyy [1] │ 10xxxxxx [1] │              │              │              │
    ⍝  00000000 000uuuzz zzzzyyyy yyxxxxxx │ 11110uuu [4] │ 10zzzzzz [1] │ 10yyyyyy [1] │ 10xxxxxx [1] │              │              │
    ⍝  000000vv uuuuuuzz zzzzyyyy yyxxxxxx │ 111110vv [5] │ 10uuuuuu [1] │ 10zzzzzz [1] │ 10yyyyyy [1] │ 10xxxxxx [1] │              │
    ⍝  0wvvvvvv uuuuuuzz zzzzyyyy yyxxxxxx │ 1111110w [6] │ 10vvvvvv [1] │ 10uuuuuu [1] │ 10zzzzzz [1] │ 10yyyyyy [1] │ 10xxxxxx [1] │
    ⍝ - NB : in square brackets [*] is the class of the byte :
    ⍝        bytes of class 1 are called "continuation bytes", bytes of class >1 are called "start bytes"
    ⍝ - UTF-8 malformed characters must be replaced by U+FFFD. They can be :
    ⍝   ∘ a continuation byte out of a sequence (even if right after a correct sequence)
    ⍝   ∘ a sequence with not enough continuation bytes (including the case of a lonely start byte)
    ⍝   × overlong sequences (a unicode number must be embedded in the shortest possible sequence, else it is an overlong sequence)
    ⍝     NB : we don't care reading overlong sequences because we convert to unicode scalars. It is problematic only if you write UTF-8.
    ⍝   ∘ bytes equal to 0xFE or 0xFF (class 7)
      ⎕IO←0 ⋄ sect←128 64 32 16 8 4 2 2
      c1←~c0←0=class←(sect/⍳8)[wchars]     ⍝ class of each byte according to the table above
      bad←cut/⍨c0∨cut←class>1              ⍝ assume >1 sequences are wrong
      unicode←(~bad)\c0/wchars             ⍝ grab the good ones now
      :If ∨/tmp←bad                        ⍝ check the groups
          bad\←bseq←{(1↓⍵)≢1↓⍵[0]⍴1}¨(seq←c1/cut)⊂c1/class
          (bad/unicode)←65533              ⍝ and mark the string
      :AndIf ∨/todo←~bseq                  ⍝ those to do
          touni←(0,+\sect)∘{64⊥⍵-s↑⍺[s←⍴⍵],6⍴128}
          unicode+←tmp\todo\touni¨todo/seq⊂c1/wchars
      :EndIf
    ∇

    ∇ uc←readutf8 ch;bad
    ⍝ This is the private version for this class
      :If 0≠⍴Malformed←bad/⍳⍴bad←65533=uc←rdU8 ch
          _Errors∪←ERR_MALFORMED
      :Else
          _Errors~←ERR_MALFORMED
      :EndIf
    ∇

    ∇ wchars←wrU8 unicode;uni2wchars
      :Access public shared
    ⍝ Get UTF-8 characters from Unicode scalars.
    ⍝ Don't forget to use the legalize function on the input before writing utf.
      ⍝ Range of values in UCS-4        Sequence of octets in UTF-8
      ⍝ x = 0000 0000 .. 0000 007F;     x;
      ⍝ x = 0000 0080 .. 0000 07FF;     C0 + x/2∧6;    80 + x%2∧6;
      ⍝ x = 0000 0800 .. 0000 FFFF;     E0 + x/2∧12;   80 + x/2∧6%2∧6;   80 + x%2∧6;
      ⍝ x = 0001 0000 .. 001F FFFF;     F0 + x/2∧18;   80 + x/2∧12%2∧6;  80 + x/2∧6%2∧6;   80 + x%2∧6;
      ⍝ x = 0020 0000 .. 03FF FFFF;     F8 + x/2∧24;   80 + x/2∧18%2∧6;  80 + x/2∧12%2∧6;  80 + x/2∧6%2∧6;   80 + x%2∧6;
      ⍝ x = 0400 0000 .. 7FFF FFFF;     FC + x/2∧30;   80 + x/2∧24%2∧6;  80 + x/2∧18%2∧6;  80 + x/2∧12%2∧6;  80 + x/2∧6%2∧6;   80 + x%2∧6;
      ⍝ x ≥ 8000 0000                   (ISO 10646-1 does not indicate what to do)
      uni2wchars←{
          ⍵<128:⍵                                                     ⍝ 0000 0000 .. 0000 007F
          ⍵<2048:192 128+64 64⊤⍵                                      ⍝ 0000 0080 .. 0000 07FF
          ⍵<65536:224 128 128+64 64 64⊤⍵                              ⍝ 0000 0800 .. 0000 FFFF
          ⍵<2097152:240 128 128 128+64 64 64 64⊤⍵                     ⍝ 0001 0000 .. 001F FFFF
          ⍵<67108864:248 128 128 128 128+64 64 64 64 64⊤⍵             ⍝ 0020 0000 .. 03FF FFFF
          ⍵<2147483648:252 128 128 128 128 128+64 64 64 64 64 64⊤⍵    ⍝ 0400 0000 .. 7FFF FFFF
          224 128 128+64 64 64⊤65533                                  ⍝ ≥ 8000 000 : replace by U+FFFD.
      }
      wchars←⊃,/uni2wchars¨unicode
    ∇

    ∇ ch←writeutf8 uni
      ch←wrU8 uni
      _Errors~←ERR_MALFORMED ⍝ this var cannot be written by <wrU8>
    ∇

    ∇ unicode←readutf16 wchars;class;malformed;wchars2uni;illegal
    ⍝ Get Unicode scalars from UTF-16 characters,
    ⍝ replacing malformed characters by U+FFFD and raising the malformed error flag.
    ⍝ Don't forget to use the legalize function on the output after reading utf.
      ⍝   16-bit value   │ condition  │ class   │ UTF-16 rule
      ⍝ ─────────────────┼────────────┼─────────┼──────────────────────────────
      ⍝ 110110xxxxxxxxxx │ 54=⌊⍵÷1024 │ class 2 │ must be followed by a class 1
      ⍝ 110111xxxxxxxxxx │ 55=⌊⍵÷1024 │ class 1 │ must follow a class 2
      ⍝ else             │ else       │ class 0 │ no rule
      class←3|55 54⍳⌊wchars÷1024
      wchars class←(⊂(~0,¯1↓2 1⍷class))⊂¨wchars class  ⍝ gather (2 1) sequences, partition others
      malformed←~class∊(,0)(2 1)               ⍝ malformed characters
      wchars2uni←{
          ⍺:65533                              ⍝ malformed characters : put U+FFFD
          2=⍴,⍵:+/65536,1024 1×⍵-55296 56320   ⍝ surrogate pairs
          ⊃⍵                                   ⍝ single characters
      }
      unicode←malformed wchars2uni¨wchars
      Malformed←malformed/⍳⍴malformed
      :If 0≠⍴Malformed
          _Errors∪←ERR_MALFORMED
      :Else
          _Errors~←ERR_MALFORMED
      :EndIf
    ∇

    ∇ wchars←writeutf16 unicode;uni2wchars;illegal;add_illegal
    ⍝ Get the UTF-16 characters from Unicode scalars.
    ⍝ Don't forget to use the legalize function on the input before writing utf.
      ⍝ If Scalar > 0xFFFF
      ⍝     H ← (⌊(Scalar-0x10000)÷0x400) + 0xD800
      ⍝     L ← 0x400|(Scalar-0x10000) + 0xDC00
      uni2wchars←{
          ⍵<65536:⍵                                    ⍝  U+0000 →   U+FFFF : single character
          ⍵<1114112:55296 56320+1024 1024⊤⍵-65536      ⍝ U+10000 → U+10FFFF : split into surrogate pairs
          65533                                        ⍝ > U+10FFFF : relpace by U+FFFD
      }
      wchars←⊃,/uni2wchars¨unicode
      _Errors~←ERR_MALFORMED
    ∇

    ∇ unicode←legalize unicode;ill
    ⍝ Replace illegal Unicode characters by U+FFFD, and raise the illegal error flag.
    ⍝ boolean spotting illegal characters (cf http://www.unicode.org/faq/utf_bom.html#9)
      ill←unicode<0                    ⍝ Unicode scalars cannot be negative
      ill←ill∨32767=32768|⌊unicode÷2   ⍝ Unicode scalars ending in FFFE or FFFF
      ill←ill∨27=⌊unicode÷2048         ⍝ UTF-16 surrogates (range U+D800 - U+DFFF)
      ill←ill∨17≤⌊unicode÷65536        ⍝ Unicode scalars beyond U+10FFFF
      Illegal←ill/⍳⍴ill
      :If 0≠⍴Illegal
          _Errors∪←ERR_ILLEGAL
          unicode[Illegal]←65533        ⍝ replace illegal characters by U+FFFD
      :Else
          _Errors~←ERR_ILLEGAL
      :EndIf
    ∇

    ∇ unicode←toquadav newlines unicode;masks1;masks2;shiftr;i;written;mask;old;new;NL
    ⍝ Choose what newline sequence will be used (user defined or auto-detected...)
    ⍝ and replace any newline sequence by the chosen one, raising the ERR_NL flag if heterogeneous sequences are found.
    ⍝ When to ⎕AV : if the chosen sequence does not belong to ⎕AV, it will be symbolized by ⎕av[4]
    ⍝ When from ⎕AV : any lonely ⎕AV[4] character will be interpreted as the chosen sequence
      _NewLines←_NewLines∪⊂NL←(⌽⍲\2⍴V11)/13,4⊃_Unicode    ⍝ ⎕AV[4] is necessarily a newline sequence in V11 or else 13
      :If ~toquadav
          _Errors~←ERR_NL                       ⍝ when from ⎕AV : clear NL error before updating it
      :EndIf

      :If 0≠⍴_NewLineUser                       ⍝ user-defined newline sequence
          _NewLine←_NewLineUser
      :ElseIf toquadav∨(0=⍴_NewLine)            ⍝ do not auto-detect when from ⎕AV if _NewLine is already set
          masks1←_NewLines⍷¨⊂unicode            ⍝ masks of beginning of newline sequences (ambiguous : there can be several sequences on the same character, eg (13 10) and (,13)
          shiftr←{0∊⍺:⍵ ⋄ (⍴⍵)↑(-⍺+⍴⍵)↑⍵}       ⍝ shift vector to the right, filling with 0
          masks2←(⍴¨_NewLines){⊃(¯1+⍳⍺)∨.shiftr⊂⍵}¨masks1     ⍝ masks of newline characters of each sequence
          masks1←(↑masks1)∧<\[1]↑masks2         ⍝ unambiguous masks of beginning of sequences (priority given to the first ones in _NewLines)
          i←(((∨/[1]masks1)⍳1)⌷[2]masks1,0)⍳1   ⍝ search a match through rows then through columns
          _NewLine←i⊃_NewLines,_NewLines[1]     ⍝ pick the newline sequence, use the first one by default.
      :EndIf

      :If V11
      :AndIf toquadav∧(~_NewLine∧.∊⊂_Unicode)   ⍝ when toquadav : if the newline sequence is untranslatable
          new←,4⊃_Unicode                       ⍝ the newline sequence will be outputed as ⎕AV[4]
      :Else
          new←_NewLine
      :EndIf

      written←{0}¨unicode                       ⍝ mask of characters that already have been replaced, to prevent overwriting

      :For old :In (⊂_NewLine)∪_NewLines        ⍝ replace any newline sequence (old) by the chosen one (new)
          unicode←old,unicode                   ⍝ add a match at the beginning
          written←((⍴old)⍴0),written            ⍝ update written the same way
          mask←(old⍷unicode)>written            ⍝ mask of matching sequences (cannot overwrite)
          unicode written←(⊂mask)⊂¨unicode written  ⍝ partitioned at find points.
          :If toquadav>ERR_NL∊_Errors           ⍝ when getting...
          :AndIf (∨/1↓mask)∧(old≢_NewLine)      ⍝ non-default newline sequence detected
          :AndIf ∧/old∘≢¨,¨13 10                ⍝ CR & LF are accepted as homogeneous to the chosen sequence => no error
              _Errors∪←ERR_NL                   ⍝ raise error
          :EndIf
          unicode←(⍴new)↓⊃,/{new,(⍴old)↓⍵}¨unicode          ⍝ replace NL by _NewLine, and remove the first match
          written←(⍴new)↓⊃,/{((⍴new)⍴1),(⍴old)↓⍵}¨written   ⍝ update written the same way
      :EndFor
    ∇

    ∇ string←unicode2apl codes;table;index
    ⍝ Translate from Unicode to ⎕AV
      :If V11
          index←_Unicode⍳codes
          string←(⎕AV,_Replacement)[index]
          Untranslatable←(index=1+⍴_Unicode)/⍳⍴codes
          :If 0≠⍴Untranslatable
              _Errors∪←ERR_UNTRANS
          :Else
              _Errors~←ERR_UNTRANS
          :EndIf
      :Else
          string←⎕UCS codes
      :EndIf
    ∇
    ∇ codes←apl2unicode string;index
    ⍝ Translate from ⎕AV to Unicode
      :If V11
          index←⎕AV⍳string
          codes←(_Unicode,65533)[index]
          Untranslatable←(index=1+⍴⎕AV)/⍳⍴string
          :If 0≠⍴Untranslatable
              _Errors∪←ERR_UNTRANS
          :Else
              _Errors~←ERR_UNTRANS
          :EndIf
      :Else
          codes←⎕UCS string
      :EndIf
    ∇

⍝==============================================================================⍝
⍝     Private Data                                                             ⍝
⍝==============================================================================⍝

    ⍝ There are currently 4 concurrent mapping from Unicode to ⎕AV :
    ⍝ A - U:\11.0\aplsrc\unicode.h
    ⍝ B - U:\11.0\comp\dyalognet.cs
    ⍝ C - )COPY U:\11.0\aplc\dyalogc.dws Compiler.UNICODE
    ⍝ D - (⎕NEW ⎕SE.UnicodeFile '').Unicode
    ⍝ This one is from A≡C, modified to use 180 96 at [219 237]
    ⍝ B uses the greek Beta (U+03b2) for ß≡⎕AV[140] instead of the german sharp S (U+00df)
    ⍝ D is completely different and as lots of zeros.
    num←{⍎4↓⍵} ⋄ x←⍬
    x,←num '  0:    0     8    10    13    32   12 57344 57345'
    x,←num '  8:   27     9  9014   619    37   39  9082  9077'
    x,←num ' 16:   95    97    98    99   100  101   102   103'
    x,←num ' 24:  104   105   106   107   108  109   110   111'
    x,←num ' 32:  112   113   114   115   116  117   118   119'
    x,←num ' 40:  120   121   122 57346 57347  175    46  9068'
    x,←num ' 48:   48    49    50    51    52   53    54    55'
    x,←num ' 56:   56    57 57348   164   165   36   163   162'
    x,←num ' 64: 8710    65    66    67    68   69    70    71'
    x,←num ' 72:   72    73    74    75    76   77    78    79'
    x,←num ' 80:   80    81    82    83    84   85    86    87'
    x,←num ' 88:   88    89    90 57349 57350  253   183 57351'
    x,←num ' 96: 9049   193   194   195   199  200   202   203'
    x,←num '104:  204   205   206   207   208  210   211   212'
    x,←num '112:  213   217   218   219   221  254   227   236'
    x,←num '120:  240   242   245   123  8866  125  8867  9015'
    x,←num '128:  168   192   196   197   198 9064   201   209'
    x,←num '136:  214   216   220   223   224  225   226   228'
    x,←num '144:  229   230   231   232   233  234   235   237'
    x,←num '152:  238   239   241    91    47 9023    92  9024'
    x,←num '160:   60  8804    61  8805    62 8800  8744  8743'
    x,←num '168:   45    43   247   215    63 8714  9076   126'
    x,←num '176: 8593  8595  9075  9675    42 8968  8970  8711'
    x,←num '184: 8728    40  8834  8835  8745 8746  8869  8868'
    x,←num '192:  124    59    44  9073  9074 9042  9035  9033'
    x,←num '200: 9021  8854  9055  9017    33 9045  9038  9067'
    x,←num '208: 9066  8801  8802   243   244  246   248    34'
    x,←num '216:   35 57352    38   180  9496 9488  9484  9492'
    x,←num '224: 9532  9472  9500  9508  9524 9516  9474    64'
    x,←num '232:  249   250   251    94   252   96  8739   182'
    x,←num '240:   58  9079   191   161  8900 8592  8594  9053'
    x,←num '248:   41    93 57353 57354   167 9109  9054  9059'
    :Field Private _Unicode←x

    x←''                                                 ⋄ ERR_OK←⍬
    ⍝ File Errors :
    x,←⊂'File does not exist'                            ⋄ ERR_EXIST←1       ⍝ updated in Import - cleared in Export
    x,←⊂'File Size not a multiple of Encoding Width'     ⋄ ERR_ODD←2         ⍝ updated in Import - cleared in Export
    ⍝ Encoding Errors :
    x,←⊂'Unmarked Encoding : Assuming UTF-8'             ⋄ ERR_NOBOM←3       ⍝ updated in Import - cleared in Export or writing Raw/Text/NestedText
    x,←⊂'Detected Encoding different from specified'     ⋄ ERR_BADBOM←4      ⍝ updated in Import - cleared in Export or writing Raw/Text/NestedText
    x,←⊂'Malformed UTF Characters'                       ⋄ ERR_MALFORMED←5   ⍝ updated in Import - cleared in Export or writing Raw/Text/NestedText
    ⍝ Unicode Errors :
    x,←⊂'Illegal Unicode Characters'                     ⋄ ERR_ILLEGAL←6     ⍝ updated in Import and when writing Raw/Text/NestedText
    ⍝ Text Errors :
    x,←⊂'Non homogeneous New Line sequences'             ⋄ ERR_NL←7          ⍝ updated when writing Text/NestedText - cleared when writing Raw
    x,←⊂'Untranslatable Characters to/from QuadAV'       ⋄ ERR_UNTRANS←8     ⍝ updated when writing Text/NestedText - cleared when writing Raw (not possible in unicode version)
    :Field Private _ErrorMessages←x

  ⍝ Format of _TableBOM :
    ⍝ 1st column : name : vector of uppercase strings used to retreive the name (See the Encoding property)
    ⍝ 2nd column : width of the encoding, in bytes
    ⍝ 3rd column : endianness : 0=N/A ; 1=Little ; 2=Big
    ⍝ 4th column : BOM (vector of bytes) (see http://en.wikipedia.org/wiki/Byte_Order_Mark)
    ⍝ the first rows pre-empt the following rows (the 1st match is used)
    ⍝ big endian should pre-empt little endian and be used by default according to the Unicode Standard (http://www.unicode.org/faq/utf_bom.html#36)
    ⍝ UTF-16 should pre-empt UTF-32, because this latter is very rarely used. User will have to specify UTF-32 to use it. This is not standard.
    x←0 4⍴''
    x,[1]←('UTF' '8') 1 0 (239 187 191)               ⍝ UTF-8                   ⍝ higher priority
    x,[1]←('UTF' '16' 'BE') 2 2 (254 255)             ⍝ UTF-16-BE
    x,[1]←('UTF' '16' 'LE') 2 1 (255 254)             ⍝ UTF-16-LE
    x,[1]←('UTF' '32' 'BE') 4 2 (0 0 254 255)         ⍝ UTF-32-BE
    x,[1]←('UTF' '32' 'LE') 4 1 (255 254 0 0)         ⍝ UTF-32-LE
    :Field Private _TableBOM←x
    ⎕ex'x' ⍝ get rid of this

    :Field Private _Encoding            ⍝ row of _TableBOM currently in use
    :Field Private _EncodingDefault←1   ⍝ default encoding - if you change it don't forget to change _ErrorMessages[5]
    :Field Private _EncodingUser←⍬      ⍝ encoding forced by the user (empty if none)

    :Property _EncodingName             ⍝ current name of encoding (see above)
        ∇ r←get
          r←⊃_TableBOM[_Encoding;1]
        ∇
    :EndProperty
    :Property _EncodingList             ⍝ list of handled encoding names
        ∇ r←get
          r←_TableBOM[;1]
        ∇
    :EndProperty
    :Property _Width                    ⍝ current width (see above)
        ∇ r←get
          r←⊃_TableBOM[_Encoding;2]
        ∇
    :EndProperty
    :Property _Endian                   ⍝ current endianness (see above)
        ∇ r←get
          r←⊃_TableBOM[_Encoding;3]
        ∇
    :EndProperty
    :Property _BOM                      ⍝ current BOM (see above)
        ∇ r←get
          r←⊃_TableBOM[_Encoding;4]
        ∇
    :EndProperty
    :Property _BOMlist                  ⍝ list of handled BOMs (see above)
        ∇ r←get
          r←_TableBOM[;4]
        ∇
    :EndProperty

⍝==============================================================================⍝
⍝     Debug stuff                                                              ⍝
⍝==============================================================================⍝

    ∇ r←getdebugdata;T;R;mal;ill;unt
      :Access Public
    ⍝ builds a matrix with one line of status below each line of text.
    ⍝ If the newline sequence is multi-char, indices will be messed up.
      T←Text
      R←(⍴T)⍴'·'
      mal ill←Malformed Illegal     ⍝ Text indices of Raw errors (can be moved because of newlines)
      unt←Untranslatable            ⍝ Text indices of Text errors (can not be moved)
      R[mal~mal∩unt]←'∆'
      R[mal∩unt]←'⍋'
      R[ill~ill∩unt]←'○'
      R[ill∩unt]←'⌽'
      R[unt~mal∪ill]←'|'
      T R←(⎕AV[4],T)('·',R)
      T R←(⊂T){1↓¨(⍺∊⎕AV[4 3])⊂⍵}¨T R

      r←⍬
      r,←⊂'· = OK ; ∆ = Malformed ; ○ = Illegal ; | = Untranslatable ; ⍋ = Malformed and Untranslatable ; ⌽ = Illegal and Untranslatable'
      r,←⊂''
      r,←,T,[1.5]R
    ∇

:EndClass ⍝ UnicodeFile  $Revision: 21539 $

error: pathspec 'Utils/UnicodeFile.dyalog' did not match any file(s) known to git


QA for jqButtonsetSimple. Note that it is overly complicated because a regular Selenium Click misses the button by one pixel.

 msg←Test dummy;Gives;GO;Boots
 Gives←{'output'WaitFor ⍵⊣'CssSelector'∘Click¨⊂⍣(1=≡⍺)⊢⍺}
 GO←'#menu_2' ⋄ Boots←'label[for="footwear_2"] span'
 msg←''
 :If 0=⍴msg←GO Gives'barefoot'
     msg←Boots GO Gives'Boots'
 :EndIf

error: pathspec 'MS3/QA/Examples/JQ/jqButtonsetSimple.dyalog' did not match any file(s) known to git


Group together the code exposed as the external API for package implementers.


Black-Scholes example

Black-Scholes example

CND ← {
    X ← ⍵
    a ← 0.31938153 ¯0.356563782 1.781477937 ¯1.821255978 1.330274429

    l ← |X
    k ← ÷1+0.2316419×l
    w ← 1 - (÷((2×(○1))⋆0.5)) × (⋆-(l×l)÷2) × (a +.× (k⋆⍳5))

    ((|0⌊×X)×(1-w))+(1-|0⌊×X)×w
}

⍝ S - current price
⍝ X - strike price
⍝ T - expiry in years
⍝ r - riskless interest rate
⍝ v - volatility

S ← 60
X ← 65
T ← 1
r ← 0.1
v ← 0.2

d1 ← ((⍟S÷X)+(r+(v⋆2)÷2)×T)÷(v×T⋆0.5)
d2 ← d1-v×T⋆0.5

⍝ Call price
callPrice ← (S×CND(d1))-(X×⋆-r×T)×CND(d2)

⍝ Put price (not tested)
⍝ putPrice ← (X×⋆-r×T)×CND(-d2)-S×CND(-d1)

error: pathspec 'tests/blackscholes.apl' did not match any file(s) known to git


Missed edit.

Missed edit.


Added find function over list of key/value lists.


Arrange for a package to know its directory path during loading.


Add command-specific help to UI.

Add command-specific help to UI.


changed log4j to log4cxx

changed log4j to log4cxx

git-svn-id: 3072ad45a6a0c933d2095f70d03f3573d019ba5f@308287 13f79535-47bb-0310-9956-ffa450edef68

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/antoine1fr/log4cxx.git/'


Transform a lambda into a named function (control_file_path).


Add ]pkg ident command.

Add ]pkg ident command.


Not going to use generalized key/value routines.


Localize variables.

Localize variables.


Add empty value test. Be consistent about handling of empty values.


Finished local_dependencies computation.


Fix compatibility issue. GNU APL's behavior of enclose was corrected; my code was probably incorrect from the start.


Rework run_probe function. Set most platform variables to 'unknown'
(except for platform family, which is still assumed to be 'unix'). Use
a probes to illustrate how to set a few of the platform variables.

Fix sh and shell functions to handle multiline output.


Make the package manager's identity a constant.


More constant definitions.

More constant definitions.


Rename to fit in package manager.

Rename to fit in package manager.

Create empty list and key/value list according to argument.


Prohibit imported APL files from assigning to system variables.


Added unwrap function to undo extra enclosures induced by lookup over each of multiple key/value lists.


now test example

now test example

start ← ⎕NOW 0

⎕ ← 'Starting computation:'

⍝ time consuming operation
res ← ⌈/ +/ 5000 5000 ⍴ ⍳ 28

⎕ ← 'Result:'
⎕ ← res

⎕ ← 'Time (ms):'
⎕ ← (⎕NOW 0) - start

0

error: pathspec 'tests/now.apl' did not match any file(s) known to git


Prohibit the package manager from attempting to load itself.


Correct end-of-line handling in sh function.


Added fibonacci series generator in APL.

⍝ This function takes a vector of "0" and "1" (without quotes) as a right formal parameter
⍝ and the maximum fibonacci value to go up to as the left formal parameter.
⍝ It return a vector of fibonacci terms less than the left formal parameter.
fib ← {
   ¯1↑⍵<⍺:⍺ fib (⍵,+/¯2↑⍵)
   ¯1↓⍵
}

error: pathspec 'Fibonacci_series/APL/jcla1/fib.apl' did not match any file(s) known to git


Don't enlist pair with empty keyword.

Don't enlist pair with empty keyword.


Fix kvl, keys and vals function to deal with one-item lists.

Add examples of processing lists of key/value lists.


new example

new example

:Class ejDatePickerAdvanced : MiPageSample
⍝ Control:: _SF.ejDatePicker
⍝ Description::  advance functionality.
⍝ Show 2 calendars to select reservation dates.
⍝ The first date cannot be before today and the second cannot be the
⍝ date before tomorrow. Its default is 1 week after check in.

    ∇ Compose;today;fromidn;minto;tbl;tr;td;head;todate;from
      :Access Public
      today←3↑⎕TS
      fromidn←dateToIDN today

      Add _.h1'Drop ↓ Inn'
      Add _.h2'Hotel reservation system'

    ⍝ The table header
      tbl←Add _.table
      head←tbl.Add _.thead
      (head.Add _.tr).{Add _.th ⍵}¨'Check in' 'Check out'

      tr←tbl.Add _.tr
    ⍝ The in date
      td←tr.Add _.td
      from←'in'td.Add _SF.ejDatePicker today'yyyy/MM/dd'
      from.Set'minDate'(newDate today)
      from.On'change' 'setNewDate',⊂('in' 'model' 'value')('out' 'eval' '$("#out").ejDatePicker("model.value")')

    ⍝ The out date
      td←tr.Add _.td
      todate←IDNToDate fromidn+7
      TO←'out'td.Add _SF.ejDatePicker todate'yyyy/MM/dd'
      minto←newDate IDNToDate fromidn+1
      TO.Set'minDate'minto
    ∇

    newDate←{'⍎new Date("',(⍕⍵),'")'}
    dateToIDN←{2 ⎕NQ'.' 'datetoidn'⍵}
    IDNToDate←{3↑ 2 ⎕NQ'.' 'idntodate'⍵}

    ∇ r←setNewDate;in;out
      :Access public
    ⍝ Reset minimum reservation check out date
      in←dateToIDN stringToDate⍕Get'in'
      r←'minDate'TO.Update newDate IDNToDate in+1

      out←dateToIDN stringToDate⍕Get'out'

    ⍝ If the new IN date is not before the OUT date we reset OUT to 1 week after
      :If in≥out
          r,←'value'TO.Update newDate IDNToDate in+7
      :EndIf
    ∇

    MONTHS←↓12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec'

    FI←{(b v)←⎕vfi ⍵ ⋄ b/v}

    ∇ ymd←stringToDate str;pos;mon;t
     ⍝ str is of the genre "Wed Aug 05 2015 00:00:00 GMT-0400 (Eastern Daylight Time)"
     ⍝ We need to weed out the day of the week and the time
      str←(+/∧\' '=str)↓str           ⍝ remove the leading spaces
      :If 0∊⍴t←MONTHS ⎕S 0 3⊢str      ⍝ look for the month as a string. If not found
          ymd←3↑FI str                ⍝ grab the 1st 3 numbers found
          ymd←ymd[⍒(2×31<ymd)+ymd<12] ⍝ put in correct order
      :Else                           ⍝ otherwise (if found)
          (pos mon)←0 1+1⊃t
          :If ~0∊⍴t←FI pos↑str        ⍝ any number before the month? (e.g. 2 May 2021)
              ymd←⌽⍣(31<⍬⍴t)⊢(1↑FI pos↓str),mon,t
          :Else
              ymd←¯1⌽mon,2↑FI pos↓str
          :EndIf
      :EndIf
    ∇

:EndClass

error: pathspec 'MS3/Examples/SF/ejDatePickerAdvanced.dyalog' did not match any file(s) known to git


Use rxvt instead of xterm.

Use rxvt instead of xterm.


Label names with type.

Label names with type.


Added euclidean norm in APL

Added euclidean norm in APL

⍝ This version works by computing the sum of the squares in ⍵
⍝ and then finding the square root.
euclidean_norm ← {
  (+/⍵ × ⍵) * ÷ 2
}

error: pathspec 'Euclidean_Norm/APL/jcla1/euclidean_norm.apl' did not match any file(s) known to git


Mark internal-use functions.

Mark internal-use functions.

Add kvl append function.


TableSimple with some simple formatting.

:Class TableSimple : MiPageSample
⍝ Control::     _DC.Table
⍝ Description:: Display tabular data with a bit of styling

    :Include #.HTMLUtils ⍝ For ScriptFollows

    ∇ Compose;lmt;i10;data;myTable
      :Access public

      Add _.style ScriptFollows
      ⍝ .myStyle table {
      ⍝     border-collapse: collapse;
      ⍝ }
      ⍝ .myStyle table, th, td {
      ⍝     border: 1px solid black;
      ⍝ }
      ⍝ .myStyle th, td {
      ⍝     width: 30px;
      ⍝     text-align: right;
      ⍝     padding: 2px;
      ⍝ }
      ⍝ .myStyle tr td: first-of-type {
      ⍝     font-weight: bold;
      ⍝ }

      Add _.h2'The Little Multiplication Table'

      lmt←∘.×⍨i10←⍳10
      data←(' ',i10)⍪i10,lmt
      myTable←'myTable .myStyle'Add _.Table data
      myTable.HeaderRows←1
    ∇

:EndClass

error: pathspec 'MS3/Examples/DC/TableSimple.dyalog' did not match any file(s) known to git


new version of mandelbrot with power tuples

⍝ Mandelbrot
⍝ grid-size in left argument (e.g., (1024 768))
⍝ X-range, Y-range in right argument

mandelbrot ← {
  X ← ⊃⍺                                 ⍝ e.g., 1024
  Y ← ⊃1↓⍺                               ⍝ e.g., 768
  xRng ← 2↑⍵
  yRng ← 2↓⍵
  dx ← ((xRng[2])-xRng[1]) ÷ X
  dy ← ((yRng[2])-yRng[1]) ÷ Y
  cxA ← Y X ⍴ (xRng[1]) + dx × ⍳X        ⍝ real plane
  cyA ← ⍉ X Y ⍴ (yRng[1]) + dy × ⍳Y      ⍝ img plane
  N ← 90                                 ⍝ iterations
  mandel1 ← {
    cx ← ⍺
    cy ← ⍵
    f ← {
      arg ← ⍵
      x ← arg[1]                         ⍝ real value
      y ← arg[2]                         ⍝ imaginary value
      count ← arg[3]
      dummy ← arg[4]
      zx ← cx+(x×x)-(y×y)
      zy ← cy+(x×y)+(x×y)
      conv ← 4 > (zx × zx) + zy × zy
      count2 ← count + 1 - conv
      (zx zy count2 dummy)
    }
    res ← (f ⍣ N) (0 0 0 'dummy')                ⍝ perform N iteration of a single mandelbrot point
    res[3]
  }
  res ← cxA mandel1¨ cyA
  res ÷ N
}

layout ← {
  arr ← '$#Oo*=+:- '
  arr[⍵+1]
}

norm ← { layout¨ ⌈9 × ⍵ }

mandelWrap ← {
  ⎕ ← norm (⌽⍵) ⍴ ⍵ mandelbrot ¯2 0.75 ¯0.75 0.75
}

mandelWrap 20 12

0

error: pathspec 'tests/mandelbrotInnerPower2.apl' did not match any file(s) known to git


TableSimple sample and QA

TableSimple sample and QA

 msg←TableSimple
⍝ Just check to see whether the litte multiplication table seems to have been produced

 :If '99' '100'≡(BROWSER.FindElementsByCssSelector⊂'#LMT td')[108 109].Text
     msg←'Expected output was not produced.'
 :Else ⋄ msg←''
 :EndIf

error: pathspec 'MS3/QA/Examples/DC/TableSimple.dyalog' did not match any file(s) known to git


Name some of the most useful functions and variables to be used in a control file. More to be added...

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/TieDyedDevil/apl-pkg.git/'