\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename gnudl-tutorial.info
@settitle Gnudl Tutorial
@include version.texi
@ifinfo
@format
START-INFO-DIR-ENTRY
* gnudl-tutorial: (gnudl-tutorial). Gnudl Tutorial
END-INFO-DIR-ENTRY
@end format
@end ifinfo
@setchapternewpage on
@c Choices for setchapternewpage are {on,off,odd}.
@paragraphindent 2
@c %**end of header
@iftex
@finalout
@c DL: lose the egregious vertical whitespace, esp. around examples
@c but paras in @defun-like things don't have parindent
@parskip 4pt plus 1pt
@end iftex
@titlepage
@title Gnudl Tutorial
@c @subtitle Gnudl Tutorial
@subtitle For use with Gnudl @value{VERSION}
@subtitle Last updated @value{UPDATED}
@author by Mark Galassi
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1995 Mark Galassi
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the author.
@end titlepage
@node Top, Overview, (dir), (dir)
@ifinfo
This file gives a tutorial for Gnudl @value{VERSION}
Copyright (C) 1995 Mark Galassi
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the author.
@end ifinfo
@menu
* Overview::
* Getting and installing the gnudl prototype::
* Gnudl prototype tutorial::
* Reference manual::
* Concept Index::
* Procedure and Macro Index::
* Variable Index::
* Type Index::
--- The Detailed Node Listing ---
Gnudl prototype tutorial
* Elementary examples::
* Surface plots::
* Random numbers and probability distributions::
* Getting data from a file::
* Display of images::
* The plotting screen layout::
* Numerical analysis support::
* Operations on vector data::
* Saving postscript files and printing::
* Special plotting commands::
* The Cellular Automata package::
Reference manual
* Plot list management::
* Two dimensional plotting::
@end menu
@node Overview, Getting and installing the gnudl prototype, Top, Top
@chapter Overview
@ifset html
@end ifset
@noindent
Gnudl (GNU Data Language, pronounced @emph{NOODLE} or @emph{GUH NEW DLE}
or @emph{GUH NEW DEE EL}) is a high-level language and environent
designed to allow flexible and powerful manipulation and plotting of
data.
Gnudl is inspired by by the new availability of powerful free software
tools; most notably the GNU Extension Language guile.
@c Gnudl is inspired by the need for a free software tool as powerful as
@c IDL (the Interactive Data Language), but with a cleaner underlying
@c language.
NOTE: Gnudl is in prototype stage, and in many ways it is just a
throwaway project with good potential. This document describes the
original design and also gives a tutorial for the current prototype
release. The original design document does not bear much resemblance to
gnudl and its goals as they have evolved. But as I go along I am only
updating the tutorial.
Gnudl is also waiting for other technologies to become available. For
example, guile is still in prerelease, and ghostscript is not very good
for embedding.
@node Getting and installing the gnudl prototype, Gnudl prototype tutorial, Overview, Top
@chapter Getting and installing the gnudl prototype
Gnudl should run nicely on any platform where guile compiles. I do
development on linux, IRIX 5.3 and SunOS 4.1.4.
You can obtain gnudl from the anonymous ftp site
@ifinfo
@end ifinfo
nis-ftp.lanl.gov:pub/users/rosalia
@ifinfo
@end ifinfo
But you must first install @code{guile}, available from
@ifinfo
@end ifinfo
ftp.cygnus.com:pub/lord
@ifinfo
@end ifinfo
Gnudl version proto2.4 compiles with the guile-iii snapshot, but you
should take a look at Mark Galassi's notes on
@ifset html
@end ifset
learning libguile
@ifset html
@end ifset
since it describes how to solve some problems that come up when
installing guile-iii.
Users in the NIS division computers in Los Alamos can make a directory
for gnudl using the NIS division CVS repository:
@code{setenv CVSROOT /n/projects/cvs}
(or @code{export
CVSROOT=/n/projects/cvs} for bash users).
and then just type @code{cvs checkout gnudl/proto4}
@node Gnudl prototype tutorial, Reference manual, Getting and installing the gnudl prototype, Top
@chapter Gnudl prototype tutorial
In this tutorial section, the prompt @code{; ->} will indicate output from
gnudl (I will not reproduce most output here, just interesting output
lines); lines in the
@example
example typeface
@end example
without @code{; ->} are lines you should type. You can cut the example
sections from this manual and paste them into gnudl.
You can invoke gnudl by typing
@example
gnudl
@end example
Also: the demos in this tutorial are all stored in the file "demo.scm",
so you can type @code{(load "demo")} in gnudl and it will tell you how
you can run the individual demos.
@menu
* Elementary examples::
* Surface plots::
* Random numbers and probability distributions::
* Getting data from a file::
* Display of images::
* The plotting screen layout::
* Numerical analysis support::
* Operations on vector data::
* Saving postscript files and printing::
* Special plotting commands::
* The Cellular Automata package::
@end menu
@node Elementary examples, Surface plots, Gnudl prototype tutorial, Gnudl prototype tutorial
@section Elementary examples
@itemize @bullet
@item
Try creating an array with
@example
(define x (indgen 30))
; -> x
x
; -> #(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29)
@end example
@code{(indgen n)} returns a vector of @code{n} numbers, each set equal
to its index in the array. Note the @code{#(0 1 2 3 ...)} notation for
vectors used by gnudl:
@example
(define y #(3 2 9.1 4.4))
; -> y
y
; -> #(3 2 9.1 4.4)
@end example
@item
Now create an array that is more finely spaced:
@example
(define x (span -10 10 400))
; -> x
x
; -> #(-10 -9.95 -9.9 -9.85 -9.8 -9.75 -9.7 -9.65 -9.6 -9.55 -9.5 -9.45 - ...)
@end example
@code{(span min max n-points)} returns an array of @code{n-points}
numbers, evenly spaced, between @code{min} and @code{max}.
@item
Now create a second array @code{y} by applying the @code{sin} function
to the array @code{x}:
@example
(define y (sin x))
; -> y
y
; -> #(544.02111088937e-3 501.4051281792e-3 457.53589377532e-3 412.52305791709e-3 ...)
@end example
Notice how gnudl performs operations on entire vectors with a single
instruction by just invoking @code{(sin x)}.
@item
Let us see how easily @footnote{I only insert these advertising-style
comments because that is what people usually do in these tutorials :-)}
gnudl allows plotting of data arrays:
@example
(plot x y)
@end example
The @code{plot} instruction takes arrays of x-y data and plots them in
the graphics window.
@item
Now let us try a more complicated application of functions to arrays:
@example
(define y (times (sin (times x 8)) (exp (minus (divide x 3)))))
(plot x y)
@end example
@c @item
@c Sometimes you want to put up a plot of a function without having to
@c define an array to store the data. You can do this with the
@c @emph{lambda} construct in scheme @footnote{@emph{lambda} actually
@c exists in all dialects of lisp}:
@c @example
@c (plot x ((lambda (x) (times (sin (times x 8)) (exp (minus (divide x 2))))) x))
@c "showpage"
@c @end example
@c @code{lambda(x)} introduces an @emph{anonymous} function of @code{x},
@c which is then given by the following expression. This last example does
@c the same as the previous one, but it
@item
You might have noted that by default gnudl shows you 6 plots on a page:
two across and three down. You can change this with the @code{p-multi}
instruction:
@example
(p-multi 2 2)
(define x (span -4 4 200))
(plot x (sin x))
(plot x (exp x))
(plot x (tan x) '(yrange .(-10 . 10)))
(plot x (exp (divide 1 (plus 1 (times x x)))))
@end example
@end itemize
@node Surface plots, Random numbers and probability distributions, Elementary examples, Gnudl prototype tutorial
@section Surface plots
@cindex surface plots
@cindex contour plots
Gnudl provides, in the @emph{proto4} snapshot, a very elementary surface
plotting mechanism. If you have a height matrix @code{a}, which you
could form with
@smalllisp
(define a (make-matrix-index (lambda (x y)
(* (exp (- (/ (+ (* (- x 5) (- x 5))
(* (- y 5) (- y 5))) 30)))
(sin (/ x 2))))
20 20))
@end smalllisp
then you can render a surface wire mesh plot with hidden lines using:
@smalllisp
(surface a)
@end smalllisp
Notice that the height matrix @code{a} was formed with the
@code{make-matrix-index} procedure, which makes a matrix of the given
size (20x20), and fills it with the given procedure:
@smalllisp
(lambda (x y)
(* (exp (- (/ (+ (* (- x 5) (- x 5))
(* (- y 5) (- y 5))) 30)))
(sin (/ x 2))))
@end smalllisp
The procedure is applied to the matrix indices, and it scales down the x
and y values (since they are integers).
Right now there are no options for shifting the view angle (should be
easy to add), or for shading the wire mesh (probably harder). The
@code{surface} call is a trivial call to gnuplot's @code{splot} command,
with the hidden line removal option.
[NOTE: I am still looking for someone to take the lead on 3D work for
Gnudl. Talk to Mark Galassi (rosalia@@nis.lanl.gov) if you are
interested.]
You can also draw a contour plot of the same height matrix with
@smalllisp
(contour m)
@end smalllisp
If you want more contour levels (the default is 6), use
@smalllisp
(contour m n-levels)
@end smalllisp
Like @code{surface}, @code{contour} is just a pipe to ghostscript right
now, and pretty unsophisticated.
@node Random numbers and probability distributions, Getting data from a file, Surface plots, Gnudl prototype tutorial
@section Random numbers and probability distributions
Gnudl provides several routines that generate vectors filled with random
numbers satisfying various probability distributions.
@itemize @bullet
@item
Here's an example in which we plot a set of data distributed according
to @emph{uniform}, @emph{poisson} and @emph{gaussian} probability
distributions. The uniform distribution consists of numbers evenly
spread between 0 and 1. The poisson distribution of mean gamma
(@code{p(x) = (1/gamma) * exp(-gamma*x)}) is uniquely characterized by
its mean, and the standard deviation is equal to the mean. The gaussian
distribution is given by @code{p(x) = 1/(2*PI*sigma) *
exp(-x*x/(2*sigma*sigma))}, and is the classic ``bell shaped curve''.
@example
(p-multi 2 3)
(plot (rnd-vector 100))
(plot (rnd-vector 1000))
(plot (poisson-rnd-vector 100 2.2))
(plot (poisson-rnd-vector 1000 2.2))
(plot (gauss-rnd-vector 100 2.2 1.1 10))
(plot (gauss-rnd-vector 1000 2.2 1.1 10))
@end example
@item
Here we look at histograms of these probability distributions:
@example
(p-multi 3 2)
(plot (poisson-rnd-vector 100 2.1))
(plot (poisson-rnd-vector 1000 2.1))
(plot (histogram (poisson-rnd-vector 1000 2.1) 100))
(plot (gauss-rnd-vector 100 2.2 1.1 10))
(plot (gauss-rnd-vector 1000 2.2 1.1 10))
(plot (histogram (gauss-rnd-vector 1000 2.2 1.1 10) 100))
@end example
@end itemize
@node Getting data from a file, Display of images, Random numbers and probability distributions, Gnudl prototype tutorial
@section Getting data from a file
It is nice to create vectors online and play with them, but most of the
time experimental scientists will be reading in data from a file. We
provide a sample data file with the gnudl distribution, called
hete_sample.dat. This file contains actual data from the HETE satellite
experiment, organized as X and Y columns of numbers.
@itemize @bullet
@item
Try reading in the data and displaying it with
@example
(define th-data (read-xy "sample_data/hete_sample.dat"))
(p-multi 1 5) ; to see long narrow plots
(plot th-data)
(plot (car th-data) (smooth (cdr th-data) 7))
@end example
@item
The previous example showed how to read simple x-y data from a file.
Gnudl also provides a more general (i.e. slower) mechanism to read files
with columns of data. The @code{read-cols} procedure will read from a
file or a pipe if the filename ends with the @code{|} (pipe) symbol.
@code{read-cols} accepts a format string specifying how the columns
should be interpreted, and returns a list of vectors containing the
various columns of data.
@example
(define th-cols (read-cols "sample_data/hete_time_hist.dat" "%s %s %f %f"))
(define th-time (caddr th-cols))
(define th-counts (cadddr th-cols))
(p-multi 1 3)
(plot th-time th-counts)
(plot th-time (smooth th-counts 3))
(plot (histogram th-counts 300))
@end example
Notice how we discard the first two columns of data (read in with \%s
options) and are picking out using the next two columns of data with the
scheme @code{caddr} and @code{cadddr} procedures.
The file @code{hete.scm} shows a more complete example of data analysis
for the HETE data.
@end itemize
@node Display of images, The plotting screen layout, Getting data from a file, Gnudl prototype tutorial
@section Display of images
Gnudl has facilities for incorporating pre-made images in a variety of
formats into its plotting window. Here are some examples, based on two
GIF files supplied with the software:
@itemize @bullet
@item
Try reading in the data and displaying it with
@example
(p-multi 2 3)
(image-gif "t.gif")
(image-gif "l.gif")
@end example
@item
Gnudl will also display raytrace images by invoking @code{pov}, the
@emph{persistence of view} raytracer. If you have a @code{.pov} file
called @code{file.pov}, you can simply run
@example
(image-pov "file.pov")
@end example
We are considering to use POV raytrace rendering to render 3-dimensional
surface plots with shading and hidden lines.
@end itemize
@node The plotting screen layout, Numerical analysis support, Display of images, Gnudl prototype tutorial
@section The plotting screen layout
So far you have seen gnudl operate in a mode where it shows x columns
and y rows of plots. But gnudl can have very general plot screens of
all sorts of shapes and sizes: the @code{p-multi} procedure is simply a
short cut for more general plot-list management routines.
The underlying mechanism to add a plot to the @code{plot-list} is the
@code{plot-list-add} procedure. To demonstrate its use, try resetting
the plot list to only have a background plot:
@example
(plot-list-reinit)
@end example
now add a plot in the rectangle @code{(100 100 400 300}:
@example
(set! default-plot-list (plot-list-add default-plot-list '(100 100 400 300) '() #f '()))
@end example
The arguments @code{'() #f '()} specify, respectively, that there is no
``hook'' procedure to be invoked for this plot; that this plot is
@emph{not} to be skipped by @code{plot}, and that we start with no list
of postscript instructions.
Now add a second plot rectangle
@example
(set! default-plot-list (plot-list-add '(400 400 550 600) '() #f '()))
@end example
and reset the @code{current-plot} variable with
@example
(reset-current-plot!)
@end example
and refresh the screen by typing
@example
(refreshD)
@end example
Now try making some new plots:
@example
(define (new-func x) (times (cos x) (sin x)))
(define x-vals (span -10 10 500))
(plot (new-func x-vals))
(plot (sin x-vals) (new-func x-vals))
@end example
As you see, these plots went into the two rectangles defined with
@code{plot-list-add}.
There is another much more general routine for manipulating the
plot-list: @code{boxl->plot-listD} takes a @emph{box list} describing a
full screen layout and uses it to add several plots to the
@code{default-plot-list}. The box matrix is a list of nested lists that
describe how many columns and rows should be nested in the various areas
of the plot list.
Box lists are best explained by example; try pasting these in (notice
that new-func and x-vals are defined in previous examples):
@example
(boxl->plot-listD '(1))
(plot (times (sin (times 4 x-vals)) (exp (divide x-vals -4))))
@end example
@example
(boxl->plot-listD '(3 1 2))
(plot (times (sin (times 4 x-vals)) (exp (divide x-vals 3))))
(plot ((lambda (x) (times (sin (times 4 x)) (divide 1 (plus 1 (times x x))))) x-vals))
(plot ((lambda (x) (times (sin (times 4 x)) (divide 1 (plus 1 (times x x))))) x-vals))
(plot (times (sin (times 4 x-vals)) (exp (divide x-vals 3))))
(plot ((lambda (x) (times (sin (times 4 x)) (divide 1 (plus 1 (times x x))))) x-vals))
(plot (times (sin (times 4 x-vals)) (exp (divide x-vals 3))))
@end example
This will set the plot screen to have three plots in the top row, one in
the middle row and two on the bottom row, and show some sample data in
those plots.
Try some more complicated box matrices with nested sub-boxes, such as:
@example
(define boxl '( (2 1) (1 3) (1 (1 1)) 1 ((1 2) 1 1)) )
(boxl->plot-listD boxl)
@end example
and then make various plots in it (there are 16 plots in this box list).
@node Numerical analysis support, Operations on vector data, The plotting screen layout, Gnudl prototype tutorial
@section Numerical analysis support
Gnudl provides a large library (actually it's pretty small right now) of
numerical routines that can be applied to data or to functions. More
routines can be added by programming them in @emph{C} or @emph{scheme},
but in this tutorial I only describe the use of some analysis routines
that we provide with guile.
@itemize @bullet
@item
To look at some of what can be done with the @emph{discrete fourier
transform}, try the following:
@example
(define v (span -5 5 200))
(define scv (plus (plus (sin v) (sin (times 7 v))) (plus (cos v) (times (sin v) (cos v)))))
(define scv-hat (dft scv 1))
(define scv-hat-hat (dft scv-hat -1))
(p-multi 2 2)
(plot scv)
(plot scv-hat)
(plot scv-hat-hat)
@end example
(there is something weird here).
@end itemize
@node Operations on vector data, Saving postscript files and printing, Numerical analysis support, Gnudl prototype tutorial
@section Operations on vector data
You have noticed how arithmetic operations and transcendental functions
can all be applied to vector data as well as single numbers.
There two more operations which make vector manipulatio powerful and
flexible: the @emph{where} operator and @emph{subscripting with a list
of indices}.
@itemize @bullet
@item
The procedure @code{(where vec condition?)} returns a list of indices
for which @code{(condition? vec[i])} is true. For example, try:
@example
(define v #(1 10 2 4 12 39 0.8 -5 22.9))
(where v (lambda (z) (> z 2.5)))
; -> (1 3 4 5 8)
@end example
This tells us that the entries @code{v[1], v[3], v[4], v[5], v[8]} are
greater than 2.5.
@item
The primitive scheme procedure @code{vector-ref} has been enhanced in
gnudl so that it will take a list or a vector of indices as an argument.
This allows the @code{where} operator to become truly powerful.
Continuing where the previous example left off:
@example
(define v #(1 10 2 4 12 39 0.8 -5 22.9))
(define index-list (where v (lambda (z) (> z 2.5))))
(vector-ref v index-list)
; -> #(10 4 12 39 22.9)
@end example
@item
Here's a more interesting application:
@example
(p-multi 2 2)
(define pi 3.141592654)
(define v (span -7 7 1000))
(define sv (sin v))
(define chopped-ind-list (where sv (lambda (z) (< z 0.7))))
(define new-v (vector-ref v chopped-ind-list))
(define new-sv (vector-ref sv chopped-ind-list))
(plot new-v new-sv)
(define gap-ind-list (where v (lambda (z) (or (< z (- pi)) (> z (/ pi 2))))))
(plot (vector-ref sv gap-ind-list))
@end example
@end itemize
@node Saving postscript files and printing, Special plotting commands, Operations on vector data, Gnudl prototype tutorial
@section Saving postscript files and printing
Gnudl has a command @code{(ps-snapshot plot-list file-name)} for saving
postscript
@node Special plotting commands, The Cellular Automata package, Saving postscript files and printing, Gnudl prototype tutorial
@section Special plotting commands
Apart from the standard "x-y plotting" possibilities, gnudl also allows
you to splatter arbitrary shapes onto into a plot rectangle. In this
mode the coordinates of the objects you draw always range from (0, 0) to
(1, 1).
@example
(p-multi 3 3)
(add-rect 0 0 0.5 0.5 'blue)
(add-rectR 0 0.5 0.6 0.6 'red) ; the R means you refresh after drawing
(add-segmentR 0 0 1 1 'green)
(add-boxR 0.3 0.3 0.4 0.4 'purple)
@end example
Another example shows the use of bar charts:
@example
(p-multi 1 10)
(bar-chart-flat (span 0 20 20)) ; all rectangles are the same height
(bar-chart (span 0 20 20)) ; height is proportional to the value
(bar-chart-flat (sin (span 0 200 200)))
(bar-chart (span -10 10 200))
(bar-chart (times 30 (sin (span -10 10 200))))
(bar-chart (times 30 (sin (span -10 10 200))) 'red)
;; now do some bar charts of histograms
(define b (span -2 4 2000))
(define esb (times (exp (divide b (- 2))) (sin (times b 8))))
(define hesb500 (histogram esb 500))
(bar-chart (cdr hesb500)) ; the histogram puts the actual data in the cdr
(bar-chart (cdr hesb500) 'blue)
(define hesb250 (histogram esb 250))
(bar-chart (cdr hesb250)) ; the histogram puts the actual data in the cdr
(bar-chart (cdr hesb250) 'blue)
@end example
@node The Cellular Automata package, , Special plotting commands, Gnudl prototype tutorial
@section The Cellular Automata package
Mark Galassi wrote a package which allows some displaying of cellular
automata as well as displaying results from his ga_ca project. Take a
look at the file @code{ca.scm} to see how special-plot and other
constructs are used together to make vignettes of many types of data.
@node Reference manual, Concept Index, Gnudl prototype tutorial, Top
@chapter Reference manual
The reference manual documents the procedures and global variables that
the user can and should access.
This applies to the prototype, and is incomplete.
Routines meant for internal use only should be documented in the design
document.
@menu
* Plot list management::
* Two dimensional plotting::
@end menu
@node Plot list management, Two dimensional plotting, Reference manual, Reference manual
@section Plot list management
@cindex plot list
The @emph{plot list} is a Gnudl construct. It is a list of all the
individual plot rectangles available in a given postscript interpreter.
@deftp {Data type} plot-entry rect hook skip-flag ps-code
Each entry in the plot list contains:
@itemize @bullet
@item
a rectangle specifying where it gets drawn
@item
a hook procedure @code{hook} that should be invoked before this entry is
redrawn (currently unused)
@item
a boolean flag @var{skip-flag} which specifies if it should be drawn
during a refresh. (this is usuall @code{#f} for the root entry, but
@code{#t} for normal plots)
@item
a vector of postscript code strings, which contains the instructions to
draw that plot.
@end itemize
@end deftp
@deftp {Data type} plot-list [entry @dots{}]
The plot list is the list of all plot entries.
@end deftp
@deffn {Plot list management} showpage
Forces the postscript interpreter to process a @code{showpage} command.
@end deffn
@deffn {Plot list management} flushpage
Sends a @code{flushpage} command to the postscript interpreter. This is
usually ignored by printers, and instead recognized by interpreters like
ghostscript: it means "draw everything you have so far".
@end deffn
@deffn {Plot list management} clear [args @dots{}]
Clears out the plot list for all the plot numbers specified in the
@var{args}.
@end deffn
@node Two dimensional plotting, , Plot list management, Reference manual
@section Two dimensional plotting
@cindex xyplot
@cindex x-y plot
@cindex 2D plot
@deffn {2D plots} plot [y | x y | x-y-alist] [args @dots{}]
Simple x-y plotting.
@end deffn
@node Concept Index, Procedure and Macro Index, Reference manual, Top
@unnumbered Concept Index
@printindex cp
@node Procedure and Macro Index, Variable Index, Concept Index, Top
@unnumbered Procedure and Macro Index
This is an alphabetical list of all the procedures and macros in Gnudl.
@printindex fn
@node Variable Index, Type Index, Procedure and Macro Index, Top
@unnumbered Variable Index
This is an alphabetical list of all the global variables in SCM.
@printindex vr
@node Type Index, , Variable Index, Top
@unnumbered Type Index
This is an alphabetical list of all the data types in Gnudl.
@printindex tp
@contents
@bye