Calculating waves

I've been scrolling around this site for a while, but just recently got really interested in actually trying out some of the challenges. I was intending to try my hand at some of the existing code-golf topics, but I didn't have Internet access for a while yesterday, and in the meantime, I thought up my own challenge.

Your task is to create a program or function that takes an array of Floats a and an integer n, then sets each value in a to the average of the two beside it, n times. When repeatedly used with increasing values of n, this generates a wave-like motion:

Specifics:

• If there happens to be only one item in a, or if n is 0 or less, the program should return the original array.
• Inputs and outputs can be in any format you desire, as long as they are visibly separated.

For each step:

• The first item in a should become the average of itself and the next item.
• The last item in a should become the average of itself and the previous item.
• Any other item in a should become the average of the previous item and the next item.
• Make sure you are calculating off the previous step's array and not the current one!

Test cases: NOTE: Your inputs/outputs do not have to be in this format!

[0, 0, 1, 0, 0], 1          -> [0, 0.5, 0, 0.5, 0]
[0, 0, 1, 0, 0], 2          -> [0.25, 0, 0.5, 0, 0.25]
[0, 0, 1, 0, 0], 0          -> [0, 0, 1, 0, 0]
[0, 0, 1, 0, 0], -39        -> [0, 0, 1, 0, 0]
[0, 16, 32, 16, 0], 1       -> [8, 16, 16, 16, 8]
[0, 1, 2, 3, 4, 5], 1       -> [0.5, 1, 2, 3, 4, 4.5]
[0, 64], 1                  -> [32, 32]
[0], 482                    -> [0]
[32, 32, 32, 16, 64, 16, 32, 32, 32], 4 -> [33, 27, 40, 22, 44, 22, 40, 27, 33]


This is , so shortest answer in bytes wins. The winner will be chosen in one week (on August 1). Good luck!

Edit: Congrats to the winner, @issacg, with a whopping 18 bytes!

• My advice to improving this challenge is to get rid of the n is not supplied and a is not supplied cases - they don't really add much. – isaacg Jul 26 '15 at 0:24
• I believe the final test case is incorrect. n should be 4, not 5. – isaacg Jul 26 '15 at 0:40
• @isaacg: Yeah, now that I look at it again, those cases don't seem that important. I've changed that, and fixed the incorrect example as well. Thanks for pointing those things out! – ETHproductions Jul 26 '15 at 0:51
• If you really want it to handle empty lists, you may want to add it to the list of test cases. I just noticed that my solution fails for that case. Personally, I'm not a big fan of problems where a large part of the solution is for handling special cases. – Reto Koradi Jul 26 '15 at 4:29
• @RetoKoradi Sorry, I had forgotten to remove the "empty list" case from the rules when I removed it from the examples. Thanks for the notice! – ETHproductions Jul 30 '15 at 2:44

Pyth, 46 18 bytes

ucR2sV+hGGt+GeG.*Q


This code expects input in the form iterations, [wave1, wave2, wave3 ...], as seen at the first link below.

The program works by applying the code within the reduce (u) function to the input list, as many times as the number of iterations.

I will demonstrate the wave propagation function on the list [0, 1, 2, 3, 4, 5], which is in G:

+hGG prepends G's first element to G, forming [0, 0, 1, 2, 3, 4, 5].

t+GeG appends G's last element to G and removes its first element, forming [1, 2, 3, 4, 5, 5].

sV first forms pairs from the lists, giving [[0, 1], [0, 2], [1, 3], [2, 4], [3, 5], [4, 5]] with the final element of the first list truncated away. Then, the pairs are summed via the s function, giving [1, 2, 4, 6, 8, 9].

cR2 uses floating point division to divide all of the numbers by 2, giving the desired result, [0.5, 1.0, 2.0, 3.0, 4.0, 4.5].

Snowman 1.0.0, 219 chars

{vg" "aS:10sB;aM0aa,AAg**-:|al|'NdE'0nRal@(%}{->:1*?{0AaG;:?{;bI:dUNiNwR'NdEwRaC;aM(~:?{(()1wR]0wRaC*))#'wRaC|*#|(()#aLNdEdUNdEwR]wR]aCwR*))#aC;:0wRdUaCwR*?{#aC;#bI:*#0aA'|aa|'!*+'(()#1aA*))#|,aa|'*nA2nD;aM|*0*;bR|tSsP


{vg" "aS:10sB;aM0aa,AAg**-:|al|'NdE'0nRal@(%}{->:1*?{0AaG;:?{;bI:dUNiNwR'NdEwRaC;
aM(~:?{(()1wR]0wRaC*))#'wRaC|*#|(()#aLNdEdUNdEwR]wR]aCwR*))#aC;:0wRdUaCwR*?{#aC;#
bI:*#0aA'|aa|'!*+'(()#1aA*))#|,aa|'*nA2nD;aM|*0*;bR|tSsP


Ungolfed / unminified version:

{vg" "aS:10sB;aM  // input space-separated list of numbers
0aa,AAg           // get first element and array of all-but-first elements
**                // discard original input and the 0

// execute the following (input[0]) times
-:
|al|'NdE'0nR               // get range from (0..input.length-1]
al@(%}{->:1*?{0AaG;:?{;bI  // chop off first element if any
:dUNiNwR'NdEwRaC;aM        // map n -> [n-1 n+1]
// if the input consisted of a single element, append [0 0]
// otherwise prepend [0 1] and append [len-2 len-1]
(~:?{(()1wR]0wRaC*))#'wRaC|*#|(()#aLNdEdUNdEwR]wR]aCwR*))#aC;
:0wRdUaCwR*?{#aC;#bI
// map indeces to avg(input[i1], input[i2])
:*#0aA'|aa|'!*+'(()#1aA*))#|,aa|'*nA2nD;aM
// replace old input, reset permavar
|*0*
;bR

|tSsP  // output result


Sample I/O format:

llama@llama:...Code/snowman/ppcg53799waves$snowman waves.snowman 4 32 32 32 16 64 16 32 32 32 [33 27 40 22 44 22 40 27 33]  • This is horribly beautiful. – kirbyfan64sos Jul 26 '15 at 17:50 Pyth - 25 24 bytes Uses enumerate, reduce to do iterations. u.ecs@L++hGGeG,khhk2GvzQ  Racket, 164 145 bytes (define(f a n)(if(< n 1)a(f(let([l(length a)][r list-ref])(for/list([i(in-range l)])(/(+(r a(max(- i 1)0))(r a(min(+ i 1)(- l 1))))2)))(- n 1))))  Ungolfed (define (f a n) (if (< n 1) a (f (let ([l (length a)] [r list-ref]) (for/list ([i (in-range l)]) (/ (+ (r a (max (- i 1) 0)) (r a (min (+ i 1) (- l 1)))) 2))) (- n 1))))  Note, you may need the #lang racket line to run this. R, 109 bytes function(x,n){l=length(x);t=if(l>2)c(.5,0,.5)else if(l==2)c(.5,.5)else 1;for(i in 1:n)x=filter(x,t,c=T);c(x)}  This creates an unnamed function that accepts a vector and an integer and returns a vector. The approach here is to treat the input as a univariate time series and apply a linear convolution filter. Ungolfed + explanation: f <- function(x, n) { # Define filter coefficients t <- if (length(x) > 2) c(0.5, 0, 0.5) else if (length(x) == 2) c(0.5, 0.5) else 1 # Apply the filter n times for (i in 1:n) { # The circular option wraps the filter around the edges # of the series, otherwise the ends would be set to NA. x <- filter(x, t, circular = TRUE) } # Returned the modified input, stripped of the extraneous # properties that the filter function adds. c(x) }  Examples: > f(c(32, 32, 32, 16, 64, 16, 32, 32, 32), 4) [1] 33 27 40 22 44 22 40 27 33 > f(0, 482) [1] 0 > f(c(0, 64), 1) [1] 32 32  Haskell, 76 characters The trick is to add the first number to the beginning of the list and the last one to the end of the list instead of dealing with the boundary conditions. f a@(x:s)=(/2)<$>zipWith(+)(x:a)(s++[last s])
f x=x
a#n|n<1=a|n>0=f a#(n-1)


Tests:

λ: [0, 0, 1, 0, 0]#1
[0.0,0.5,0.0,0.5,0.0]
λ: [0, 0, 1, 0, 0]#2
[0.25,0.0,0.5,0.0,0.25]
λ: [0, 0, 1, 0, 0]#0
[0.0,0.0,1.0,0.0,0.0]
λ: [0, 0, 1, 0, 0]#(-39)
[0.0,0.0,1.0,0.0,0.0]
λ: [0, 16, 32, 16, 0]#1
[8.0,16.0,16.0,16.0,8.0]
λ: [0, 1, 2, 3, 4, 5]#1
[0.5,1.0,2.0,3.0,4.0,4.5]
λ: [0, 64]#1
[32.0,32.0]
λ: [0]#482
[0.0]
λ: [32, 32, 32, 16, 64, 16, 32, 32, 32]#4
[33.0,27.0,40.0,22.0,44.0,22.0,40.0,27.0,33.0]

• You can save a few bytes by using infix operators for 2-argument functions and guards instead of if then else, i.e. c becomes a#n|n<1=a|1<2=iterate f a!!n and s becomes x!y=(x+y)/2 (and is called ...zipWith(!)(x:a)...). – nimi Jul 26 '15 at 10:16
• Thanks! Didn't know how guards work in one-line expressions. – Keyran Jul 26 '15 at 11:13
• Another 2 bytes: make c an infix operator, say #: a#n|n<1=a|1<2=iterate f a!!n. Call it like [0, 0, 1, 0, 0] # 2. – nimi Jul 26 '15 at 20:44

CJam, 23 22 bytes

q~{_(@)@@+@@+.+.5f*}*


Try it online

The input is in CJam list format, e.g. for the last example:

[32 32 32 16 64 16 32 32 32] 4


The output is also a CJam list:

[33.0 27.0 40.0 22.0 44.0 22.0 40.0 27.0 33.0]


The basic approach is that in each step, the vector is shifted one position to the left and one position to the right. Each of the two vectors is padded with the first/last element, and then the average of the two vectors is calculated.

Explanation:

q~    Get and interpret input.
{     Loop over repeat count.
_     Copy list.
(     Pop off left element.
@     Get original list to top.
)     Pop off right element.
@@    Get first element and list with last element removed to top.
+     Concatenate. This gives right-shifted list with first element repeated.
@@    Get list with first element removed and last element to top.
+     Concatenate. This gives left-shifted list with last element repeated.
.+    Perform vector addition of two shifted lists.
.5f*  Multiply sum by 0.5 to give average.
}*    End loop over repeat count.
     Convert result array to string.

• I'm not the OP, but "If there happens to be zero or one items in a, or if n is 0 or less, the program should return the original array. " – Maltysen Jul 26 '15 at 6:03

Java, 181 bytes

Here's the golfed version:

float[]g(float[]i,int n){float[]c=i.clone();int l=c.length,s=1;if(n>0&&l>1){c[0]=(i[0]+i[1])/2f;c[--l]=(i[l]+i[l-1])/2f;while(s<l)c[s]=(i[s-1]+i[++s])/2f;return g(c,n-1);}return i;}


Ungolfed:

float[] g(float[] i, int n) {
float[] c = i.clone();
int l = c.length,s=1;
if(n>0&&l>1) {
c[0] = (i[0]+i[1])/2f;
c[--l] = (i[l]+i[l-1])/2f;
while(s<l)
c[s] = (i[s-1] + i[++s]) / 2f;
return g(c, n-1);
}
return i;
}


I tried to shorten assignments and conditionals as much as possible with Java. Improvements are welcome, of course.

JavaScript (ES6), 153132 67 chars

I come back to my first answer 6 months later and what do I do? Golf off 50%, that's what. ;)

s=(a,n)=>n<1?a:s(a.map((j,i)=>(a[i&&i-1]+a[a[i+1]+1?i+1:i])/2),n-1)


This version calls itself repeatedly until n is less than 1, decrementing n by 1 each time.

A non-recursive solution (151 130 78 chars):

(a,n)=>n<1?a:eval("while(n--)a=a.map((j,i)=>(a[i&&i-1]+a[a[i+1]+1?i+1:i])/2)")


Ungolfed: (outdated)

Recursive:

s = function (a, n) {
if (n < 1)
return a;
b = [];
l = a.length;
x = y = 0;
for(var i = 0; i < l; i++) {
x = a[(i < 1) ? 0 : i-1];
y = a[(i > l-2) ? i : i+1];
b[i] = (x + y)/2;
}
if (n > 2)
return b;
return s(b,n-1);
}


Non-recursive:

s = function (a, n) {
if (n < 1)
return a;
b = [];
l = a.length;
x = y = 0;
while(n-- > 0) {
for(var i = 0; i < l; i++) {
x = a[(i < 1) ? 0 : i-1];
y = a[(i > l-2) ? i : i+1];
b[i] = (x + y)/2;
a = b.slice(0);   // setting a to a copy of b, for copyright reasons
}
return b;
}

• if(n<2)return b;return s(b,n-1) could be reduced to return n<2?b:s(b,n-1) – Cyoce Jan 11 '16 at 7:16
• @Cyoce Thanks, I've taken that into account, and then some... – ETHproductions Jan 11 '16 at 17:24

Java, 203 bytes

Trying my first put with Java. Improvement tips are welcome:)

double[]f(double[]a,int n){int j,s,i=0;s=a.length-1;if(n<1||s<1)return a;double b[]=a;for(;i++<n;a=b.clone()){b[0]=.5*(a[0]+a[1]);b[s]=.5*(a[s]+a[s-1]);for(j=1;j<s;++j)b[j]=.5*(a[j-1]+a[j+1]);}return b;}


Pretty printed:

double[] g(double[] a, int n) {
int j, s, i = 0;
s = a.length - 1;
if (n < 1 || s < 1)
return a;
double b[] = a;
for (; i++ < n; a = b.clone()) {
b[0] = .5 * (a[0] + a[1]);
b[s] = .5 * (a[s] + a[s - 1]);
for (j = 1; j < s; ++j)
b[j] = .5 * (a[j - 1] + a[j + 1]);
}
return b;
}

• Welcome to PPCG! I don't golf much in Java, but can you move the three assignments inside the outer for loop into the loop's increment statement? Like for(i=0;i<n;b[0]=...,b[s-1]=...,a=...,++i)for(...)b[j]=...;? Then you should be able to get rid of the braces. – Martin Ender Jul 26 '15 at 11:14
• Unfortunately they have to be repeated on each iteration, so they have to stay inside the braces. – Geir Jul 26 '15 at 11:28
• The increment is also repeated each iteration, which is why you'd put them in the third slot (separated from the ++i and each other with commas instead of semicolons). Try it out. :) – Martin Ender Jul 26 '15 at 11:36
• I see where you're going, but I'm losing the update in the final iteration (unless there's a trick I don't know). Still, able to shave a few bytes here and there by doing "ugly things":) – Geir Jul 26 '15 at 15:29
• I don't think you are losing the update on the final iteration. f(a;b;c){d;e;} should be completely identical to f{a;b;}{d;e;c;}, and therefore also to f(a;b;e,c)d;. However, with your rearranged code that no longer works, because you can't move the for inside the other for, so I guess all of this no longer matters. ;) – Martin Ender Jul 27 '15 at 0:32

Python 2, 98 Bytes

Took the straightforward approach, used exec to get out of using a while loop. I think there's a better way of doing the logic to figure out special case positions, but this works for now. Input should be formatted like [list], times.

b,c=input()
k=~-len(b)
exec'b=[(b[x-(0<x<k)]+b[x+(x<k)-(x==k)])/2.for x in range(-~k)];'*c
print b


Ungolfed:

BASE,TIME = input()
TEMP = [0]*len(BASE)                               # Temporary array as to not modify base.
while TIME:
for x in xrange(len(BASE)):
if x == 0:
TEMP[x] = (BASE[x]   + BASE[x+1])/2.0  # First element special case.
elif x == len(BASE)-1:
TEMP[x] = (BASE[x]   + BASE[x-1])/2.0  # Last element special case.
else:
TEMP[x] = (BASE[x-1] + BASE[x+1])/2.0  # Every other element.
BASE = TEMP                                    # Set base to temporary array.
TEMP = [0]*len(BASE)                           # Reset temporary array to 0s.
TIME = TIME - 1
print BASE


Mathematica, 81 bytes

I have a feeling it could be golfed more if I could figure out a better way to handle the positivity condition.

f[l_,_]:=l;f[l_,n_/;n>0]:=Nest[.5{1,0,1}~ListConvolve~ArrayPad[#,1,"Fixed"]&,l,n]


Worth noting: Mathematica offers lots of potential built-in solutions in its range of list-processing and filter functions, as well as CellularAutomaton. I chose Nest[... ListConvolve ...] because it was the easiest way to work out the kinks at the ends of the list, but other angles might prove shorter.

Matlab , 109

function a=f(a,n)
if numel(a)>1&n>0
for k=1:n
a=[a(1)+a(2) conv(a,[1 0 1],'valid') a(end-1)+a(end)]/2;end
end


Examples:

>> f([0, 0, 1, 0, 0], 1)
ans =
0    0.5000         0    0.5000         0

>> f([0, 0, 1, 0, 0], 2)
ans =
0.2500         0    0.5000         0    0.2500

>> f([0, 0, 1, 0, 0], 0)
ans =
0     0     1     0     0

>> f([0, 0, 1, 0, 0], -39)
ans =
0     0     1     0     0

>> f([0], 482)
ans =
0

>> f([], 10)
ans =
[]


Scala, 195 characters (186 with lazy output, i.e. Stream) 187 characters

(t:Seq[Float],n:Int)⇒t.size match{case 0|1⇒t;case 2⇒{val a=t.sum/2;Seq(a,a)};case i⇒(t/:(1 to n)){(s,_)⇒(s.take(2).sum/2)+:s.sliding(3).map(l=>(l(0)+l(2))/2).toList:+(s.drop(i-2).sum/2)}}


probably not optimal, mapping sliding(3) is very useful in this case.

tests:

scala> (t:Seq[Float],n:Int)⇒t.size match{case 0|1⇒t;case 2⇒{val a=t.sum/2;Seq(a,a)};case i⇒(t/:(1 to n)){(s,_)⇒(s.take(2).sum/2)+:s.sliding(3).map(l=>(l(0)+l(2))/2).toList:+(s.drop(i-2).sum/2)}}
res0: (Seq[Float], Int) => List[Float] = <function2>

scala> res0(Seq(0, 0, 1, 0, 0), 1)
res1: Seq[Float] = List(0.0, 0.5, 0.0, 0.5, 0.0)

scala> res0(Seq(0, 0, 1, 0, 0), 2)
res2: Seq[Float] = List(0.25, 0.0, 0.5, 0.0, 0.25)

scala> res0(Seq(0, 0, 1, 0, 0), 0)
res3: Seq[Float] = List(0.0, 0.0, 1.0, 0.0, 0.0)

scala> res0(Seq(0, 0, 1, 0, 0), -39)
res4: Seq[Float] = List(0.0, 0.0, 1.0, 0.0, 0.0)

scala> res0(Seq(0, 16, 32, 16, 0), 1)
res5: Seq[Float] = List(8.0, 16.0, 16.0, 16.0, 8.0)

scala> res0(Seq(1, 2, 3, 4, 5), 1)
res6: Seq[Float] = List(1.5, 2.0, 3.0, 4.0, 4.5)

scala> res0(Seq(0,64), 1)
res7: Seq[Float] = List(32.0, 32.0)

scala> res0(Seq(0), 482)
res8: Seq[Float] = List(0.0)

scala> res0(Seq(32, 32, 32, 16, 64, 16, 32, 32, 32), 4)
res9: Seq[Float] = List(33.0, 27.0, 40.0, 22.0, 44.0, 22.0, 40.0, 27.0, 33.0)


q (27 characters)

{avg x^/:1 -1 xprev\:x}/[;]


Examples

q)f:{avg x^/:1 -1 xprev\:x}/[;]
q)f[4;32 32 32 16 64 16 32 32 32]
33 27 40 22 44 22 40 27 33f
//1-length input
q)f[10;enlist 1]
,1f
//0-length input
q)f[10;float$()] float$()


R, 93 Bytes

As an unnamed function

function(a,n){l=length(a);while((n=n-1)>=0)a<-colMeans(rbind(c(a[-1],a[l]),c(a[1],a[-l])));a}


Expanded

function(a,n){
l=length(a);             # get the length of the vector
while((n=n-1)>=0)        # repeat n times
a<-colMeans(         # do the column means and assign to a
rbind(             # create an array
c(a[-1],a[l]),   # shift the vector left and duplicate last
c(a[1],a[-l])    # shift the vector right and duplicate first
)
);
a                        # return the vector
}


Tests

> f=function(a,n){l=length(a);while((n=n-1)>=0)a<-colMeans(rbind(c(a[-1],a[l]),c(a[1],a[-l])));a}
> f(c(0, 0, 1, 0, 0), 1)
[1] 0.0 0.5 0.0 0.5 0.0
> f(c(0, 0, 1, 0, 0), 2)
[1] 0.25 0.00 0.50 0.00 0.25
> f(c(0, 0, 1, 0, 0), 0)
[1] 0 0 1 0 0
> f(c(0, 0, 1, 0, 0), -39)
[1] 0 0 1 0 0
> f(c(0, 16, 32, 16, 0), 1)
[1]  8 16 16 16  8
> f(c(0, 1, 2, 3, 4, 5), 1)
[1] 0.5 1.0 2.0 3.0 4.0 4.5
> f(c(0, 64), 1)
[1] 32 32
> f(c(0), 482)
[1] 0
> f(c(32, 32, 32, 16, 64, 16, 32, 32, 32),4)
[1] 33 27 40 22 44 22 40 27 33
>


Japt, 39 37 bytes (non-competing)

This answer is non-competing because the language is newer than the challenge. I just wanted to see how well my golfing language could hold up to my first challenge.

Vm0 o r_£ZgY©Y-1 +ZgY>Zl -2?Y:°Y)/2}U


Try it online!

Vm0 o r_£ZgY©Y-1 +ZgY>Zl -2?Y:°Y)/2}U
Vm0 o      // Generate the range of integers [0, max(V,0)).
r_     }U  // Reduce it with this function, with a starting value of U:
£          //  Return the argument, with each item X, index Y, and the full array Z mapped by this function:
ZgY©Y-1 +  //   Return (Z[max(Y-1,0)] plus
ZgY>Zl -2? //    Z[Y > Z.length-2?
Y:°Y)      //      Y:--Y],)
/2         //   divided by two.
// Implicit: output last expression


C++14, 158 bytes

#define D(a,b)d[i]=(c[a]+c[b])/2;
auto f(auto c,int n){while(n-->0&&c.size()>1){auto d{c};int i{};D(0,1)while(++i<c.size()-1)D(i-1,i+1)D(i,i-1)c=d;}return c;}


Requires input to be a container value_type==double, like vector<double>.

Ungolfed:

#define D(a,b) d[i] = (c[a]+c[b])/2;   //average
auto f(auto c, int n) {
while(n-- > 0 && c.size() > 1) {     //breaks
auto d{c};                         //copy container
int i{};
D(0,1)                             //left
while(++i < c.size()-1)            //count up to right
D(i-1,i+1)                       //interior
D(i,i-1)                           //right
c=d;                               //overwrite container
}
return c;
}


Racket 223 bytes

(let p((l l)(m 0)(g list-ref))(cond[(> n m)(let*((j(length l))(k(for/list((i j))(cond[(= i 0)(/(+(g l 0)(g l 1))2)]
[(= i(- j 1))(/(+(g l(- j 2))(g l(- j 1)))2)][else(/(+(g l(+ i 1))(g l(- i 1)))2)]))))(p k(+ 1 m) g))][l]))


Ungolfed:

(define(f l n)
(let loop ((l l)
(m 0)
(lr list-ref))
(cond
[(> n m)
(let* ((j (length l))
(k (for/list ((i j))
(cond
[(= i 0)       (/ (+ (lr l 0)
(lr l 1))
2)]
[(= i (- j 1)) (/ (+ (lr l (- j 2))
(lr l (- j 1)))
2)]
[else          (/ (+ (lr l (+ i 1))
(lr l (- i 1)))
2)])
)))
(loop k
(+ 1 m)
lr))]
[else l]
)))


Testing:

(f '[32 32 32 16 64 16 32 32 32] 4)


Output:

'(33 27 40 22 44 22 40 27 33)


Jelly, 14 bytes

.ịṚjṡ3 .ịⱮÆmµ¡


Try it online!

Full program.

C# (Visual C# Interactive Compiler), 160 144 bytes

float[]a(float[]b,int c)=>c>0&b.Length>1?a(b.Select((_,w)=>w<1?(b[w]+b[w+1])/2:w>b.Length-2?(b[w]+b[w-1])/2:(b[w-1]+b[w+1])/2).ToArray(),c-1):b;
`

Uses good ol' recursion.

Try it online!