This channel is intended for people just starting with the Raku Programming Language (raku.org). Logs are available at irclogs.raku.org/raku-beginner/live.html
Set by lizmat on 8 June 2022.
00:02 guifa joined
deoac Given the word `abcd` how would a construct the following nested list `[ (abcd) (a bcd) (ab cd) (abc d) (a b cd) (a bc d) (ab c d) (a b c d) ]` 00:09
That is splitting the word in every it can be, while keeping the letters in order. 00:10
I can do it with nested loops, but that's not very rakuish... 00:11
Nemokosch hmmm 00:12
m: my $str = 'abcd'; my @split-positions <== 0 ^..^ $str.elems andthen .combinations; dd @split-positions; 00:20
oof
not .elems, .chars... 00:21
m: my $str = 'abcd'; my @split-positions <== 0 ^..^ $str.chars andthen .combinations; dd @split-positions;
okay, this is a start
... and here I thought it's basically one step away but found no such step xD 00:53
now I'm thinking it might be better to just write a recursion for it 00:55
oh there is snip in v6.e 00:59
m: use v6.*; my $str = 'abcd'; my @split-positions <== 0 ^..^ $str.chars andthen .combinations; dd @split-positions; @split-positions.map({ $str.comb.snip($_)>>.join }).say; 01:03
uh... the build is too old
deoac: other than that, apparently it did work 01:07
it requires a sufficiently recent Rakudo
deoac Does the `snip` module provide the same functionality? 01:12
Nemokosch If the author is lizmat then quite sure 😄
deoac Either way, I'm going to enjoy figuring out the magic in you solution!
Yep, lizmat!
Nemokosch nice. I think it's like a polyfill. 01:13
01:16 rf joined
Anyways, I'm gonna propose a snip counterpart for strings, the same way there is contains or index or flip 01:20
01:33 deoac left 02:53 jgaz left
:(*@args, *%kwargs) m: say 'abc'.chars 03:37
m: say 'abc'.length
03:44 rf left 05:17 jaguart left 06:12 jaguart joined 06:19 Heptite left 09:05 ab5tract joined 09:14 dakkar joined
m: [1, 2, 3].length 09:37
Nemokosch neither is length 09:39
this was kind of a conscious design decision
to avoid common terms and mixing a string with a list 09:40
m: [1, 2, 3].chars.say #clearly about string representation 09:41
m: [1, 2, 3].elems.say # clearly about list representation 09:42
m: [1, 2, 3].Int.say # funnily, listy stuff can turn into an integer using its size 09:43
consequently:
m: say 'They are "equal" (as numbers!)' if [1, 2, 3] == <foo bar baz>; 09:44
:(*@args, *%kwargs) aren't strings and lists both indexable sequences 10:03
so they should have common interface 10:04
Nemokosch no, they aren't 10:06
that's the thing 10:07
:(*@args, *%kwargs) :cameliathink:
Nemokosch strings aren't indexable sequences
not any more than a number or yeah, anything would be 10:09
10:09 ab5tract left
m: my $random-scalar = 'foo'; say $random-scalar[0]; $random-scalar = 12458; say $random-scalar[0]; 10:11
everything can be taken as a 1-element list (sadly) 10:12
:(*@args, *%kwargs) why can't they be indexed 😭 raku is doing its best to separate very similar types as much as possible 10:32
Nemokosch I wish we stopped looking at strings as "very similar types" to lists 10:34
like, lists of what?
C answered question by saying "lists (arrays, actually) of bytes" and ended up with something that no sane person should call a "string" anymore 10:35
:(*@args, *%kwargs) lists of size 1 strings or characters
Nemokosch what is a "character"?
what is size 1?
I'm not even joking
:(*@args, *%kwargs) a unicode code point
weak typing 😭 10:36
Nemokosch a unicode code point may represent a modifier
so 👨‍👧‍👦 might be 2 or 3 characters by that term 10:37
I opened up a Python shell and copied it
it immediately looked like 3 graphemes
and reported a size of 5 10:38
:family_mgb:
oops
👨‍👧‍👦
the terminal can't fit it into one character for me but Raku at least says that this is "one character" 10:40
because in Raku a character is a grapheme and that's that
but that might not be the only representation unit that you care about - as illustrated by yourself
:(*@args, *%kwargs) ok lists of graphemes
Nemokosch if you want to get characters, you get characters 10:41
if you want to get codepoints, you get codepoints
I don't know why those who thought this was a good (or even okay) idea but they did... 10:42
even something horribly missing can turn into a 1-element list at some point
lizmat m: my $a = $*FOO; dd PROCESS::<$FOO> 10:50
camelia Failure.new(exception => X::Dynamic::NotFound.new(name => "\$*FOO"), backtrace => Backtrace.new)
lizmat m: my $a = $*FOO; dd PROCESS::<$FOO>:exists
camelia Bool::True
:(*@args, *%kwargs) another thing is that lists and maps have different indexing operators why? they have different lookup algorithms? they both have O(1) lookup and that is all that matters to users 10:52
lizmat oops, wrong channel :-) 10:53
Nahita yes they have different lookup algorithms, one is pointer arithmetic other depends on hash computations 10:56
also lists are always indexed with a numeric value, hashes, well, anything hashable 10:57
"different things should look different"
lizmat more importantly, the different postcircumfixes are a signal to the human reader on their functionality
Nahita or something like that was the quote
:(*@args, *%kwargs) aren't @ and % enough to tell them they are different anyways 11:03
lizmat yes, you can. But everything in Raku is an object, so an Array and a Hash are as well 11:08
and you *can* put them into a scalar, and then the $ wouldn't tell you much, would it ?
Nemokosch technically, I think the same thing could support both lookups 11:20
Skarsnik It's actually bother me to not have {} for hash when I work with other language, because most of the time hash are not in the base language 11:37
:(*@args, *%kwargs) most modern languages should have built in maps/hashes? 11:57
or is that only a thing with scripting languages? 11:58
m: my %h = :foo('bar'); say %h{'foo'}; say %h['foo']; 12:03
me when the cleanest pair syntax is the php fat arrow 😠 12:26
lakmatiol outside of C, what language doesn't ship with hashmap? 12:30
Skarsnik C++ 12:35
I mean in the language, not in the standard library
Nemokosch C++ is also a highly hackable language, you may as well consider the standard library a part of it 12:43
Skarsnik I never work with the stl on my C++ projects, since outside containers you are mostly using C stdlib x) 12:48
lakmatiol stl is part of C++ last I checked 12:49
Nemokosch this, to be honest 12:55
colon pairs can be nice as named arguments tho
Skarsnik => is from Perl I think, not Php, but yes it's the nicer syntax 12:57
Nemokosch PHP itself started off like 12:58
"let's make this Perl but absolutely not for programmers"
Perl 4.5 🤪 12:59
by now, however, it's plain to see which language could resurrect itself 13:00
Skarsnik It's sad for Perl 5 that the beginners doing Perl-cgi web page give it a bad reputation x) 13:01
Nemokosch true and the schism didn't help either, when we rebuilding should have started 13:03
anyway, I have to say it's bizarre how there are still people who think they managed to protect Perl from Perl6 somehow and that the former survived while the latter died 13:04
that "protection" is essentially the reason Perl turned into a zombie language that proves to be unable to innovate over and over again
the only excuse I can think of is that people for some reason still use POSIX shell (mostly Bash) which is set to be always far worse than Perl 13:08
I dream of a world where Perl is the language used for shell stuff, casually mocked as weird, and /bin/sh derivatives are no more. 13:09
13:10 jgaz joined
:(*@args, *%kwargs) php is simplified perl with bad and inconsistent function naming 13:11
and \ for namespace resolution (don't you already have ::?) 13:12
Nemokosch idk if PHP has ::, read up on it a couple of years ago but never really used it 13:13
anyway, PHP of these days looks like a modern language while even the most moder Perl barely avoids looking like an esoteric hybrid of C and (S)hell 13:15
modern
:(*@args, *%kwargs) php at least managed to not get abused to write unreadble one-liners 😆 13:20
Nemokosch APL wants to have a word about this 13:22
anyway I wanted to show you something that containers casually allow in Raku 13:23
first
m: (1..6).roll(10).say
this makes sense, right? 10 times rolled a die with values from 1 to 6 13:24
now I'm gonna batch it up each 3 13:25
m: (1..6).roll(10).batch(3).say
if you have containers, the values can be bound to the same containers in the two examples, meaning that you can directly mutate the same value, both as a flat array and a batched array 13:26
m: my @arr = (1..6).roll(10); dd @arr; @arr[4] = 'haha'; dd @arr; @arr.batch(3)[1;1] = 'hihi'; dd @arr; 13:27
this also (correctly) implies that indexing is not "magic" in Raku, it is just one of the functions that can return a container 13:29
:(*@args, *%kwargs) arrays are lists of containers 🤔 13:30
Nemokosch indeed 13:31
:(*@args, *%kwargs) so that works
Nemokosch Scalar containers in particular 13:33
but anyway Scalars are the most universally understood containers in Raku :DD
:(*@args, *%kwargs) do you have a list of raku magic methods 13:37
Nemokosch what do you mean? 13:39
:(*@args, *%kwargs) methods that alter object's behavior 13:40
smth like BUILD or CALL-ME 13:41
or gist 13:42
Nemokosch m: say Any.^methods>>.gist.grep({ $_ eq .uc }) 13:43
okay, this is not all of them
also the ones with underscores are typically "implementation details" aka you shouldn't rely on them, they are only exposed for internal purposes 13:44
ACCEPTS is important
with lowercase, raku is even more important than gist 13:45
for introspection, VAR, WHAT, HOW, WHICH, and WHO are pretty essential
HOW in particular is the entry point of the metamodel, one could say 13:46
when I did Any.^methods, I basically run the call on the HOW of Any 13:47
:(*@args, *%kwargs) why are FLATTENABLE_* in snake case while others are lisp case
Nemokosch ^ 13:48
:(*@args, *%kwargs) ah
Nemokosch I don't know if this is a formal rule but it's a tendency I noticed
:(*@args, *%kwargs) should i use snake case or lisp case for raku programs
seems like lisp case is more consistent with stdlib 13:49
Nemokosch yes, that's the mainstream
:(*@args, *%kwargs) > Raku intentionally confuses items and single-element lists 13:50
Nemokosch do you know TIMTOWTDI BSCINABTE? 13:51
yes, seen this before but I'm yet to understand the benefit of this
perhaps it could even be argued that this is a relic of old, flat lists
:(*@args, *%kwargs) consistent is good 13:52
Nemokosch yes xD
in short
I'd say this applies to names 13:53
:(*@args, *%kwargs) why are raku docs' lists so terrible docs.raku.org/routine-method.html 13:54
Skarsnik be careful with .^ or HOW, sometime thing at compile time does not have complete information x)
Nemokosch I didn't even know this existed
imo that's only really a problem if you want to build Rakudo itself 😛 13:55
in that case sure, it's always touchy to know what is already available and what isn't...
:(*@args, *%kwargs) oh nvm ik how to read it it is sorted alphabetically but still 13:56
Skarsnik This give me some issue when writing Nativecall function signature check x)
Nemokosch okay but NativeCall itself is a deep sea 13:57
@:(*@args, *%kwargs) what would you like to see? 13:58
feedback is always useful in the constant struggle for a better documentation 13:59
:(*@args, *%kwargs) oh nah its ok-ish to me i just didn't know how to use it 14:01
Nemokosch well, before you get too used to it 14:02
new-raku.finanalyst.org/routines.html
we miiight finally move to something like this
:(*@args, *%kwargs) originally going to say "add search feature" but there is already one at the top
Skarsnik Searching Str is confusing on this page x) Should it reach the Str class directly (or at the first result) 14:04
Str Synthesised documentation from type/Version type/Sequence type/StrDistance type/DateTime type/Real type/ForeignCode type/Code type/Pair type/IO/CatHandle type/Junction type/IO/Special type/Allomorph type/Mu type/Backtrace type/Label type/IO/Path type/Blob type/Systemic type/Num type/Match type/Thread type/List type/Date type/IO/Handle type/Nil 14:05
Nemokosch github.com/Raku/doc-website/issues please report things like this here 14:06
it would be great to show some interest 😅 14:07
new-raku.finanalyst.org/search.html is better but also less convenient 14:10
:(*@args, *%kwargs) m: switch ' ' -> $c { case ' ': say '<space>'; break; default: say $c; }
no switch
Nemokosch oh don't worry about that
Skarsnik I think you are searching for given/when
Nemokosch ^^
there is something that is even overkill for switch-case 😄 14:11
Skarsnik If I remember correctly
Nemokosch given binds the topic to the value you specify
and when is evaluated based on smartmatch 14:12
also, no break - the default behavior is the equivalent, I think succeed 14:13
(if you want fall-through, I think proceed would do that for you)
:(*@args, *%kwargs) m: sub dispatch($c) { my %dispatches = { ' ' => '<space>'; "\n" => '<newline>'; }; %dispatch.EXISTS-KEY($c) ?? %dispatch{$c} !! $c; } say dispatch(' '); 14:14
m: sub dispatch($c) { my %dispatches = { ' ' => '<space>'; "\n" => '<newline>'; }; %dispatches.EXISTS-KEY($c) ?? %dispatches{$c} !! $c; } say dispatch(' '); 14:15
Skarsnik haha I love the random 0; at github.com/Skarsnik/perl6-gumbo/bl...er.pm6#L72 to avoid a 6.c bug xD
Nemokosch there is absolutely no break from what I know - in when, it's succeed (and the default), in loops, there is last
with the continue-ish counterparts of proceed and next, respectively 14:16
Nahita use :exists not EXISTS-KEY
Nemokosch that's not the problem, though, but the use of semicolons
m: sub dispatch($c) { my %dispatches = { ' ' => '<space>', "\n" => '<newline>' }; %dispatches.EXISTS-KEY($c) ?? %dispatches{$c} !! $c; } say dispatch(' ');
oh yeah, the curly braces themselves are rather just noise in this case 14:17
:(*@args, *%kwargs) noob error 😅
Nemokosch m: sub dispatch($c) { my %dispatches = ' ' => '<space>', "\n" => '<newline>'; %dispatches.EXISTS-KEY($c) ?? %dispatches{$c} !! $c; } say dispatch(' ');
the feedback (namely that it parsed as a Block) was definitely less than awesome though 14:18
I think there could be at least a warning to this
when the lhs is a %var and the rhs is a Block for some reason
by the way 14:19
@:(*@args, *%kwargs) do you know that assignment itself is magic?
it's a call to the STORE method
therefore I think it would be easy to chase it down and add a warning or something 14:20
:(*@args, *%kwargs) m: class Foo { method STORE { say 'hi'; } } my $foo = Foo.new; 14:21
Nemokosch mm, not like this. the Scalar has its STORE executed, in this case
I wonder, though 14:22
m: class Foo { method STORE { say 'hi'; } } my $foo := Foo.new; $foo = 'haha';
oopsie
there is Proxy if you really want to do something like this 14:23
docs.raku.org/type/Proxy
:(*@args, *%kwargs) there is no method to overload + in raku hmm 14:25
Nemokosch you think so? 😼 14:26
:(*@args, *%kwargs) wait its a multi
Nemokosch disclaimer: it's not very Raku-ish to overload + for something that isn't essentially a number
:(*@args, *%kwargs) which means i can
Nemokosch the cool folks would just invent new operators
for new data types
having said that, + does have some overloads for not-quite-numeric stuff 14:27
the important thing here is that = is not a usual operator while + is, it's really just &infix:<+> 14:28
sorry for flooding you but... do you know the Perl&Raku weekly challenges? 14:29
:(*@args, *%kwargs) no
Nemokosch theweeklychallenge.org/challenges/ 14:33
usually rather small tasks, sometimes even just a couple of lines of Raku code
and you can check others' solutions as well
I also try to do them most of the time 14:34
but for example there is Bruce Gray/Util who just got crowned champion for november, definitely a very nice author, his talks inspired me a lot to start with the language 14:35
:(*@args, *%kwargs) m: say(for (1, 2, 3, 4) -> $x { $x }); 14:44
m: say($_ * 2 for (1, 2, 3, 4)); 14:46
Nemokosch it might need extra parens? 14:47
:(*@args, *%kwargs) m: say ($_ * 2 for (1, 2, 3, 4));
m: say (for (1, 2, 3, 4) -> $x { $x }); 14:48
raku is whitespace-significant 14:49
Nemokosch absolutely
say (for (1, 2, 3, 4) -> $x { $x }); is the same as say((for (1, 2, 3, 4) -> $x { $x }));
:(*@args, *%kwargs) m: my @range = 0...10; my @doubled-odds = (for @range -> $i { if $i % 2 == 1 { $i * 2 } }); say @doubled-odds; 14:53
m: my @range = 0...10; my @doubled-odds = (for @range -> $i { $i * 2 if $i % 2 == 1 }); say @doubled-odds; 14:54
Nemokosch there is also %% as the "evenly divisible" operator 14:55
:(*@args, *%kwargs) somehow implicit variable still exists in raku lol 14:58
Nemokosch what do you mean "still"?
:(*@args, *%kwargs) it is from perl and stayed in raku
Nemokosch yep
there is also $/
15:01 rf joined
:(*@args, *%kwargs) ill try to avoid it 😈 15:06
Nahita :\ 15:07
Nemokosch why
:(*@args, *%kwargs) because explicit is better than implicit 15:09
Nemokosch this is not P*thon 😄 15:10
BY THE WAY
weren't you the one who wanted implicit variable declaration for everything?
:(*@args, *%kwargs) implicit declaration not variable 15:11
but whatever fair
Nemokosch well, that is a Pythonism that doesn't follow "the zen of Python" 😛 15:12
:(*@args, *%kwargs) ppl don't complain about it somehow 15:14
maybe i stop complaining about $_? 15:15
Nemokosch I don't know. I think it's really good when used in short contexts 15:16
stevied ok, I dropped the module for updating legacy extensions: raku.land/zef:sdondley/Distributio...er?v=0.0.2 15:17
docs are a little sloppy at the moment; patching them up 15:19
:(*@args, *%kwargs) yeah, use $_ when the alternative is more verbose 15:20
Nemokosch say, you have something like foo.bar.baz ** foo.bar.baz 15:22
perhaps it's better to write something like
$_ ** $_ given foo.bar.baz
or
foo.bar.baz andthen $_ ** $_ 15:23
or
foo.bar.baz.&{ $_ ** $_}
:(*@args, *%kwargs) IIFE 😎 (sub ($x) { $x ** $x })(foo.bar.baz) 15:30
Nemokosch 😄 15:32
perhaps even a pointy block would do
( -> $x { $x ** $x } )(foo.bar.baz)
:(*@args, *%kwargs) {$_ ** $_}(foo.bar.baz) 15:33
Nemokosch aaand we are back to $_ 15:34
:(*@args, *%kwargs) m: sub f { @_ } say f(1, 2, 3, 4); 15:35
@_ is not gone 15:36
Nemokosch I wonder how much this is even intentional
but honestly, who ever writes subroutines without any signature
:(*@args, *%kwargs) m: sub f { {|%(@_.pairs), |%_} } say f(1, 2, 3, 4, foo => 'bar'); 15:37
how
m: sub f(*@_, *%_) { {|%(@_.pairs), |%_} } say f(1, 2, 3, 4, foo => 'bar'); 15:38
rf m: sub f(*@_, *%_) { {|%(@_.pairs), |%_} } say f(1, 2, 3, 4, foo => 'bar'); 15:41
camelia ===SORRY!=== Error while compiling <tmp>
Strange text after block (missing semicolon or comma?)
at <tmp>:1
------> ub f(*@_, *%_) { {|%(@_.pairs), |%_} }⏏ say f(1, 2, 3, 4, foo => 'bar');
expecting any of:
infix…
rf m: sub f(*@_, *%_) { {|%(@_.pairs), |%_} } ; say f(1, 2, 3, 4, foo => 'bar');
camelia (0 => 1 3 => 4 1 => 2 2 => 3 foo => bar)
:(*@args, *%kwargs) why does it give a list instead of a hash 15:54
m: sub f(*@_, *%_) { %(|%(@_.pairs), |%_) } say f(1, 2, 3, 4, foo => 'bar'); 15:55
Nemokosch hm, are you sure the braces didn't get parsed as block delimiters?
:(*@args, *%kwargs) it has 2 slips how can it be a block 15:56
Nemokosch not sure if that would hold it back 15:57
:(*@args, *%kwargs) slips (unpacks) can only exist inside containers
Nemokosch no 15:58
they will flatten out IF they are in one
but they can solidify as a list if they aren't
they are Lists, after all 15:59
anyway, I can't say if what you witness is a bug or not 16:00
but I strongly suspect it got interpreted as a block
:(*@args, *%kwargs) til docs.raku.org/type/Slip 16:04
i thought python slices are stupid but here we have a type of list just for unpacking
16:08 jgaz left
Nemokosch does python even have slices? 16:21
:(*@args, *%kwargs) docs.python.org/3/library/functions.html#slice 16:22
16:22 Heptite joined
lakmatiol pretty sure this is documented here docs.raku.org/type/Hash Please see the section on hash literals for different ways to declare a hash. Additionally, they can be declared using curly braces as long as these rules are followed: Empty curly braces will always declare an empty hash. A reference to $_ (even implicit) will instead declare a block. A Pair or variable with % as the first element 16:23
will declare a hash.
:(*@args, *%kwargs) the apparently stupid thing here is that instead of slicing right away python create a slice object and let the list (or whatever indexable type) itself do the actual work so lst[:3] becomes lst[slice(None, 3, None)] 16:25
lakmatiol yeah, that's a python 3 change
:(*@args, *%kwargs) but some objects implement custom behavior with slices so it might as well be deliberate
lakmatiol it also allows numpy to do things like arr[20:25,20:25] for multi-axis slices 16:26
which passes a tuple of slices to __getitem__
:(*@args, *%kwargs) i haven't yet found a use of slips as objects tho 16:28
lakmatiol you can use it map 16:29
which is occasionally useful
but ye, a lot of raku is very situational
:(*@args, *%kwargs) m: my $s = |(4, 5, 6); my @a = (1, 2, 3, $s, 7); say @a;
lakmatiol like the (1, 1, * + * ... *) syntax. Sure, it's a fancy way to do fibonacci numbers, but outside of that, its usage is fairly nebulous. 16:30
Nemokosch interesting, I never knew about that slice 16:31
What I really like about this, though, is that it's easy to remember 16:32
and the sequence generator in general is pretty useful in my opinion
okay but there was no $_, and @_ didn't seem to play a similar role, if we look at that expression 16:35
so this wouldn't convince me per se that the behavior is right 16:36
m: sub f(*@args, *%kwargs) { { |@args.pairs, |%kwargs } } say f(1, 2, 3, 4, foo => 'bar'); 16:37
now this really doesn't seem to contain any $_ in any sense...
lakmatiol yeah, that one may be a bug.
Nemokosch In my opinion, many of these things boil down to the one-pass parsing applied to a seriously complex language 16:38
and I suspect the only big reason for the one-pass parsing is the overall slowness of grammar parsing 16:39
the built-in grammars are absolutely capable of more nuanced parsing
BUT that would involve backtracking
:(*@args, *%kwargs) backtracking slow? 16:40
all this make me not trust hash literals lol 16:44
gonna use %()
m: say( %(a => 1, b => 2) eqv {a => 1, b => 2} ); 16:47
- not a type - is capitalized
Nemokosch like in Python? 😛 16:49
:(*@args, *%kwargs) i don't like that in python either 16:50
Nemokosch idk I don't feel strongly about it
there is also NaN I think
or Inf
:(*@args, *%kwargs) anyways 16:51
lakmatiol seems like in order to get a hash from {}, you need to have a Pair be the first element
which makes sense
but this check happens before Slip gets unpacked
> { :3rd, (:1st, :2nd ).Slip } {nd => 2, rd => 3, st => 1} > { (:1st, :2nd ).Slip, :3rd } (st => 1 nd => 2 rd => 3) 16:52
> sub maybe-pair { :2nd } &maybe-pair > { maybe-pair, :1st } (nd => 2 st => 1) 16:53
cursed
:(*@args, *%kwargs) anything other than that and its not guaranteed 16:54
and gets unpredictable
lakmatiol yeah
it is in the end a literal syntax
so IG it makes sense it behaves oddly once you start feeding it non-literals
Nemokosch tbh there is too much syntax for too few characters 😆 16:55
lakmatiol yeah
Nemokosch the language should just go the APL way haha 16:56
lakmatiol this should've been some unicode brace pair
17:37 dakkar left
stevied cam anyone clue me in on what's wrong here: github.com/sdondley/Distribution-E...6882661024 17:42
Nemokosch I have seen this before but I'm not sure I could figure it out 17:47
could this already be a "too long path"?
stevied not sure what that is? 17:48
i just reran the test, same settings, and it worked. the definition of insanity has been refuted 17:49
passed: github.com/sdondley/Distribution-E...6882785846
19:47 n1to joined 20:35 jgaz joined
rf Nice module @stevied! 21:45
stevied Thanks! It’s still a little rough around the edges in a couple of places but will polish it up some later this week. 22:28
22:36 jgaz left 23:53 n1to left