######################################################################

# comments and trailing commas in pseudo-JSON don't bother jeff
jf -a . tsconfig.json
compilerOptions
    target                            es5
    module                            commonjs
    strict                            true
    esModuleInterop                   true
    skipLibCheck                      true
    forceConsistentCasingInFileNames  true

jf -to=lines 'in.tstype()' tsconfig.json
interface {
  compilerOptions: interface {
    target: string
    module: string
    strict: boolean
    esModuleInterop: boolean
    skipLibCheck: boolean
    forceConsistentCasingInFileNames: boolean
  }
}

jf -from=ini -a in@tryparse Cargo.toml
package
    name     demos
    version  0.1.0
    authors  1 items
                pac <none.of@your.biz>
    edition  2,018
dependencies  {}

# multiple inputs are put together into a general input object
jf -a 'in.revalue(v.@limit20)' tsconfig.json https://www.google.com | head -n 30
tsconfig.json
    compilerOptions
        target                            es5
        module                            commonjs
        strict                            true
        esModuleInterop                   true
        skipLibCheck                      true
        forceConsistentCasingInFileNames  true
https://www.google.com
    head
        @         head
        children  1 items
                    @            meta
                    @content     text/html; charset=U
                    @http-equiv  Content-Type
                    children     2 items
                                    @          meta
                                    @content   /images/branding/goo
                                    @itemprop  image
                                    children   5 items
                                                @     title
                                                text  1 items
                                                        Google
                                                ········································
                                                @       script
                                                @nonce  s4I9Zm5bEcnaeeD6FPkw
                                                text    1 items
                                                            (function(){var _g={
                                                ········································
                                                @     style

# no need to pipe from curl and lose MIME-type autodetection
# jf -a 'in . del(`client_ip`, `timezone`)[1:]' https://worldtimeapi.org/api/ip
# the above is commented, not to risk showing ip and other info

######################################################################

# a text file with a million and 2 bytes of ASCII
wc -cl e-digits.txt | nn
      0 1000002 e-digits.txt

# just showing the beginning of that single-line file
head -c 52 e-digits.txt | nn
2.71828182845904523536028747135266249775724709369995

# tally all those digits
jf -a in.tally e-digits.txt
2  99,846
.  1
7  99,910
1  100,132
8  99,814
4  100,389
5  100,087
9  99,691
0  99,425
3  100,228
6  100,479

jf -a 'in.tally.sort(-v)' e-digits.txt
6  100,479
4  100,389
3  100,228
1  100,132
5  100,087
7  99,910
2  99,846
8  99,814
9  99,691
0  99,425
.  1

# now these bullets are good for something: casual insta-glance on
# the side conveys each digit key
jf -a 'in.tally.sort(-v)  .  ren(`${k} ${+k*bullet}`)' e-digits.txt
6 ••••••     100,479
4 ••••       100,389
3 •••        100,228
1 •          100,132
5 •••••      100,087
7 •••••••    99,910
2 ••         99,846
8 ••••••••   99,814
9 •••••••••  99,691
0            99,425
.            1

######################################################################

# colored tiles, showing numeric color scale overall
jf -q '(0..50) . map((v/50).tile) . join . quote(nan.tile)'
××

# simpler way to do the same
jf -q '0..50.tiles . quote(nan.tile)'
××

# some data stats/viz
jf -q '
data = 50.map(rexp(3)) - 3;
{
    stats: data.numstats,
    viz: data.spark,
}'
stats
    n        50
    min      -2.9943585613012100
    max      10.875763491839111
    sum      9.95385072507803
    mean     0.1990770145015605
    sd       3.732687119970095
    geomean  NaN
    rms      26.39408374578538
    pos      20
    zero     0
    neg      30
    nan      0
viz    +▄▁▆▆▆▇▆▆▇+▆▇▆+▆▆▇▄▁▆−−+▇▆++▆▇▆+▃▇▇+

######################################################################

# how many items each top-level item has
jf -a '{k: v.len(): in}' cadex.json.gz
groupDetail   3
terms         1
seriesDetail  26
observations  164

# what type each top-level item is, and how many items it has
jf -a 'in.map({type: v.type(), items: v.len()})' cadex.json.gz
groupDetail
    type   object
    items  3
terms
    type   object
    items  1
seriesDetail
    type   object
    items  26
observations
    type   array
    items  164

# what type each top-level item is, and how many items it has
jf -a '{k: {type: v.type(), items: v.len()}: in}' cadex.json.gz
groupDetail
    type   object
    items  3
terms
    type   object
    items  1
seriesDetail
    type   object
    items  26
observations
    type   array
    items  164

jf -to=lines 'in.tstype()' cadex.json.gz
interface {
  groupDetail: interface {
    label: string
    description: string
    link: null
  }
  terms: interface {
    url: string
  }
  seriesDetail: interface {
    FXAUDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXBRLCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXCNYCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXEURCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXHKDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXINRCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXIDRCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXJPYCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXMYRCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXMXNCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXNZDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXNOKCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXPENCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXRUBCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXSARCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXSGDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXZARCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXKRWCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXSEKCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXCHFCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXTWDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXTHBCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXTRYCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXGBPCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXUSDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
    FXVNDCAD: interface {
      label: string
      description: string
      dimension: interface {
        key: string
        name: string
      }
    }
  }
  observations: []interface {
    d: string,
    FXAUDCAD: interface {
      v: string
    },
    FXBRLCAD: interface {
      v: string
    },
    FXCNYCAD: interface {
      v: string
    },
    FXEURCAD: interface {
      v: string
    },
    FXHKDCAD: interface {
      v: string
    },
    FXINRCAD: interface {
      v: string
    },
    FXIDRCAD: interface {
      v: string
    },
    FXJPYCAD: interface {
      v: string
    },
    FXMXNCAD: interface {
      v: string
    },
    FXNZDCAD: interface {
      v: string
    },
    FXNOKCAD: interface {
      v: string
    },
    FXPENCAD: interface {
      v: string
    },
    FXRUBCAD: interface {
      v: string
    },
    FXSARCAD: interface {
      v: string
    },
    FXSGDCAD: interface {
      v: string
    },
    FXZARCAD: interface {
      v: string
    },
    FXKRWCAD: interface {
      v: string
    },
    FXSEKCAD: interface {
      v: string
    },
    FXCHFCAD: interface {
      v: string
    },
    FXTWDCAD: interface {
      v: string
    },
    FXTRYCAD: interface {
      v: string
    },
    FXGBPCAD: interface {
      v: string
    },
    FXUSDCAD: interface {
      v: string
    }
  }
}

# typical example of a mid-complexity ad-hoc query, using gzipped data
jf -a '
    latest = in.observations.last;
    rates = {k-`FX`-`CAD`: +v.v: latest.drop(`d`)};
    { date: latest.d, rates.sort(k)... }' cadex.json.gz | sbs 3
date  2023-08-25         █ IDR   0.000089           █ RUB   0.01428           
AUD   0.8725000000000001 █ INR   0.01646            █ SAR   0.3627            
BRL   0.2791             █ JPY   0.0093             █ SEK   0.1233            
CHF   1.5376000000000001 █ KRW   0.001027           █ SGD   1.0036000000000000
CNY   0.1867             █ MXN   0.0811100000000000 █ TRY   0.0513            
EUR   1.4695             █ NOK   0.1273             █ TWD   0.04276           
GBP   1.7133000000000000 █ NZD   0.8044             █ USD   1.3606            
HKD   0.1735             █ PEN   0.3684             █ ZAR   0.0730200000000000

# typical example of a mid-complexity ad-hoc query, using live web data
jf -a '
    latest = in.observations.last;
    rates = {k-`FX`-`CAD`: +v.v: latest.drop(`d`)};
    { date: latest.d, rates.sort(k)@nice4@green... }' \
    https://www.bankofcanada.ca/valet/observations/group/FX_RATES_DAILY/json?start_date=`date +%Y`-01-01 | sbs 3
date  2023-08-25 █ IDR   0.0001 █ RUB   0.0143
AUD   0.8725     █ INR   0.0165 █ SAR   0.3627
BRL   0.2791     █ JPY   0.0093 █ SEK   0.1233
CHF   1.5376     █ KRW   0.0010 █ SGD   1.0036
CNY   0.1867     █ MXN   0.0811 █ TRY   0.0513
EUR   1.4695     █ NOK   0.1273 █ TWD   0.0428
GBP   1.7133     █ NZD   0.8044 █ USD   1.3606
HKD   0.1735     █ PEN   0.3684 █ ZAR   0.0730

######################################################################

# at some point I wanted to check some assumptions about plurals by
# looking at examples of words ending with any vowel followed by `y`
jf -a 'in.lower.lines.filter(v ~ `[aeiou]y$`)' words.txt.gz | head
1,533 items
    abacay
    abay
    abbey
    abey
    abray
    absey
    accloy
    accoy
    ackey

######################################################################

# get the playtime for all playable media files in the jf-demo folder
jf -from=b -a '{k: try(v.duration, skip): in}.sort(-v)' *.*
3x3.mp4            1.802
beats.wav          1.5
2048hz Clicks.m4a  1.022

# get more info about all files in the jf-demo folder
jf -from=b -a '{k: v.mediainfo: in}.denil(`text/plain`).sort(-v.size)' *.* | head -n 20
movies.json
    mime       application/json
    size       3,386,802
    duration   NaN
    width      NaN
    height     NaN
    depth      NaN
    thumbnail  text/plain
words.txt.gz
    mime       application/gzip
    size       1,086,426
    duration   NaN
    width      NaN
    height     NaN
    depth      NaN
    thumbnail  text/plain
e-digits.txt
    mime       text/plain
    size       1,000,002
    duration   NaN

######################################################################

# wondering how long float64 mantissas will work as unix-style timestamps...
# are those in millionths or billionths of a second?
jf -q '2**{52,53,64}/{1e6,1e9}/day/365.25+1970'
52
    1000000     2,112.710460471345
    1000000000  1,970.142710460471
53
    1000000     2,255.420920942689
    1000000000  1,970.2854209209427
64
    1000000     586,512.0460906264
    1000000000  2,554.5420460906266

# you say about 1500 each day, what range is that a year?
jf -q 1500.fuzz*[365,366].kv
1450
    365  529,250
    366  530,700
1500
    365  547,500
    366  549,000
1550
    365  565,750
    366  567,300

# now you tell me about 1400-1500 a day, so between 1400 and 1500 a day...
jf -q [1400,1500].kv*[365,366].kv
1400
    365  511,000
    366  512,400
1500
    365  547,500
    366  549,000

# partial ASCII table
jf -q '{v: v.ord: space+visascii}' | sbs
   32 █ +  43 █ 6  54 █ A  65 █ L  76 █ W  87 █ b  98  █ m  109 █ x  120
!  33 █ ,  44 █ 7  55 █ B  66 █ M  77 █ X  88 █ c  99  █ n  110 █ y  121
"  34 █ -  45 █ 8  56 █ C  67 █ N  78 █ Y  89 █ d  100 █ o  111 █ z  122
#  35 █ .  46 █ 9  57 █ D  68 █ O  79 █ Z  90 █ e  101 █ p  112 █ {  123
$  36 █ /  47 █ :  58 █ E  69 █ P  80 █ [  91 █ f  102 █ q  113 █ |  124
%  37 █ 0  48 █ ;  59 █ F  70 █ Q  81 █ \  92 █ g  103 █ r  114 █ }  125
&  38 █ 1  49 █ <  60 █ G  71 █ R  82 █ ]  93 █ h  104 █ s  115 █ ~  126
'  39 █ 2  50 █ =  61 █ H  72 █ S  83 █ ^  94 █ i  105 █ t  116 █       
(  40 █ 3  51 █ >  62 █ I  73 █ T  84 █ _  95 █ j  106 █ u  117 █       
)  41 █ 4  52 █ ?  63 █ J  74 █ U  85 █ `  96 █ k  107 █ v  118 █       
*  42 █ 5  53 █ @  64 █ K  75 █ V  86 █ a  97 █ l  108 █ w  119 █       

# partial ASCII table; worse version, but shows pipes and func `map`
jf -q 'space.ord..126 ; _.map(v.chr, v)' | sbs
   32 █ +  43 █ 6  54 █ A  65 █ L  76 █ W  87 █ b  98  █ m  109 █ x  120
!  33 █ ,  44 █ 7  55 █ B  66 █ M  77 █ X  88 █ c  99  █ n  110 █ y  121
"  34 █ -  45 █ 8  56 █ C  67 █ N  78 █ Y  89 █ d  100 █ o  111 █ z  122
#  35 █ .  46 █ 9  57 █ D  68 █ O  79 █ Z  90 █ e  101 █ p  112 █ {  123
$  36 █ /  47 █ :  58 █ E  69 █ P  80 █ [  91 █ f  102 █ q  113 █ |  124
%  37 █ 0  48 █ ;  59 █ F  70 █ Q  81 █ \  92 █ g  103 █ r  114 █ }  125
&  38 █ 1  49 █ <  60 █ G  71 █ R  82 █ ]  93 █ h  104 █ s  115 █ ~  126
'  39 █ 2  50 █ =  61 █ H  72 █ S  83 █ ^  94 █ i  105 █ t  116 █       
(  40 █ 3  51 █ >  62 █ I  73 █ T  84 █ _  95 █ j  106 █ u  117 █       
)  41 █ 4  52 █ ?  63 █ J  74 █ U  85 █ `  96 █ k  107 █ v  118 █       
*  42 █ 5  53 █ @  64 █ K  75 █ V  86 █ a  97 █ l  108 █ w  119 █       

# on the way to PCM/wav-related calculation below...
jf -n '{44_100,48_000}'
{
  "44100": 44100,
  "48000": 48000
}

# getting there...
jf -n '{44_100,48_000}*{mono:1,stereo:2}*2'
{
  "44100": {
    "mono": 88200,
    "stereo": 176400
  },
  "48000": {
    "mono": 96000,
    "stereo": 192000
  }
}

# calculate PCM time-durations of 4GB, the max size for .wav files
jf -n '{44_100,48_000}*{mono:1,stereo:2}*2 ; 4*gb/_ ; _@s2hms'
{
  "44100": {
    "mono": "13:31:35.77",
    "stereo": "06:45:47.89"
  },
  "48000": {
    "mono": "12:25:39.24",
    "stereo": "06:12:49.62"
  }
}

# KBs per minute for common MP3/AAC CBR settings
jf -q '{`${64*v}k`: 8*v: 2..4} * {v.fix1: v: .5*20.iota} * 60' | sbs 3
128k            █ 192k             █ 256k            
    0.5   480   █     0.5   720    █     0.5   960   
    1.0   960   █     1.0   1,440  █     1.0   1,920 
    1.5   1,440 █     1.5   2,160  █     1.5   2,880 
    2.0   1,920 █     2.0   2,880  █     2.0   3,840 
    2.5   2,400 █     2.5   3,600  █     2.5   4,800 
    3.0   2,880 █     3.0   4,320  █     3.0   5,760 
    3.5   3,360 █     3.5   5,040  █     3.5   6,720 
    4.0   3,840 █     4.0   5,760  █     4.0   7,680 
    4.5   4,320 █     4.5   6,480  █     4.5   8,640 
    5.0   4,800 █     5.0   7,200  █     5.0   9,600 
    5.5   5,280 █     5.5   7,920  █     5.5   10,560
    6.0   5,760 █     6.0   8,640  █     6.0   11,520
    6.5   6,240 █     6.5   9,360  █     6.5   12,480
    7.0   6,720 █     7.0   10,080 █     7.0   13,440
    7.5   7,200 █     7.5   10,800 █     7.5   14,400
    8.0   7,680 █     8.0   11,520 █     8.0   15,360
    8.5   8,160 █     8.5   12,240 █     8.5   16,320
    9.0   8,640 █     9.0   12,960 █     9.0   17,280
    9.5   9,120 █     9.5   13,680 █     9.5   18,240
    10.0  9,600 █     10.0  14,400 █     10.0  19,200

######################################################################

# fs is one of the few funcs which spontaneously looks at your files
jf -q 'dot.fs.sort(-v)'
movies.json                         3,386,802
words.txt.gz                        1,086,426
e-digits.txt                        1,000,002
pi-digits.txt                       1,000,002
top-100k-domains.csv.gz             913,806
data-uris.html                      800,155
movies.json.gz                      743,003
na-pop-density-map-2020-shrunk.png  330,005
cadex.json                          284,933
timezones.jsonl                     273,235
terminal-examples.html              174,922
beats.wav                           144,046
examples.html                       132,726
3x3.mp4                             113,324
no-data.html                        90,136
first-10000-primes.jsonl            58,982
google-com.json                     51,165
cadex.html                          34,052
terminal-examples.ansi              20,786
e-digits.html                       19,325
cadex.json.gz                       15,556
country-info.tsv                    13,881
terminal-examples.sh                10,633
2048hz Clicks.m4a                   9,928
tsconfig.json                       6,792
demo-commands.txt                   5,314
no-data-examples.jf                 5,163
cadex-example.jf                    3,113
e-digits-example.jf                 1,898
e-digits.ansi                       1,825
browser-popup-examples.sh           845
rebuild.sh                          839
strcap.jf                           408
podcast-feeds.txt                   336
Cargo.toml                          211
primes-up-to.sh                     194

# group by common file extension, sorted for easier eye-scanning
jf -q 'dot.fs.sort(-v).group(k.ext).sort(k)'
.ansi
    terminal-examples.ansi  20,786
    e-digits.ansi           1,825
.gz
    words.txt.gz             1,086,426
    top-100k-domains.csv.gz  913,806
    movies.json.gz           743,003
    cadex.json.gz            15,556
.html
    data-uris.html          800,155
    terminal-examples.html  174,922
    examples.html           132,726
    no-data.html            90,136
    cadex.html              34,052
    e-digits.html           19,325
.jf
    no-data-examples.jf  5,163
    cadex-example.jf     3,113
    e-digits-example.jf  1,898
    strcap.jf            408
.json
    movies.json      3,386,802
    cadex.json       284,933
    google-com.json  51,165
    tsconfig.json    6,792
.jsonl
    timezones.jsonl           273,235
    first-10000-primes.jsonl  58,982
.m4a
    2048hz Clicks.m4a  9,928
.mp4
    3x3.mp4  113,324
.png
    na-pop-density-map-2020-shrunk.png  330,005
.sh
    terminal-examples.sh       10,633
    browser-popup-examples.sh  845
    rebuild.sh                 839
    primes-up-to.sh            194
.toml
    Cargo.toml  211
.tsv
    country-info.tsv  13,881
.txt
    e-digits.txt       1,000,002
    pi-digits.txt      1,000,002
    demo-commands.txt  5,314
    podcast-feeds.txt  336
.wav
    beats.wav  144,046

# now reverse sort by total byte-weight for each such category
jf -q 'dot.fs.sort(-v).group(k.ext).sort(-v.sum())'
.json
    movies.json      3,386,802
    cadex.json       284,933
    google-com.json  51,165
    tsconfig.json    6,792
.gz
    words.txt.gz             1,086,426
    top-100k-domains.csv.gz  913,806
    movies.json.gz           743,003
    cadex.json.gz            15,556
.txt
    e-digits.txt       1,000,002
    pi-digits.txt      1,000,002
    demo-commands.txt  5,314
    podcast-feeds.txt  336
.html
    data-uris.html          800,155
    terminal-examples.html  174,922
    examples.html           132,726
    no-data.html            90,136
    cadex.html              34,052
    e-digits.html           19,325
.jsonl
    timezones.jsonl           273,235
    first-10000-primes.jsonl  58,982
.png
    na-pop-density-map-2020-shrunk.png  330,005
.wav
    beats.wav  144,046
.mp4
    3x3.mp4  113,324
.ansi
    terminal-examples.ansi  20,786
    e-digits.ansi           1,825
.tsv
    country-info.tsv  13,881
.sh
    terminal-examples.sh       10,633
    browser-popup-examples.sh  845
    rebuild.sh                 839
    primes-up-to.sh            194
.jf
    no-data-examples.jf  5,163
    cadex-example.jf     3,113
    e-digits-example.jf  1,898
    strcap.jf            408
.m4a
    2048hz Clicks.m4a  9,928
.toml
    Cargo.toml  211


# building out a pipeline starting from jeff
jf -n -to=lines '[`${v.nice0.rpad(12)}${k}`: dot.fs.sort(-v)]'
3,386,802   movies.json
1,086,426   words.txt.gz
1,000,002   e-digits.txt
1,000,002   pi-digits.txt
913,806     top-100k-domains.csv.gz
800,155     data-uris.html
743,003     movies.json.gz
330,005     na-pop-density-map-2020-shrunk.png
284,933     cadex.json
273,235     timezones.jsonl
174,922     terminal-examples.html
144,046     beats.wav
132,726     examples.html
113,324     3x3.mp4
90,136      no-data.html
58,982      first-10000-primes.jsonl
51,165      google-com.json
34,052      cadex.html
20,786      terminal-examples.ansi
19,325      e-digits.html
15,556      cadex.json.gz
13,881      country-info.tsv
10,633      terminal-examples.sh
9,928       2048hz Clicks.m4a
6,792       tsconfig.json
5,314       demo-commands.txt
5,163       no-data-examples.jf
3,113       cadex-example.jf
1,898       e-digits-example.jf
1,825       e-digits.ansi
845         browser-popup-examples.sh
839         rebuild.sh
408         strcap.jf
336         podcast-feeds.txt
211         Cargo.toml
194         primes-up-to.sh

# ecoli -ext colors lines by unique file extension; sbs means `side-by-side`
jf -n -to=lines '[`${v.nice0.rpad9}   ${k}`: dot.fs.sort(-v)]' | \
    ecoli -ext | sbs 2
3,386,802   movies.json                        █ 20,786      terminal-examples.ansi   
1,086,426   words.txt.gz                       █ 19,325      e-digits.html            
1,000,002   e-digits.txt                       █ 15,556      cadex.json.gz            
1,000,002   pi-digits.txt                      █ 13,881      country-info.tsv         
913,806     top-100k-domains.csv.gz            █ 10,633      terminal-examples.sh     
800,155     data-uris.html                     █ 9,928       2048hz Clicks.m4a        
743,003     movies.json.gz                     █ 6,792       tsconfig.json            
330,005     na-pop-density-map-2020-shrunk.png █ 5,314       demo-commands.txt        
284,933     cadex.json                         █ 5,163       no-data-examples.jf      
273,235     timezones.jsonl                    █ 3,113       cadex-example.jf         
174,922     terminal-examples.html             █ 1,898       e-digits-example.jf      
144,046     beats.wav                          █ 1,825       e-digits.ansi            
132,726     examples.html                      █ 845         browser-popup-examples.sh
113,324     3x3.mp4                            █ 839         rebuild.sh               
90,136      no-data.html                       █ 408         strcap.jf                
58,982      first-10000-primes.jsonl           █ 336         podcast-feeds.txt        
51,165      google-com.json                    █ 211         Cargo.toml               
34,052      cadex.html                         █ 194         primes-up-to.sh          

######################################################################

# calculate the first 100 fibonacci numbers: using bigint values allows using
# different limits without worries, since float64 starts giving wrong results
# at around 80 items; if float64s were used instead, this algorithm would be
# constant-space and linear-time
echo 100 | jf -to=a 'a = 1n; b = 0n; in.map(v.nth, t = b; b = a+b; a = t; b)'
1st    1n
2nd    1n
3rd    2n
4th    3n
5th    5n
6th    8n
7th    13n
8th    21n
9th    34n
10th   55n
11th   89n
12th   144n
13th   233n
14th   377n
15th   610n
16th   987n
17th   1,597n
18th   2,584n
19th   4,181n
20th   6,765n
21st   10,946n
22nd   17,711n
23rd   28,657n
24th   46,368n
25th   75,025n
26th   121,393n
27th   196,418n
28th   317,811n
29th   514,229n
30th   832,040n
31st   1,346,269n
32nd   2,178,309n
33rd   3,524,578n
34th   5,702,887n
35th   9,227,465n
36th   14,930,352n
37th   24,157,817n
38th   39,088,169n
39th   63,245,986n
40th   102,334,155n
41st   165,580,141n
42nd   267,914,296n
43rd   433,494,437n
44th   701,408,733n
45th   1,134,903,170n
46th   1,836,311,903n
47th   2,971,215,073n
48th   4,807,526,976n
49th   7,778,742,049n
50th   12,586,269,025n
51st   20,365,011,074n
52nd   32,951,280,099n
53rd   53,316,291,173n
54th   86,267,571,272n
55th   139,583,862,445n
56th   225,851,433,717n
57th   365,435,296,162n
58th   591,286,729,879n
59th   956,722,026,041n
60th   1,548,008,755,920n
61st   2,504,730,781,961n
62nd   4,052,739,537,881n
63rd   6,557,470,319,842n
64th   10,610,209,857,723n
65th   17,167,680,177,565n
66th   27,777,890,035,288n
67th   44,945,570,212,853n
68th   72,723,460,248,141n
69th   117,669,030,460,994n
70th   190,392,490,709,135n
71st   308,061,521,170,129n
72nd   498,454,011,879,264n
73rd   806,515,533,049,393n
74th   1,304,969,544,928,657n
75th   2,111,485,077,978,050n
76th   3,416,454,622,906,707n
77th   5,527,939,700,884,757n
78th   8,944,394,323,791,464n
79th   14,472,334,024,676,221n
80th   23,416,728,348,467,685n
81st   37,889,062,373,143,906n
82nd   61,305,790,721,611,591n
83rd   99,194,853,094,755,497n
84th   160,500,643,816,367,088n
85th   259,695,496,911,122,585n
86th   420,196,140,727,489,673n
87th   679,891,637,638,612,258n
88th   1,100,087,778,366,101,931n
89th   1,779,979,416,004,714,189n
90th   2,880,067,194,370,816,120n
91st   4,660,046,610,375,530,309n
92nd   7,540,113,804,746,346,429n
93rd   12,200,160,415,121,876,738n
94th   19,740,274,219,868,223,167n
95th   31,940,434,634,990,099,905n
96th   51,680,708,854,858,323,072n
97th   83,621,143,489,848,422,977n
98th   135,301,852,344,706,746,049n
99th   218,922,995,834,555,169,026n
100th  354,224,848,179,261,915,075n

# calculate prime numbers using the algorithm with O(n**1.5) time-complexity
echo 100 | jf -to=a 'in
    .filter(n => n != 1 && n.sqrt.all(div => div == 1 || n % div != 0))
    .map((k+1).nth, v)'
1st   2
2nd   3
3rd   5
4th   7
5th   11
6th   13
7th   17
8th   19
9th   23
10th  29
11th  31
12th  37
13th  41
14th  43
15th  47
16th  53
17th  59
18th  61
19th  67
20th  71
21st  73
22nd  79
23rd  83
24th  89
25th  97

# calculate prime numbers in streaming mode
seq 100 | jf -from=ev '
    (in != 1 && in.sqrt.all(div => div == 1 || in % div != 0)) ? in : skip' | nl
     1    2
     2    3
     3    5
     4    7
     5    11
     6    13
     7    17
     8    19
     9    23
    10    29
    11    31
    12    37
    13    41
    14    43
    15    47
    16    53
    17    59
    18    61
    19    67
    20    71
    21    73
    22    79
    23    83
    24    89
    25    97

######################################################################

# JS-like array/string join order
jf -q [dash,tile,fullblock]^space
– ■ █

# python-like string/array join order
jf -q space^[dash,tile,fullblock]
– ■ █

# operator ^ is exactly like function `join`
jf -q '[dash, tile, fullblock].join(space)'
– ■ █

# old-fashioned way of calling `join`
jf -q 'join([dash, tile, fullblock], space)'
– ■ █

# joining 2 arrays makes a dict, but that's a digression...
jf -q [upper[:3],dot,-3,slash]^[3,2,5.25,nil]
ABC  3
.    2
-3   5.25
/    null

# subtraction to remove all substring occurrences
jf -q [hex,digits,2*hex,2*hex-digits]
4 items
    0123456789abcdefABCDEF
    0123456789
    0123456789abcdefABCDEF0123456789abcdefABCDEF
    abcdefABCDEFabcdefABCDEF

# same thing, but easily guessable, if you don't know enough jeff
jf -q '[hex, digits, 2*hex, replaceall(2*hex, digits, "")]'
4 items
    0123456789abcdefABCDEF
    0123456789
    0123456789abcdefABCDEF0123456789abcdefABCDEF
    abcdefABCDEFabcdefABCDEF

# break a string into pieces
jf -q hex/3
3 items
    01234567
    89abcdef
    ABCDEF

# multiplying/repeating a string the python way
jf -to=l -n 80*dash
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# everything is always just functions
jf -to=l -n 'mul(80, dash)'
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# again, 80 dashes
jf -to=lines -n 80.dashes
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# again, in the end everything is always just functions
jf -to=lines -n 'dashes(80)'
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# you can always call any func like a pretend-method
jf -to=l -n '80.dashes()'
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# talk about typing your thoughts out
jf -to=l -n 2.slashes+space+77.dashes
// –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# if you're thinking in python, you might have come up with this instead
jf -to=l -n 2*slash+space+77*dash
// –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# floating-point math
jf -q [5.2,5.2**23,-75.abs/5,maxint]
4 items
    5.2
    29,381,698,884,548,508
    15
    9,007,199,254,740,992

# arbitrary-precision math
jf -q [5.2i,5.2i**23i,-75i.abs/5i,maxint.bigint]
4 items
    26 / 5
    350,257,144,982,200,575,261,531,309,080,576 / 11,920,928,955,078,125
    15n
    9,007,199,254,740,992n

# array conveniences (as a special case of automatic depth-first recursion)
jf -q [3.iota...,3.iota.log10...]
6 items
    1
    2
    3
    0
    0.3010299956639812
    0.4771212547196624

######################################################################

# function calls as you know them
jf -q 'keys(styles)'
12 items
    reset
    normal
    invert
    inverted
    red
    green
    blue
    orange
    pink
    magenta
    gray
    black

# you can always put the 1st arg before, method-style
jf -q 'styles.keys()'
12 items
    reset
    normal
    invert
    inverted
    red
    green
    blue
    orange
    pink
    magenta
    gray
    black

# dict `styles` has ANSI-codes as string values
jf -q styles.red+tile+styles.reset


# object indexing with indices: remember that `red` was styles' 3rd key
jf -q styles[2]+tile+styles.reset


# exclusive slicing, which mixes string-keys and indices: `magenta` is
# styles' 8th key
jf -q 'styles[`red`:7]@type'
red    string
green  string
blue   string

# object slicing with string-keys, all-inclusive
jf -q 'styles[`red`..`magenta`]@type'
red      string
green    string
blue     string
orange   string
pink     string
magenta  string

# normally .. creates numeric arrays, but when used for
# slicing containers it acts as an inclusive range
jf -q 3.5..8
5 items
    3.5
    4.5
    5.5
    6.5
    7.5

# normal .. works even backwards
jf -q 5..3
3 items
    5
    4
    3

jf -q 'styles[`red`..`magenta`] + tile + styles.reset'
red      
green    
blue     
orange   
pink     
magenta  

# until `blue`, included
jf -q 'styles[`red`..`blue`] + fullblock + styles.reset'
red    
green  
blue   

# until right before `blue`
jf -q 'styles[`red`:`blue`] + fullblock + styles.reset'
red    
green  

######################################################################

# number 1..20 in 5-item blocks
seq 20 | awk 'NR%5 == 1 { print "" }; 1'

1
2
3
4
5

6
7
8
9
10

11
12
13
14
15

16
17
18
19
20

# jeff can read text `blocks` as arrays of strings/lines
seq 20 | awk 'NR%5 == 1 { print "" }; 1' | jf -from=blocks
[
  [
    "1",
    "2",
    "3",
    "4",
    "5"
  ],
  [
    "6",
    "7",
    "8",
    "9",
    "10"
  ],
  [
    "11",
    "12",
    "13",
    "14",
    "15"
  ],
  [
    "16",
    "17",
    "18",
    "19",
    "20"
  ]
]

# label each such array into a dict/object
seq 20 | awk 'NR%5 == 1 { print "" }; 1' | \
    jf -to=ansi -from=bl '[`one,two,three,four,five`/comma ^ v@n: in]'
4 items
    one    1
    two    2
    three  3
    four   4
    five   5
    ········································
    one    6
    two    7
    three  8
    four   9
    five   10
    ········································
    one    11
    two    12
    three  13
    four   14
    five   15
    ········································
    one    16
    two    17
    three  18
    four   19
    five   20

# let's use NaN instead of null as the missing-value marker
seq 17 | awk 'NR%5 == 1 { print "" }; 1' | jf -from=bl  -to=ansi '
    // turn each string-array into an object
    [`one,two,three,four,five`/comma ^ v@n: in]
    // use nan as the default missing value, replacing null
    .revalue(v ?? nan)'
4 items
    one    1
    two    2
    three  3
    four   4
    five   5
    ········································
    one    6
    two    7
    three  8
    four   9
    five   10
    ········································
    one    11
    two    12
    three  13
    four   14
    five   15
    ········································
    one    16
    two    17
    three  NaN
    four   NaN
    five   NaN

######################################################################

# memory stats
cat /proc/meminfo
MemTotal:       16734040 kB
MemFree:        12913252 kB
HighTotal:             0 kB
HighFree:              0 kB
LowTotal:       16734040 kB
LowFree:        12913252 kB
SwapTotal:             0 kB
SwapFree:     11849323336 kB

# read input as unix-conf: /proc/meminfo not a real file on windows,
# so pipe it in using `cat`, which makes it work even on msys/windows
cat /proc/meminfo | jf -from=uc -a
MemTotal   16734040 kB
MemFree    12913212 kB
HighTotal  0 kB
HighFree   0 kB
LowTotal   16734040 kB
LowFree    12913212 kB
SwapTotal  0 kB
SwapFree   11848123524 kB

# all values are strings which could become numbers, if they weren't all
# ending in ` kB`: get rid of it, then
cat /proc/meminfo | jf -from=uc -a 'in - ` kB`'
MemTotal   16734040
MemFree    12913212
HighTotal  0
HighFree   0
LowTotal   16734040
LowFree    12913212
SwapTotal  0
SwapFree   11845926868

# same as before, but also pipe result, bottom-call func `n` to turn all
# strings into numbers, and finally reverse-sort by those same numbers
cat /proc/meminfo | jf -from=uc -a 'in - ` kB` ; _@n.sort(-v)'
SwapFree   11,843,682,616
MemTotal   16,734,040
LowTotal   16,734,040
MemFree    12,913,300
LowFree    12,913,300
HighTotal  0
HighFree   0
SwapTotal  0

# dividing 2 dictionaries
cat /proc/meminfo | jf -from=uc -a 'in - ` kB` ; _@n.sort(-v) / {gb:gb,kb:kb}'
SwapFree
    gb  11.028183881193399
    kb  11,563,888.94140625
MemTotal
    gb  0.0155847892165184
    kb  16,341.8359375
LowTotal
    gb  0.0155847892165184
    kb  16,341.8359375
MemFree
    gb  0.0120264180004597
    kb  12,610.61328125
LowFree
    gb  0.0120264180004597
    kb  12,610.61328125
HighTotal
    gb  0
    kb  0
HighFree
    gb  0
    kb  0
SwapTotal
    gb  0
    kb  0

# dividing 2 dictionaries, then transposing the result
cat /proc/meminfo | \
    jf -from=uc -a 'in - ` kB` ; _@n.sort(-v) / {gb:gb,kb:kb} ; _.tr()'
gb
    SwapFree   11.026044465601444
    MemTotal   0.0155847892165184
    LowTotal   0.0155847892165184
    MemFree    0.0120264291763306
    LowFree    0.0120264291763306
    HighTotal  0
    HighFree   0
    SwapTotal  0
kb
    SwapFree   11,561,645.6015625
    MemTotal   16,341.8359375
    LowTotal   16,341.8359375
    MemFree    12,610.625
    LowFree    12,610.625
    HighTotal  0
    HighFree   0
    SwapTotal  0

# streaming-mode filter & calculator
seq 20 | jf -from=el 'n = +in; (n % 2 == 0) ? skip : (n + tab + n**3.5)'
1    1
3    46.7653718043596882
5    279.5084971874737221
7    907.4926996951546698
9    2187.0000000000004547
11    4414.4275959630376747
13    7921.3961521943838306
15    13071.3187934500310803
17    20256.8179386595656979
19    29897.6878537454758771

# streaming-mode filter & calculator, with automatic JSON/number parsing
seq 20 | jf -from=ev '(in % 2 == 0) ? skip : (in + tab + in**3.5)'
1    1
3    46.7653718043596882
5    279.5084971874737221
7    907.4926996951546698
9    2187.0000000000004547
11    4414.4275959630376747
13    7921.3961521943838306
15    13071.3187934500310803
17    20256.8179386595656979
19    29897.6878537454758771

######################################################################

# input/output gzip (de)compression
jf -n -to=json.gz lower | jf -from=j.gz -to=ansi
abcdefghijklmnopqrstuvwxyz

# input bzip decompression
jf -n lower | bzip2 | jf -from=j.bz -to=ansi
abcdefghijklmnopqrstuvwxyz

# gzip decoding of generic bytes
echo hello there | gzip | jf -from=b.gz -to=b
hello there

# bzip decoding of generic bytes
echo hello there | bzip2 | jf -from=b.bz -to=b
hello there

# base64 encoding of generic bytes, limited to the first 50 output bytes
fh bmp x*y | jf -from=b -to=l in.datauri[:50]
data:image/x-bmp;base64,Qk02sHsBAAAAADYAAAAoAAAAAA

# do the same thing, but with PNG data read as generic bytes
fh 720p x*y | jf -from=b -to=l in.datauri[:50]
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAA

# fh x*y | jf -from=b -to=text in.datauri | si