K-ballo changed the topic of #ste||ar to: STE||AR: Systems Technology, Emergent Parallelism, and Algorithm Research | stellar.cct.lsu.edu | HPX: A cure for performance impaired parallel applications | github.com/STEllAR-GROUP/hpx | Buildbot: http://rostam.cct.lsu.edu/ | Log: http://irclog.cct.lsu.edu/
<srinivasyadav227> and datapar works only if Vc library is present?
<hkaiser> srinivasyadav227: hey
<srinivasyadav227> yes,
<hkaiser> yes, we built things around Vc at that time, but any newer library should be easily adapted as the Vc specific are encapsulated in a couple of traits
<srinivasyadav227> you mean like in datapar/detail/?
<hkaiser> hold on, need to look
<srinivasyadav227> ok
<srinivasyadav227> here libs/parallelism/execution/include/hpx/execution/traits/detail/vc/ ?
<hkaiser> srinivasyadav227: yes, that's what I was looking for
<hkaiser> it should work if you create those four traits for any other library
<hkaiser> for instance for the std::experimental::simd types available in the gcc std library
<hkaiser> srinivasyadav227: to answer your other question: yes, the use of the simd types requires the use of the datapar policy
<srinivasyadav227> hkaiser: currently datapar supports only for couple of algorithms right (for_each, count, ...), so how do they interact or use datapar internally?..only through execution policy right?..and what if that a particular algorithm does not support datapar, say copy , it silently uses hpx::execution::seq?
<srinivasyadav227> <hkaiser "I'd rather simplify the normal a"> this was long back, but since then I have been trying to find something related to datapar and understand, could you please elaborate this?.. here by "normal algorithms" you mean these libs/parallelism/algorithms/include/hpx/parallel/algorithms right? or you were referring to something else?.. because in this, I could not find anything related to datapar or am I missing
<srinivasyadav227> something? ;)
<hkaiser> yes, by normal I meant the ones in hpx/parallel/algorithms
<hkaiser> and yes, we have only a few datapar enabled algorithms, I don't even know what would happen if the policy was used with another algorithm ;-)
<srinivasyadav227> omg, haha, this is scary, ;)
<hkaiser> srinivasyadav227: it was an experiment...
<srinivasyadav227> yea I get it! ;)
<srinivasyadav227> does this mean that changes for for_each algo related to datapar are only available in older commit?.. or could you please direct me to changes for for_each related to datapar?, I did not understand from where to separate them using tag_invoke
<hkaiser> this is the overload for the datapar policy
<hkaiser> srinivasyadav227: you might want to use a debugger to step through the code to see what's happening
<srinivasyadav227> inorder to use those I need to install Vc right?.. so I should build hpx again?
<hkaiser> srinivasyadav227: yah
<srinivasyadav227> I still have have build files of hpx, or else I can re-install by passing any kind of flag
<hkaiser> you will need vc v1.4, might be an older version
<hkaiser> you just need the cmake flag HPX_WITH_DATAPAR=On or the compiler flag -DHPX_HAVE_DATAPAR
<srinivasyadav227> oh ok, I will do it
<srinivasyadav227> the newer versions of Vc are not compatible?
<hkaiser> you might need to rebuild to enable finding the vc headers
<hkaiser> not sure what the state of vc is nowadays, back then it was V1.4, iirc
<srinivasyadav227> oh ok,, I will rebuild again
<srinivasyadav227> ok, I will try with v1.4 first, ;)
hkaiser has quit [Quit: bye]
jehelset has joined #ste||ar
<gonidelis[m]> k-ballo: here, on the "Possible Implementation" it calls `last2 = ranges::next(first, last)`
<gonidelis[m]> but, what if I passed a sentinel value
<gonidelis[m]> instead of a "distance"?
<gonidelis[m]> (that's more of a general sentinels question I must admit)
<k-ballo[m]> then you have to get to the end iterator manually?
<gonidelis[m]> but how does the code know that?
<gonidelis[m]> how does the code know that this sentinel<int>{5} is saying, reverse the thing from start until 5. it could may as well be reverse the thing from start until start+5
<gonidelis[m]> no?
<gonidelis[m]> k-ballo: ^^
jehelset has quit [Remote host closed the connection]
K-ballo has joined #ste||ar
<K-ballo> the end iterator is that which is equal to the sentinel
<K-ballo> you need to get your hands on the end iterator, as efficiently as possible
<K-ballo> worst case scenario, you just keep incrementing from first until the iterator equals last
<K-ballo> that's what ranges::next does
<gonidelis[m]> K-ballo: isn't it ambiquous?
<K-ballo> no
<gonidelis[m]> so again, it's like saying start incrementing until you either find a 5 or you have been incremented 5 times
<gonidelis[m]> it's not well defined
<K-ballo> no, that's not what it means
<K-ballo> the meaning is defined by the Sentinel type, and its relation to the iterator
<gonidelis[m]> but how does the implementation handle that?
<K-ballo> I don't see what the problem would be
<K-ballo> where's the implementation difficulty?
<gonidelis[m]> <K-ballo "worst case scenario, you just ke"> that means that last is a sentinel_value and not a distance
<K-ballo> I don't follow
<gonidelis[m]> sentinel being a distance and sentinel being a sentinel_value requires different implementations
<K-ballo> those are not things, a sentinel is just a sentinel
<K-ballo> and the algorithm just needs the iterator that corresponds to the sentinel
<K-ballo> and ranges::next does that job
<K-ballo> efficiently
<gonidelis[m]> ranges::next makes first equal to last+1?
<K-ballo> no, to last
<K-ballo> and not first, it returns the new value
<gonidelis[m]> yy
<gonidelis[m]> why do we pass first then?
<K-ballo> ranges(it, sentinel) returns the first iterator starting from it for which the sentinel predicate holds
<gonidelis[m]> as an arg to rangeS::next
<K-ballo> where would you start otherwise?
<K-ballo> you can't produce an iterator out of thin air
<gonidelis[m]> so it produces an iterator, and that iterator is last2
<K-ballo> that iterator is the iterator that corresponds to the sentinel
<gonidelis[m]> ok my problem is this "Return the nth successor of iterator i. "
<gonidelis[m]> from cppref
<gonidelis[m]> that's not the case you are describing
<gonidelis[m]> that treats the second argument as a distance
<K-ballo> 3) The first iterator equivalent to bound
<K-ballo> you want the overload taking a sentinel
<gonidelis[m]> i saw that... but the "Return the nth successor of iterator i. " is outer
<gonidelis[m]> so i guess it encapsulates all the cases
<K-ballo> it does, in the sentinel case the n is determined by the sentinel
<gonidelis[m]> ahhhhhh!!!!!!!!!!
<K-ballo> in the first case, the n is 1
<gonidelis[m]> okkkk yeah great!
<gonidelis[m]> finally! now it makes sense
<K-ballo> in the other two cases, n is given
<gonidelis[m]> c'moonnn... yeah. now i feel comfortable
<K-ballo> that was probably just copied over from std::next, you could suggest an eidt
<gonidelis[m]> K-ballo: do you know if we have any ranges::next impl btw? :p
<gonidelis[m]> <K-ballo "that was probably just copied ov"> oh ok
<gonidelis[m]> and say what ;p ?
<K-ballo> I don't know, I'd guess not, what other algorithms take bidirectional iterators?
<gonidelis[m]> K-ballo: haven't come accross any other
<gonidelis[m]> reverse is my first
<gonidelis[m]> bidir algo
<K-ballo> copy_backward?
<gonidelis[m]> yeah sure
<gonidelis[m]> i don't think we have implemented that
<gonidelis[m]> we have not
<gonidelis[m]> hkaiser constantly refers to that issue
hkaiser has joined #ste||ar
jehelset has joined #ste||ar
<gonidelis[m]> hkaiser: hey. i think we need a proper sequential impl for reverse (since once gain we use std::reverse). i though of going with the "possible implementation" here but we don't have a `ranges::iter_swap` right?
<hkaiser> gonidelis[m]: should be easy enough to implement
<jedi18[m]1> Hi! So I'm thinking of trying to adapt adjacent_difference for https://github.com/STEllAR-GROUP/hpx/issues/4822 over the next one week or two
<jedi18[m]1> Is that a good one to start with or would you recommend a different one?
<jedi18[m]1> Also this includes this issue as well right? https://github.com/STEllAR-GROUP/hpx/issues/1668
<hkaiser> jedi18[m]1: adjacent_difference is not the most difficult, but also not the most easy one
<gonidelis[m]> hkaiser: i should implement it as a facility under detail right? just like `detail::distance`
<K-ballo> what's wrong with std::reverse?
<hkaiser> gonidelis[m]: yah
<gonidelis[m]> <K-ballo "what's wrong with std::reverse?"> it does not support sentinels
<hkaiser> K-ballo: does not support iter/sentinel pairs
<K-ballo> yeah, but
<K-ballo> we were just discussing how reverse is implemented
<K-ballo> first thing it has to do is turn the sentinel into an iterator
<jedi18[m]1> hkaiser: What about unique then? Ranges for unique have been implemented so I'll only have to focus on #4822
<gonidelis[m]> hkaiser: jedi18 `rotate` seems quite wellcoming
<hkaiser> jedi18[m]1: I think we don't have any very easy ones left ;-)
<jedi18[m]1> gonidelis: Oh ok thanks, I'll go for rotate then?
<hkaiser> so you should be fine with adjacent_difference
<gonidelis[m]> jedi18: let's wait for hkaiser to confirm
<hkaiser> gonidelis[m]: rotate relies on reverse, iirc
<jedi18[m]1> hkaiser: if I go for adjacent_difference I'll also need to do https://github.com/STEllAR-GROUP/hpx/issues/1668, is that too much to take in at one go?
<gonidelis[m]> hkaiser: it has a `detail::reverse` call yeah
<jedi18[m]1> What about reverse? I see that is unimplemented too
<hkaiser> jedi18[m]1: #1668 will be a natural byproduct, I think
<hkaiser> jedi18[m]1: gonidelis[m] is wroking on reverse, currently
<gonidelis[m]> <K-ballo "first thing it has to do is turn"> what's your point?
<K-ballo> there is no sentinel-aware reverse implementation
<K-ballo> reverse has to be implemented in terms of a pair of iterators
<K-ballo> that's why ranges::reverse starts by turning the sentinel into an iterator
<jedi18[m]1> Ohh ok fine, I'll try adjacent_difference then. Are there any pre-requisites I need to know or will gonidelis 's article from yesterday(thanks again for that btw) be enough?
<gonidelis[m]> hkaiser: it uses std::adjacent_difference for the seq impl...
<hkaiser> hmm, and there is no ranges::adjacent_difference
<gonidelis[m]> because <numeric> ?
<gonidelis[m]> i think
<hkaiser> jedi18[m]1: ok, let's go with min/max/minmax_element
<jedi18[m]1> hkaiser: Oh ok sure! Thanks!
<hkaiser> ranges v3 has one, though - not sure what's different, will look
<K-ballo> concepts
<K-ballo> <numeric> stuff wasn't rangeified because figuring out the concepts was hard
<gonidelis[m]> i thought numeric had not been adapted yet
<hkaiser> ahh
<hkaiser> right
<gonidelis[m]> <K-ballo "that's why ranges::reverse start"> why not do `auto last2{ ranges::next(first, last) }; std::reverse(first, last2);` then?
<K-ballo> yes, that's effectively what you'd do
<K-ballo> how is that different from any other std:: algorithm?
<hkaiser> K-ballo: it might be more efficient not to forward the iter to the sentinel before calling the std:: algorithm, rather reimplement it
<K-ballo> ?
<K-ballo> reverse cannot be implemented in terms of sentinels
<gonidelis[m]> K-ballo: why?
<hkaiser> that is correct, I misunderstood what you were saying
<K-ballo> it's what we discussde earlier today
<K-ballo> you can't walk backwards from a sentinel, you need to turn it into an iterator in order to do that
<gonidelis[m]> <K-ballo "yes, that's effectively what you"> then why does `iter_swap(first, tail);` uses the ranges version? i mean since we deducted the problem to an iterator based range
<gonidelis[m]> it could may as well use `std::iter_swap`
<K-ballo> ranges::iter_swap differs from std::iter_swap in its support of proxy iterators
<K-ballo> proxy iterators are not supported by traditional algorithms
<gonidelis[m]> hm... so last2 is a proxy
<gonidelis[m]> I admit I didn't know about proxy iters
<K-ballo> it can be a proxy, it doesn't have to be
<gonidelis[m]> in other words I could may as well implement the std::iter_swap and just make it support idfferent first-last types
<hkaiser> I think you're fine with just using std::iter_swap
<K-ballo> if you are fine with std::iter_swap then you are fine with std::reverse just as well
<K-ballo> ranges::iter_swap doesn't support sentinels anyhow
K-ballo has quit [Read error: Connection reset by peer]
K-ballo has joined #ste||ar
<gonidelis[m]> hkaiser: yt?
<hkaiser> gonidelis[m]: here
<gonidelis[m]> hkaiser: i guess neither of those two would work for our sentinel case
<gonidelis[m]> right?
<hkaiser> sec
<hkaiser> gonidelis[m]: we already have that functionality, just a different name
<hkaiser> trying to find it...
<gonidelis[m]> adance
<gonidelis[m]> advance^^
<gonidelis[m]> yeah
<gonidelis[m]> ohh!!! thanks
<hkaiser> feel free to rename it or just call it from ranges::next()
<gonidelis[m]> call it from ranges::next() ?
<hkaiser> well, you need ranges::next, no?
<gonidelis[m]> which i already have, detail::advance_to_sentinel
<hkaiser> corrcet
<hkaiser> what I meant was you could actually implement a ranges::next by just calling the advance_to_sentinel
<gonidelis[m]> oh ok...
<gonidelis[m]> where could that be done?
<hkaiser> gonidelis[m]: we need to consolidate the range related facilities
wash[m] has quit [*.net *.split]
zao has quit [*.net *.split]
parsa has quit [Quit: Free ZNC ~ Powered by LunarBNC: https://LunarBNC.net]
parsa has joined #ste||ar
zao has joined #ste||ar
wash[m] has joined #ste||ar
pedro_barbosa[m] has quit [Ping timeout: 246 seconds]
tid_the_harveste has quit [Ping timeout: 240 seconds]
gonidelis[m] has quit [Ping timeout: 244 seconds]
ms[m] has quit [Ping timeout: 246 seconds]
vroni[m] has quit [Ping timeout: 268 seconds]
k-ballo[m] has quit [Ping timeout: 244 seconds]
srinivasyadav227 has quit [Ping timeout: 240 seconds]
gnikunj[m] has quit [Ping timeout: 240 seconds]
tiagofg[m] has quit [Ping timeout: 240 seconds]
jedi18[m]1 has quit [Ping timeout: 268 seconds]
jpinto[m] has quit [Ping timeout: 268 seconds]
klaus[m] has quit [Ping timeout: 258 seconds]
rori has quit [Ping timeout: 268 seconds]
heller1 has quit [Ping timeout: 260 seconds]
tid_the_harveste has joined #ste||ar
vroni[m] has joined #ste||ar
gonidelis[m] has joined #ste||ar
<hkaiser> gonidelis[m]: yah, could be
hkaiser has quit [Read error: Connection reset by peer]
hkaiser has joined #ste||ar
ms[m] has joined #ste||ar
jedi18[m]1 has joined #ste||ar
pedro_barbosa[m] has joined #ste||ar
jpinto[m] has joined #ste||ar
k-ballo[m] has joined #ste||ar
srinivasyadav227 has joined #ste||ar
gnikunj[m] has joined #ste||ar
tiagofg[m] has joined #ste||ar
heller1 has joined #ste||ar
<gonidelis[m]> K-ballo: is difference type the same as dereference type?
klaus[m] has joined #ste||ar
<K-ballo> no
<gonidelis[m]> what's the difference?
<K-ballo> iff/eref
<gonidelis[m]> right
rori has joined #ste||ar
<gonidelis[m]> it took my ages to figure out
<gonidelis[m]> are there any differences in terms of semantics?
<K-ballo> definitely
<gonidelis[m]> ??
<K-ballo> there definitely are differentes in terms of semantics between difference type and dereference type
<gonidelis[m]> you mean differencies
<K-ballo> I do
<gonidelis[m]> cool
<K-ballo> differences, actually
<gonidelis[m]> both are valid
<K-ballo> I only meant one
<gonidelis[m]> do we have anything like `std::iter_difference_t` implemented?
<gonidelis[m]> i can see this counting_iterator thing but that's a type...
<K-ballo> iterator_traits<>::difference_type ?
<gonidelis[m]> yeah just found it
<gonidelis[m]> thanks
<gonidelis[m]> but since standard has this, why does it also have `iter_difference_t`
<K-ballo> it adds some defaults and/or relaxations
<gonidelis[m]> hm... ok. so that will do
<gonidelis[m]> hkaiser: `std::iter_swap` works for differenct type of iterators
<gonidelis[m]> you were right
<gonidelis[m]> hkaiser: K-ballo so again, i cannot really understand the purpose of `ranges::iter_swap`
<K-ballo> it's a customization point (for proxy iterators)
<K-ballo> it's the range equivalent of std::iter_swap
<gonidelis[m]> K-ballo: are proxy iterators somewhere in the standard so i could read about them
<K-ballo> maybe read the paper on adding support for proxy iterators?
<K-ballo> not really much to gain though, just for curiosity
<gonidelis[m]> i just want to understand what they are and how they work
<K-ballo> a proxy iterator is one that when dereferenced returns a reference-like object
<K-ballo> think std::vector<bool>::iterator
<K-ballo> except, think of a reasonable use case, try to forget about the vector<bool> aspect
<K-ballo> zip iterator, kiiiinda
<K-ballo> gonidelis[m]: you may have seen HPX has an invalid overload of std::swap for tuples of references
<gonidelis[m]> <K-ballo "think std::vector<bool>::iterato"> i didn't catch the example
<gonidelis[m]> what's special about std::vector<bool>¨ιτερατορ
<gonidelis[m]> oh shit... greek hieroglyphs again
<gonidelis[m]> std::vector<bool>::iterator ^^
<K-ballo> when dereferenced it returns a reference-like object
<K-ballo> it doesn't return a real reference to a bool, it can't possibly, since it doesn't actually store bools
<gonidelis[m]> why "-like"?
<K-ballo> because it's an object that behaves like a reference
<K-ballo> it's not a reference
<gonidelis[m]> so the bools are stored in the vector and the iterator refers to them
<K-ballo> the bools aren't stored
<K-ballo> vector<bool> stores bits, not bools
<gonidelis[m]> yeah ok. so again. the bits are stores and the iterator refers to them
<K-ballo> it's not possible to refer to a bit
<K-ballo> bits are not addressable
<gonidelis[m]> lol
<gonidelis[m]> you tricked me into that
<gonidelis[m]> yeah I just re-read it.
<K-ballo> if it were possible then there wouldn't be a problem, no need for proxys, nothing
<gonidelis[m]> so what does the iterator do? how does it refer to/find them?
<K-ballo> it returns a reference-like object instead
<gonidelis[m]> the iterator?
<K-ballo> the vector, the iterator too
<gonidelis[m]> is reference-like an official term?
<K-ballo> official? yes, but not normative
<gonidelis[m]> normative?
<K-ballo> it doesn't have a formal definition (in the standard)
<gonidelis[m]> <K-ballo "https://eel.is/c++draft/vector.b"> what's this magic
<K-ballo> see how `reference` is not a reference, but an object type that attempts to behave as one instead
<K-ballo> it's a proxy
<gonidelis[m]> how `operator bool()` works in the reference class?
<K-ballo> how is it implemented?
<K-ballo> there's a pointer to a block, and a bit index within that block, and it just reads the corresponding bit in the block
<gonidelis[m]> K-ballo: where's the pointer to the block?
<K-ballo> in the reference class
<gonidelis[m]> it's hard
<gonidelis[m]> i am pissed
<K-ballo> because it is hard?
<gonidelis[m]> yes
<gonidelis[m]> i cannot figure how it works
<gonidelis[m]> there is the class vector and the class reference and these two are friend classes
<K-ballo> you picked the wrong language
<gonidelis[m]> K-ballo: what do you mean?
<K-ballo> if you are gonna get pissed every time it's hard, with C++ you are going to get pissed all the time
<gonidelis[m]> K-ballo: getting pisses make good to me
<gonidelis[m]> pissed*
<gonidelis[m]> ok it starts to make sense now
<gonidelis[m]> thank god
<gonidelis[m]> what i am missing now is, shouldn't I use sth like `std::vector<bool> a; std::reference(a);`
<gonidelis[m]> K-ballo: i don't know
<K-ballo> no
<K-ballo> a[x] will give you a reference
<K-ballo> or *a.begin()
<K-ballo> (assuming `std::reference` refers to `std::vector<bool>::reference`)
<gonidelis[m]> where's the `*` operator overloading?
<gonidelis[m]> i found the `[]` one
<K-ballo> the iterator dereference operation? in the iterator
<hkaiser> K-ballo: does operator*() for vector<bool> return a reference? I thought it returned a proxy object
<K-ballo> it returns an `std::vector<bool>::reference`, the proxy object
<hkaiser> ahh, ok
<hkaiser> sure
<gonidelis[m]> K-ballo: so it's like a[x] is implemented immediately within the vector class and `*a.begin()` is possible because there is the `begin()` implemented there
<K-ballo> ?
<K-ballo> `*a.begin()` is possible because `a.begin()` returns an iterator
<gonidelis[m]> and the iterator can be referenced
<K-ballo> assuming non-empty, sure
<K-ballo> any dereferenceable iterator can be dereferenced
<gonidelis[m]> ok so back to the subject, making a.begin() return an iterator leads to the vector<bool> giving a reference-like object
<gonidelis[m]> ?
<gonidelis[m]> i am 90% what i said is wrong
<K-ballo> uhm? no
<K-ballo> vector<bool> (and it's corresponding iterator) yield a reference-like object because they can't yield a proper reference, there's no bool object stored anywhere
<K-ballo> for context: references reference objects (and sometimes functions too, but those aren't relevant here)
<K-ballo> no object -> no reference
<gonidelis[m]> where is it declared that *a.begin() where a is a vector<bool> is not a straightforward ref?
<gonidelis[m]> but we do have a vector<bool> object
<K-ballo> no good for producing references to bools, only goot for producing refernces to vector<bool>s
<K-ballo> std::vector<bool>::iterator having a reference type of std::vector<bool>::reference is implied throught the docs, but just of think of it.. if it were a proper bool&, what would it refer to?
<gonidelis[m]> what does int& refer to?
<K-ballo> an int object
<gonidelis[m]> so there are not bool objects
<K-ballo> ?
<K-ballo> you mean within std::vector<bool>? no, std::vector<bool> does not contain bools, it contains bits
<gonidelis[m]> so there don't exist such things as boob objects
<K-ballo> std::vector<anything-else> contains anything-elses
<K-ballo> boob object
<K-ballo> bool objects obviously exist, here's one: bool x;
<gonidelis[m]> ...
<K-ballo> std::vector<bool> doesn't store any
<K-ballo> have you read https://eel.is/c++draft/vector.bool yet?
<gonidelis[m]> (i need to lie on the floor for like 20 minutes and stare on the ceiling after that)
<gonidelis[m]> <K-ballo "have you read https://eel.is/c++"> i am constantly scanning it while we are talking for the past half an hour
<K-ballo> > operations dealing with the bool value type map to bit values in the container storage
<K-ballo> > To optimize space allocation
<gonidelis[m]> ok i think i am close. what would be the reference class for the vector<int> type then?
<K-ballo> it's not a class, it's a proper reference: int&
<gonidelis[m]> so it's an & operator overloading or sth?
<K-ballo> ? no
<gonidelis[m]> fuvk
<K-ballo> std::vector<int> stores ints, v[x] gives you a (proper) reference to an int
<gonidelis[m]> so there is not need for operator`[]` definition
<K-ballo> of course there's an op[] definition
<K-ballo> why wouldn't there be one? i don't follow
<gonidelis[m]> so there would be an op[] def but not a op& one
<K-ballo> I don't follow
<gonidelis[m]> ok let it be... i have lots of things to consider
<gonidelis[m]> that was a blast
<K-ballo> most people don't need to know about proxy iterators
<gonidelis[m]> i want to
<gonidelis[m]> getting to know the language is valuable
<gonidelis[m]> hkaiser: would you mind giving it a look
<gonidelis[m]> there are the sentinel cases left to do
<hkaiser> gonidelis[m]: next() does not entirely live in std::ranges
<hkaiser> it's also in std::
<hkaiser> same for line 35
<hkaiser> well, if it's really either input or output iterator, you could check for just is_iterator
<hkaiser> currently it's a noop, essentially
<gonidelis[m]> noop?
<hkaiser> gonidelis[m]: if you call next(iter), there will be no observable effect, iter == next(iter)
bita has joined #ste||ar
jehelset has quit [Remote host closed the connection]
bita has quit [Ping timeout: 264 seconds]
diehlpk has joined #ste||ar
diehlpk has quit [Quit: Leaving.]