ChanServ changed the topic of #zig to: zig programming language | ziglang.org | be excellent to each other | channel logs: https://irclog.whitequark.org/zig/
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
<andrewrk> MajorLag, how would comptime function call caching change that behavior?
<andrewrk> scientes, I think those 2 things are unrelated
<andrewrk> right now I test std by specifying a file directly and using --test-filter
<andrewrk> I consider it an open issue, that which tests to run is not intuitive
<MajorLag> andrewrk: maybe I blamed the wrong thing. All I know is that every def in the loop is treated as though it has the same is_pub as the first def encountered. There are other instances, I can't use an isSlice() fn because of #906.
<andrewrk> oh, that sounds like an easy fix in the @typeInfo implementation
<andrewrk> hm I don't see an obvious bug with is_pub
<MajorLag> I don't think it is specific to .is_pub
<MajorLag> in fact, if I remove the non-pub struct def something else weird happens. Is a `fn func(self: this) void` var_args? is that a property of `this`?
<MajorLag> no, even using actual typenames trips is_var_args, despite neither struct having any var_args functions.
mahmudov has joined #zig
<MajorLag> ..and now I'm crashing the compiler. I think I'll just wait until stage2 is ready to do fancy stuff with comptime.
kristate has joined #zig
<kristate> online 10:40am JST
<andrewrk> MajorLag, I don't blame you
<MajorLag> Ok, apparently TypeInfo.Definition.Data.FnDef just has empty arg_names?
<MajorLag> Grabbing the typeInfo of the Fn and using TypeInfo.Fn.args seems to work properly though...
<andrewrk> kristate, I have all tests passing in async-fs for darwin using only kqueue
<andrewrk> I'll push in a moment
<kristate> andrewrk: cool -- I can take that and push it into bsd
<andrewrk> probably FSEvents is in the future, but I'd like to put that off for now and get more progress on stage2
<MajorLag> ...not really. arg type comparisons still succeed or fail in inexplicable ways. Oh well. I'd better quit this now before I pull my hair out.
<kristate> andrewrk: well, the faster we can get async-fs into master, the better
<kristate> I want to work on networking
<andrewrk> right
<kristate> andrewrk: also, I don't like that we have so many public functions into the loop
<kristate> like bsdAddKev
<kristate> it should be one function for adding handlers, and then that function can support epoll or kqueue
<andrewrk> why not have that though?
<andrewrk> this is the "layered abstraction" concept
<andrewrk> or "multilayered". I haven't heard anyone name it before
<andrewrk> idea being that you expose multiple layers of abstraction
<andrewrk> and the API consumer should use the highest one if it makes sense, otherwise they should drop down a layer
<andrewrk> for example std.ArrayList exposing ensureCapacity
<kristate> so, for TCP and UDP, all they need is to add an FD to the loop
<kristate> they don't have any special flags and TCP and UDP is common on most platforms
<kristate> loop complexity should be inside loop.zig
<kristate> also, when we document loop.zig, we have a lot of domain knowledge, but others will struggle to figure out which function and which flags need to be used
<andrewrk> I don't think that users will be accessing methods of loop directly
<andrewrk> I think they will be using event.fs.* , event.tcp.*, event.Group, event.Lock, etc
<kristate> andrewrk: i guess it boils down to culture. we are all watching how you are structuring zig, if we have so many ways to access the loop, then it may be appropriate to do that on other APIs too
<andrewrk> I see it all as very disorganized right now
<andrewrk> nearly every API is in flux and some of the std lib is experimental
<kristate> andrewrk: likewise, I want to directly access the loop to process other FDs, like serial device drivers and tunnels
<andrewrk> I think it will become obvious the best way to structure once more is complete
<andrewrk> and once we have doc gen
<andrewrk> kristate, I agree with you that Loop should have a higher level posix API for adding a file descriptor
<kristate> andrewrk: well, it doesn't need to be posix, but it just has to be one interface
<kristate> I don't see the need for the complexity from the start -- i implemented such an interface
<andrewrk> let me have another look - what function are you referring to in particular?
<kristate> addEvHandle, removeEvHandle, waitEvHandle
<andrewrk> ahh
<kristate> flags are of type EventFlagType
<kristate> wanted to make that an enum, but couldn't get enums to work with binary ops
<andrewrk> how do you communicate EVFILT_VNODE?
<kristate> andrewrk: libuv solves that by telling the loop what type the FD/handle is
<andrewrk> enum isn't the right type for a bit field - it's e.g. packed struct {Read: bool, Write: bool, Except: bool, Reserved: u5}
<andrewrk> telling the loop what type the FD/handle is is kinda the same thing as having multiple functions depending on the system API
<andrewrk> here's the deal - if we need to abstract, let's abstract - but right now there isn't a callsite in zig std lib of where the abstraction would accomplish anything
<kristate> andrewrk: it is and it isnt :) having multiple functions requires a choice. for instance, the TCP code would have to guess/match what platform its on
<andrewrk> it very well may be in the future, so let's keep your idea in mind for if that happens
<andrewrk> I really do see what you are saying, and I think we may switch to your strategy in the future - but let's wait until we can actually take advantage of the API in practice
<andrewrk> for example your TCP/UDP implementation may require it
<andrewrk> if so, great, let's do it
<kristate> andrewrk: okay, lets regroup and get async-fs into master
<kristate> andrewrk: I know that you want to get stage2 going as fast as possible, and as long as you understand that we should be in that direction, I am fine
<andrewrk> looks like it's just windows now
<kristate> yeah
<kristate> windows seems to be ReadDirectoryChangesW
<andrewrk> looks like it will be closer to linux than darwin
<kristate> andrewrk: i am going to pull async-fs on my mac and test
<kristate> andrewrk: which version of macOS are you testing on?
<andrewrk> I noticed that in practice I get a delete event and then no further events, so one improvement will be to additionally watch the directory and detect when the file is re-created
<andrewrk> 10.13.5
<kristate> andrewrk: are you testing on real windows hardware or wine?
<andrewrk> real windows hardware. I have 3 laptops
<kristate> cool
<kristate> going to jump to tokyo university
<kristate> be back online in an hour or so
<kristate> once we get TCP and UDP going, we can start using it in my research lab for projects
<andrewrk> that will be a great milestone
kristate has quit [Ping timeout: 240 seconds]
kristate has joined #zig
<kristate> back online
\u is now known as meowray
kristate has quit [Remote host closed the connection]
kristate has joined #zig
qazo has quit [Quit: 345345]
qazo has joined #zig
zolk3ri has joined #zig
davr0s has joined #zig
qazo has quit [Quit: 345345]
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
kristate has quit [Remote host closed the connection]
kristate has joined #zig
kristate has quit [Ping timeout: 244 seconds]
noonien has joined #zig
mahmudov has quit [Ping timeout: 244 seconds]
bheads has joined #zig
SimonNa has joined #zig
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
bheads has quit [Ping timeout: 244 seconds]
bheads has joined #zig
mahmudov has joined #zig
Avinash has joined #zig
davr0s has joined #zig
Avinash has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<MajorLag> andrewrk: is there any way to get the active tag type of a union other than going through a switch?
<unique_id> good question, I would also like to know.
<andrewrk> MajorLag, yes if the union is tagged you can implicit cast it to its enum type
<andrewrk> example: @TagType(x)(x)
<unique_id> Does anyone know how to allocate a huge virtual array on Linux using mmap? From my notes from the last time I tried this, it seems overcommit stops me from doing it? So I need to make multiple contiguous allocations and to make that robust I guess I need to read from /proc/self/maps ?
<andrewrk> unique_id, how huge is huge? I think overcommit is actually the thing that lets you get away with it when you probably shouldn't
<unique_id> gigabytes, not that huge :)
<andrewrk> did you try already? it might just work
<unique_id> From my notes, if I trust my old self, allocating larger than ~4 GiB did not work
<MajorLag> andrewrk: thanks, I didn't think of that. I tried fancy comptime stuff, it didn't work out.
<andrewrk> note that mmap is memory allocation - the system very well might have overcommit off, in which case you are using x GiB memory by doing this
<andrewrk> MajorLag, yeah, apologies, that's one of the less obvious things about tagged unions
<andrewrk> oh my example is wrong. @TagType(@typeOf(x))(x)
bheads has quit [Ping timeout: 248 seconds]
<unique_id> andrewrk: I needed the MAP_NORESERVE flag. Otherwise mmap returns -1 for me when the 'length' is large. Why I do not exactly know, but probably because I don't have much swap space (I hate that stuff).
<unique_id> The linux documentation could be made clearer
<unique_id> and I'm not even writing to it, it's failing right away at mmap
<andrewrk> unique_id, but now when you write to a page it might cause OOM and there's no way to handle it
bheads has joined #zig
<bheads> freenod has become a PITA
<unique_id> andrewrk: that's a good point
<andrewrk> bheads, are you getting spammed? I figured out how to stop it
<bheads> andrewrk, I get disconnected once an hour
<bheads> then have to wait for my username to timeout so I can re identify
<andrewrk> there's a command to force it to timeout. it's something to do with "ghost" iirc
mahmudov has quit [Ping timeout: 264 seconds]
<andrewrk> how delightful! there is a zig stackoverflow tag now
<unique_id> nice!
<unique_id> andrewrk: Is there ever a way to handle OOM on Linux? I'm not sure what not reserving swap space means exactly but if it increases the chance of an issue then yeah that's not good. But I'm not going to use map_noreserve because getting killed by sigsegv instead of the oom killer makes the program look buggy
<unique_id> (apparently you'll get a segfault error when you run out of memory if you do map_noreserve)
<andrewrk> unique_id, yeah, if overcommit_vm is disabled in the kernel. rare but possible
<andrewrk> also, as you've observed, sometimes mmap returns an error which you can handle
<andrewrk> what's your use case for preallocating so much memory?
<bheads> please say your build a genomics library
<unique_id> I don't need that much, but I do want the option of having pointers to arrays that can grow.
<unique_id> hah no, I'm working on a game
<bheads> oh darn, I guess I am still going to have to write that myself :)
<unique_id> I just can't figure out the rules of this. I'm on a 16GiB/GB computer, with 2GiB/GB swap, and I can allocate 5GiB through mmap, no more. If I do 6GiB it fails. I need this to work for everyone.
<andrewrk> unique_id, why not follow the strategy of ArrayList and ArenaAllocator where they allocate a little more than necessary, and when they run out they ask for ~1.5x more
<andrewrk> it's amortized O(1)
<bheads> another option is a block allocator
<andrewrk> afaik that's what std.heap.ArenaAllocator is
<unique_id> andrewrk: That's the standard strategy. But in games you write all kinds of systems as I call them that manage their own memory in custom ways. Being able to call "virtual_alloc(billion objects)" could be useful for some system, temporary or as the final design
<bheads> I was thinking for the array itself, ie an array that points to large blocks. So array[5] is really in array.block[0].*[5]
<andrewrk> unique_id, allocating so much with mmap doesn't pre-reserve the memory, so it's not really accomplishing the goal
<bheads> for a game, dont count on the user having 6 gigs
<andrewrk> if you're trying to achieve deterministic timing you need to pre-reserve the memory
<andrewrk> unique_id, for game I suggest using mlockall() at the beginning of your app
<andrewrk> and then don't ask for more memory than you expect the user to have
<unique_id> andrewrk: The point is to not have the memory allocated. So you can have an array that grows without pointers to the data ever being invalidated
<bheads> putting all your game data in a huge array will result in bad cache performance
<andrewrk> but then at some point that you can't really control, writing to memory will be non-deterministic speed because it's not reserved
<andrewrk> you wouldn't want to use this memory while rendering the frame, for example
<andrewrk> you want to only touch pre-reserved memory in the frame
<andrewrk> mapped-but-not-reserved memory is a generally horrible idea
<bheads> also due to paging your data wont be linear
<unique_id> lol bheads
<MajorLag> unique_id, if I understand correctly, a pool allocator is more appropriate to what you're trying to accomplist. You keep pools of fixed size blocks and reuse them, adding new pools as needed to grow.
<MajorLag> It won't let you grow something like an arraylist without realloc, but it will let you go from 1000 particles to 5000 particles without invalidating any addresses.
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
<unique_id> those guys' previous engine was bought by autodesk
<unique_id> interestingly enough, they've moved from C++ to C
bheads has quit [Ping timeout: 244 seconds]
bheads has joined #zig
bheads has quit [Disconnected by services]
bheads has joined #zig
<unique_id> andrewrk: If you're saying I should cap the memory used and have that reserved so there's no system allocation calls for more memory after loading a level, then that would be ideal but it's not something that I want to do for an open world game that support modding. All systems will be able to grow to use as much memory as the game demands of it, but they'll do so in a cache efficient, specialized, and proper manner.
<andrewrk> unique_id, but don't you have something like a loading screen, and then your gameplay?
<unique_id> sure
<andrewrk> I'm just saying that once the loading screen is done, all the memory you will ever touch should be mlocked
<andrewrk> unless you're doing loading as a background task during gameplay
<andrewrk> which sounds like perhaps is the case in an open world game
<unique_id> yeah but it still might work. Mods can report how much memory they would like to use.
<andrewrk> I just think that accessing non-reserved memory should not be in the renderFrame() or computeNextFrame()
<unique_id> which is the equivalent of saying that the game should know how much memory it needs for the level?
<unique_id> and then have it reserved
<unique_id> The only issue is that people create mods to stress their system. They might spawn an endless of x and y. And that's a huge amount of fun. So I don't see the issue with asking the OS for more memory in emergency situations
<andrewrk> right - or if that is not the case, then you need the concept of "loading" during gameplay, which means that you need some kind of background loading job, and need to handle the case of it not finishing in time
noonien has quit [Quit: Connection closed for inactivity]
<andrewrk> hm, yes I see
<andrewrk> the user may spawn an endless amount of x and y in exchange for the possibility of frame skips
<unique_id> yes
<andrewrk> you could still model it as a "loading" task to spawn something, provided that there is no frame deadline for the item being spawned
<andrewrk> and then you'd have no frame skips, but the items might be spawned a few frames late
<unique_id> yeah that would work
<wink_> Q: There are two types of struct initializers I've created: pub fn init() Self { return Self { ...... }; } which is nice syntatically but doesn't work if I need to refer to the address of a field in Self because there is a copy. In that case I change the init to be pub fn init(pSelf: *Self) void {}. Which technique should I prefer, or maybe somethi
<wink_> ng else?
<andrewrk> wink_, https://github.com/ziglang/zig/issues/287 is intended to address this use case
<MajorLag> in the category of something else, you can perform a kind of copy eliding by forcing init to be inline. Give me a minute to recall the precise construction.
<MajorLag> oh right, the compiler actually tries to stop you from doing this and you have to work around it...
davr0s has joined #zig
<MajorLag> hmm... nevermind. I can't prove the behavior right now because it seems to be working even with @noInlineCall.
<wink_> From reading 287 it seems I should prefer "init() Self" style when possible, is that correct?
<andrewrk> wink_, yes
<MajorLag> This is one of those stupid tricks you should only ever do if you have to.
<MajorLag> In fact, even then you probably shouldn't.
<andrewrk> MajorLag, can't you just mark the init function inline?
<MajorLag> yes, but that meant that to test the behavior I'd have to add @noInlineCall and remove `inline`. This way I could swap back and forth more easily.
<MajorLag> In real life you'd mark the fn inline.
<MajorLag> If you used this in real life, which you probably shouldn't. It's just part of a series of Poking at the Compiler exercises.
<MajorLag> In that same series: `unreachable: C:\projects\zig-d3l86\src\analyze.cpp:hash_const_val:4762` if you try to use a BoundFn type as a parameter type to a function.
mahmudov has joined #zig
<andrewrk> BoundFn - the type that the compiler wants to pretend doesn't exist
<andrewrk> but we're going to have to admit it :)
mahmudov has quit [Ping timeout: 256 seconds]
<wink_> You guys lost me, should I use "inline fn" (which I've never done)? If I inline a "pub inline fn init() Self" can I take the address of a field as it won't do a "copy"?
mahmutov has joined #zig
<andrewrk> wink_, no, if you don't need struct fields to reference each other then use init() Self
<andrewrk> if you do, the recommended workaround until #287 is done is to use create()/destroy() and allocate the struct on the heap
<andrewrk> having fields point to each other is rare, it might be a code smell if you're doing it
<wink_> sg
<wink_> The particular case I've run into now is that I'm calling another init function within my own init function and want to pass the address of a field as a parameter, that doesn't seem terribly esoteric on the face of it, should I really not do that type of thing?
<andrewrk> var self = Self{...}; foo(&self.bar); return self;
<andrewrk> make sure that foo is not capturing a reference to bar
<wink_> So don't do what what you've shown (gtg to lunch, later)?
<andrewrk> mutating the data would be fine, but make sure it does not store a reference and use it later
<andrewrk> if you want it to be able to do that, then wait until #287 is done or use the heap workaround that I mentioned
schroffl has joined #zig
<MajorLag> andrewrk, I'm not seeing any relevant documentation: are there any bit ordering guarantees in packed structs? I would imagine it just matches native endianess, is that a correct assumption?
<andrewrk> MajorLag, that's correct
<andrewrk> right now it's convenient for representing memory mapped addresses for embedded/OS dev. there's a plan to better support the use case for mapping a packed struct to a specific endianness for e.g. a file format
<andrewrk> the current workaround for this use case is to have a little endian version and a big endian version and choose the correct one based on builtin.endian
<schroffl> Hey guys, is there any way to get information about a type/struct/etc. apart from the documentation or source-code?
<andrewrk> schroffl, you mean like reflection?
<schroffl> No, for example, I am trying to read from stdin right now, but I don't have any idea of the File struct (it's a struct, right? :p). And because the documentation is not fully complete I was wondering whether you could somehow get this information in some other way.
<schroffl> GHCi (Haskells repl) has the ":i <...>" which shows the instances of a type, where it's declared, etc.
<andrewrk> @compileLog(@typeOf(x))
<andrewrk> I have some ideas for a repl-ish thing like that in stage2
<schroffl> Thank you! Sounds like the thing I'm looking for :)
<MajorLag> andrewrk: I've already built tooling for reading and writing struct to disk with appropriate endianess, getting the bit pattern correct for bit-packed data should be doable as part of that and is on my short list which is why I asked. If @reify ends up going in then creating an appropriately bit-reversed struct would be a usecase for that though.
<schroffl> andrewrk Any ideas on how that might look like? I think something like "zig show <...>" would already be quite awesome
<andrewrk> schroffl, here's a 1 minute demo for context: https://www.youtube.com/watch?v=b_Pm29crq6Q
<andrewrk> you can see that the stage2 compiler stays running and rebuilding
<andrewrk> the idea is that it can also show a repl prompt there
<andrewrk> so you have your fully built code, and you can introspect it in any way that e.g. an IDE can
<MajorLag> Will it work at runtime, so you can call up a prompt on a breakpoint or panic and debug? because that'd be wicked.
<andrewrk> no, this is a comptime repl
<andrewrk> I might have a more interesting answer to your question when I look into hot code swapping
bheads has quit [Disconnected by services]
bheads has joined #zig
bheads has quit [Disconnected by services]
bheads has joined #zig
schroffl has quit [Remote host closed the connection]
schroffl has joined #zig
bheads has quit [Ping timeout: 248 seconds]
haolez has joined #zig
<haolez> I'm thinking of using zig in a small project that needs to access a postgres database. What would be the best option as of today in zig for that? Maybe interfacing with the official libpq C library from postgres itself
<andrewrk> using the official libpq C library would be the null hypothesis
<andrewrk> up to you if you want to write the code to speak the pg protocol directly
<andrewrk> haolez, with libpg you have 2 options - use @cImport in your code adn directly use the .h files, or do a `zig translate-c pg.h` offline and then clean up the bindings by hand and use that
<andrewrk> for example you might change some optional pointers into normal pointers so that you don't accidentally pass null
<haolez> Might try the translate alternative. libpq is ridiculously complicated. I will probably have to cherrypick what I need, which is very basic
<andrewrk> that's a very reasonable option
<haolez> Another option is to put something like postgrest in front of my database, which then can be accessed with HTTP methods, which I believe must be trivial in zig or any other language
<andrewrk> zig std lib does not yet have an http client
<andrewrk> so you're probably better off with libpg at this point
<haolez> hmm so I would still need to translate a c library, right?
<haolez> got it
<haolez> Ah! I was reading about zig yesterday and a doubt came up! Let me take this opportunity to clarify it: libpq uses Linux's "select" to implement async stuff. Will I be able to use something like that to wait for postgres events with hot loops? Thanks again
<andrewrk> haolez, it sounds like there would be a benefit to writing postgres client code in zig since it could integrate with zig's event loop
<andrewrk> to be clear, not zig's event loop, the event loop that zig's std lib provides
<MajorLag> andrewrk: any idea how it is possible for TypeInfo.Fn.args[i].arg_type to be null? Is it for empty varargs or something?
<andrewrk> haolez, however if libpg did their API correctly, then it can be integrated regardless
<andrewrk> MajorLag, for every arg after a comptime one
<haolez> andrewrk: cool! It might be a fun little project. I'm considering zig because this is a microservices architecture using docker and container orchestration, and it has become quite expensive! I would like to replace some of my bloated python containers with static binaries that are self-sufficient, and I was going to go with Go, but then I found Zig and it seems like a better fit :)
<andrewrk> MajorLag, @typeInfo on generic functions is not really well thought out
<andrewrk> I should type up an issue for that
<MajorLag> ah, ok. I wasn't sure why that would be the case, but "it isn't finished yet" makes sense.
<andrewrk> if anything the types of args would be a function and you'd have to pass in the types of the previous args and the values of previous comptime args, before you could find out the type
<andrewrk> because that's how it works
<andrewrk> haolez, your project is very related to what kristate and I am working on in the std lib right now
<andrewrk> I'm just finishing up cross-platform async I/O for file system read/write and directory watching
<MajorLag> builtin.TypeInfo.Fn.args should maybe be an iterator then?
<andrewrk> kristate is working on async I/O tcp/udp
<haolez> andrewrk: async stuff? My system is very "queue-oriented", if that's even a term :D and I would benefit from waiting on events without hot loops
<haolez> andrewrk: nice! you guys got a great pace here. I will try to get up to speed here. Will come back with more doubts for sure :)
<andrewrk> MajorLag, sorry I think my brain is at capacity right now, I think this is going to have to be a ticket that I can be thougthful about later
<MajorLag> right, sorry, throwing questions at you about unrelated stuff while you're being questioned about async
<haolez> my bad :D
<andrewrk> imagine that your postgres queries start with async, and finish with await
<haolez> async is hard to get right following zig's philosophy, but it actually looks like you guys are pulling it off
<haolez> thanks! will take a look
<andrewrk> if you had it integrated this way, your program would be doing M:N threading, optimally using cpu cores and I/O
<andrewrk> there are a couple of important problems to solve with coroutines but it looks like it's going to work
<andrewrk> the biggest problem is that c++ folks are barely getting around to using coroutines, so there are a bunch of bugs in LLVM
<andrewrk> (and until LLVM decides to rewrite in zig, we rely on people caring about c++ in order for LLVM to care about bugs)
<haolez> you will have coroutines, but not a standard allocator haha that's awesome! it's like learning forth all over again
<haolez> got it
return0e has quit [Read error: Connection reset by peer]
return0e has joined #zig
<MajorLag> `const TargetFnType = @typeOf(@field(Target, trait_def.name));`. That felt cool to write, and it actually worked. Neat.
schroffl has quit [Remote host closed the connection]
<MajorLag> `zig test trait.zig` =>`trait.zig:69:13: error: ByteStreamTrait trait unsatisfied.`. Seems I may have just been misunderstanding certain aspects of TypeInfo's layout before. This do-over is actually working pretty seamlessly so far.
<andrewrk> ooh "unsatisfied", that's a nice word
<MajorLag> Changed it when I made the error message more descriptive. `error: ByteStreamTrait trait not satisfied by TestByteStream`
<MajorLag> Though I could make it `error: TestByteStream has left ByteStreamTrait unsatisfied.`
<andrewrk> avoiding passive language: `error: TestByteStream does not satisfy ByteStreamTrait trait`
<andrewrk> idk, passive language is probably ok in compile errors
<MajorLag> I'll make a note for later cleanup. Also: `error: Only GenericType can follow GenericType in trait function args`. This is actually going quite smoothly now.
<MajorLag> typeInfo isn't as broken as I thought it was this morning. my understanding of it was just off. #906 is still an issue though.
<MajorLag> anyways, off to a thing.
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]
davr0s has joined #zig
\u has joined #zig
meowray has quit [*.net *.split]
andrewrk has quit [*.net *.split]
zolk3ri has quit [Quit: leaving]
davr0s has quit [Quit: My MacBook Pro has gone to sleep. ZZZzzz…]