Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lamp/cs206
  • bwermeil/cs206-2020
  • zabifade/cs206-2020
  • cauderan/cs206-2020
  • malonga/cs206-2020
  • dumoncel/cs206
  • bounekhe/cs206
  • bergerault/cs206
  • flealsan/cs206
  • hsu/cs206
  • mouchel/cs206
  • vebraun/cs206
  • vcanard/cs206
  • ybelghmi/cs206
  • belghmi/cs206
  • bousbina/cs206
  • waked/cs206
  • gtagemou/cs206
  • arahmoun/cs206
  • elhachem/cs206
  • benrahha/cs206
  • benslima/cs206
22 results
Show changes
Showing
with 0 additions and 2422 deletions
labs/images/sbt-test-error.png

44.4 KiB

labs/images/sum-def.png

6.75 KiB

labs/images/syntax-error-bug.png

47.3 KiB

labs/images/test-source.png

19 KiB

labs/images/warnings-errors.png

1.8 KiB

# Parallel Box Blur Filter
Use the following commands to make a fresh clone of your repository:
```
git clone -b scalashop git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-scalashop
```
## Useful links
* [A guide to the Scala parallel collections](https://docs.scala-lang.org/overviews/parallel-collections/overview.html)
* [The API documentation of the Scala parallel collections](https://www.javadoc.io/doc/org.scala-lang.modules/scala-parallel-collections_2.13/latest/scala/collection/index.html)
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Setup scalashop
In this assignment, we will implement a box blur filter, used in applications
like Adobe® PhotoShop® to blur images.
For the purposes of this assignment, a filter is an algorithm that takes an
input image and transforms it in some way into an output image.
The box blur filter outputs an image in which every pixel has an average value
of the surrounding pixels from the original image.
The box blur filter is an example of an *embarrassingly parallel* problem -- no
or very little effort is required to separate it into parallel tasks.
Every pixel of the output image can be computed independently of the other
pixels, and in parallel.
We will proceed in four steps. First, we will implement the kernel of the box
blur filter, a method used to compute a single pixel of the output image.
Then we will implement two versions of the parallel box blur, and measure the
performance difference.
Finally, we will try out our parallel box blur implementations on real images,
using ScalaShop -- the image manipulation tool that would impress even
the Adobe® folks.
By the time you are finished with this assignment, you will:
- understand how the box blur filter works
- be able to recognize embarrassingly parallel problems
- know how to measure the performance of a parallel algorithm
- see how to agglomerate parallel computations into batches
- better understand how memory access patterns affect performance of parallel
algorithms
## Preliminaries
Before we begin, we need to cover some basic data types and helper methods.
These utilities have already been implemented in the package object (in the file `package.scala`) for this
exercise.
First, we will use the `RGBA` type to refer to the value of an image pixel.
We will limit ourselves to 32-bit pixel depth images, so we define `RGBA` to
be equal to the 32-bit integer type:
```scala
type RGBA = Int
```
Why do we call this type `RGBA`?
This is because each pixel value is composed from 4 components - red, green,
blue and alpha, where alpha denotes the amount of transparency in the
respective pixel.
These components are referred to as *channels*.
The value of each channel is at least 0 and at most 255.
We can extract the red, green, blue and alpha channel using the following
utility methods, which use bit masking and bit shifting:
```scala
def red(c: RGBA): Int = (0xff000000 & c) >>> 24
def green(c: RGBA): Int = (0x00ff0000 & c) >>> 16
def blue(c: RGBA): Int = (0x0000ff00 & c) >>> 8
def alpha(c: RGBA): Int = (0x000000ff & c) >>> 0
```
Similarly, given the values of the four channels, we can obtain the pixel value
like this:
```scala
def rgba(r: Int, g: Int, b: Int, a: Int): RGBA =
(r << 24) | (g << 16) | (b << 8) | (a << 0)
```
Now that we know how to manipulate individual pixels, we can define our image
type `Img`:
```scala
class Img(val width: Int, val height: Int) {
private val data = new Array[RGBA](width * height)
def apply(x: Int, y: Int): RGBA = data(y * width + x)
def update(x: Int, y: Int, c: RGBA): Unit = data(y * width + x) = c
}
```
The image is a two-dimensional entity -- to refer to a pixel in an image, we
need to specify an `x` and `y` component.
On the other hand, the underlying memory model is one-dimensional -- a single
offset value specifies the position in the array.
When we store the image into memory, we need to map between the
two-dimensional image model and the one-dimensional memory model.
We will do this by storing consecutive rows of the image one after another, as
illustrated in the following figure:
![mapping](mapping.png)
Thus, the offset of a pixel at coordinates `x` and `y`, is equal to
`y * width + x`, where `width` is the number of pixels in a single row.
Although there are other mappings used in practice, we will restrict to this
simple mapping throughout the exercise.
To ensure that the value of the `x` and `y` coordinates are confined to the
dimensions of the image, namely width and height, occasionally we have to call
the `clamp` method:
```scala
def clamp(v: Int, min: Int, max: Int): Int
```
Finally, we will use the `task` construct to start parallel computations.
Every `task` construct invocation returns an object on which we can call the
`join` method.
Calling the `join` method blocks the execution of the program until the parallel
computation ends.
Below, we calculate the expression `1 + 1` in parallel to the main program:
```scala
val computation = task {
val result = 1 + 1
println("Done!")
result
}
println("About to wait for some heavy calculation...")
computation.join()
```
We now have everything we need to start implementing the parallel box filter.
## The Box Blur Filter Kernel
In the first part of the assignment, we will implement the box blur filter
kernel method.
A kernel is a method that computes the resulting value of a single pixel.
The kernel method is typically computationally cheap and is not worth
parallelizing its implementation.
However, as we will later see, we can apply the same kernel method to different
pixels in parallel.
![kernel](kernel.png)
The `boxBlurKernel` method takes the source image `src`, coordinates `x` and `y`
of the pixel, and the `radius` of the blur.
It returns the resulting average value of the surrounding pixels.
We compute the average value by separating the pixel into four channels,
computing the average of each of the channels,
and using the four average values to produce the final pixel value.
In the previous figure, the `radius` parameter is equal to `1` and the average
is computed from `9` pixels.
You can find its signature in the package object of this assignment:
def boxBlurKernel(src: Img, x: Int, y: Int, radius: Int): RGBA
Implement the `boxBlurKernel` method.
Use two nested `while`-loops.
Make sure that the pixels at the image edges are affected only by the
pixels inside the image (hint: use the `clamp` method from the package object).
## Vertical Stripping Box Blur
We can now implement the parallel box blur filter.
Note that the `boxBlurKernel` method is relatively inexpensive.
Executing `boxBlurKernel` might be much faster than starting a parallel
computation, so having a separate parallel computation for the value of each
pixel would be far too expensive.
For this reason, we want to batch together many `boxBlurKernel` calls, and have
a smaller number of parallel tasks.
This is sometimes referred to as *agglomeration*, and is present in many
parallel algorithm implementations.
There are many different ways we can do agglomeration for the parallel box blur.
One is to divide the image into a fixed number of equally wide vertical strips.
For each strip, we start a parallel task, and wait for their completion.
Within each strip, we traverse the pixels going from the top to the bottom of
the image, as illustrated in the following figure:
![stripping](vertical.png)
We start by implementing the sequential `blur` method in the
`VerticalBoxBlur.scala` source file, which takes the source image `src`, the
destination image `dst`, the starting (included) and ending (excluded) `x` coordinates
(i.e, column indices) of the strip, called `from` and `end`, and the blur `radius`.
The `blur` method blurs the pixels from the `src` image and writes them to the
`dst` image:
```scala
def blur(src: Img, dst: Img, from: Int, end: Int, radius: Int): Unit
```
The implementation of `blur` should rely on the previously defined `boxBlurKernel`.
Then, implement the `parBlur` method, which divides the image into `numTasks` vertical strips and runs each task in parallel:
```scala
def parBlur(src: Img, dst: Img, numTasks: Int, radius: Int): Unit
```
Use Scala ranges to create a list of splitting points
(hint: use the `by` method on ranges).
Then use collection combinators on the list of splitting points to create a list
of start and end tuples, one for each strip
(hint: use the `zip` and `tail` methods).
Finally, use the `task` construct to start a parallel task for each strip,
and then call `join` on each task to wait for its completion.
### Benchmarking VerticalBoxBlur
Before running the benchmarking program, go to the top of `VerticalBoxBlur.scala`
and replace the line:
```scala
Key.verbose -> true
```
by:
```scala
Key.verbose -> false
```
Now you can run the `VerticalBoxBlur` program with the following sbt command:
```
> runMain scalashop.VerticalBoxBlurRunner
```
Change the number of tasks and the radius parameter.
How does the performance change?
## Horizontal Stripping Box Blur
In this part of the exercise we will pick an alternative agglomeration for the
box blur algorithm.
Instead of dividing the image into vertical strips, we will divide it into
horizontal strips in a similar way:
![stripping](horizontal.png)
We implement the two methods, `blur` and `parBlur` in a similar way as before:
```scala
def blur(src: Img, dst: Img, from: Int, end: Int, radius: Int): Unit
def parBlur(src: Img, dst: Img, numTasks: Int, radius: Int): Unit
```
Note that the arguments `from` (included) and `end` (excluded) this time denote the values of the
`y` coordinate (i.e, row indices), and that we traverse the pixels left-to-right within each strip.
### Benchmarking HorizontalBoxBlur
Before running the benchmarking program, go to the top of `HorizontalBoxBlur.scala`
and replace the line:
```scala
Key.verbose -> true
```
by:
```scala
Key.verbose -> false
```
Now you can now run the `HorizontalBoxBlur` program from sbt with:
```
> runMain scalashop.HorizontalBoxBlurRunner
```
If you implemented the two blur versions correctly, you should observe that the
horizontal stripping is slightly faster.
This is because the pixel traversal order visits the pixels which are closer
together in memory (remember the mapping between the pixel coordinates and the
memory addresses). As a result, each core can reuse some of the pixels that it
fetched from the memory during the previous invocation of `boxBlurKernel`.
The processor cores spend less time fetching pixels from memory and lower the
pressure on the memory bus.
## ScalaShop
Now we have everything we need to start ScalaShop, from sbt run:
```
> runMain scalashop.ScalaShop
```
Change the blur implementation, parallelism level and blur radius, and study the
effect your changes have on performance.
* Which of the two blur implementations is faster?
* For which values of the `radius` parameter is the difference most significant?
* Why?
* What if we split the image into rectangles? Will this be faster?
*"Adobe" and "Photoshop" are either registered trademarks or trademarks of Adobe
Systems Incorporated in the United States and/or other countries.*
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\scalashop\kernel.png"
inkscape:export-xdpi="16.044189"
inkscape:export-ydpi="16.044189"
sodipodi:docname="avg.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13978"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13980" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13264"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13266" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker11620"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path11622" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11430"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11432"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11220"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11222"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8212" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8122"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path8124"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8004"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8006" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7904"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7906" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7810"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7812" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5934"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5936" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.55904437"
inkscape:cx="498.91476"
inkscape:cy="485.13131"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 569.48922,182.84133 0,536.93787"
id="path3342"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 476.55518,182.84133 0,536.93787"
id="path3346"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 390.18714,182.84133 0,536.93787"
id="path3350"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3352"
d="m 304.82925,182.84133 0,536.93787"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,268.75392 -419.48108,0"
id="path3354"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3356"
d="m 630.8714,359.12582 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,454.81371 -419.48108,0"
id="path3358"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3360"
d="m 630.8714,550.05861 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,649.73349 -419.48108,0"
id="path3362"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 213.41044,182.84133 0,536.93787"
id="path3364"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="643.29187"
y="549.94373"
id="text11422"
sodipodi:linespacing="125%"
transform="scale(1.0677679,0.93653312)"><tspan
sodipodi:role="line"
id="tspan11424"
x="643.29187"
y="549.94373"
style="font-size:65.55731964px">. . .</tspan></text>
<text
sodipodi:linespacing="125%"
id="text11426"
y="-384.24774"
x="803.21533"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0,0.93653312,-1.0677679,0,0,0)"><tspan
style="font-size:65.55731964px"
y="-384.24774"
x="803.21533"
id="tspan11428"
sodipodi:role="line">. . .</tspan></text>
<rect
style="fill:#000000;fill-opacity:0.85806454;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3403"
width="87.649574"
height="97.272865"
x="389.95117"
y="453.85275" />
<rect
y="358.1488"
x="304.09036"
height="97.272865"
width="87.649574"
id="rect6045"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6047"
width="87.649574"
height="97.272865"
x="389.95117"
y="358.1488" />
<rect
y="358.1488"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6049"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6051"
width="87.649574"
height="97.272865"
x="304.09036"
y="453.85275" />
<rect
y="453.85275"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6053"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6055"
width="87.649574"
height="97.272865"
x="479.3895"
y="551.12567" />
<rect
y="551.12567"
x="388.16238"
height="97.272865"
width="87.649574"
id="rect6057"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6059"
width="87.649574"
height="97.272865"
x="302.30157"
y="551.12567" />
<path
inkscape:connector-curvature="0"
id="path6065"
d="m 630.8714,182.89311 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\scalashop\horizontal.png"
inkscape:export-xdpi="32.263706"
inkscape:export-ydpi="32.263706"
sodipodi:docname="horiz.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13978"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13980" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13264"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13266" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker11620"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path11622" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11430"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11432"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11220"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11222"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8212" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8122"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path8124"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8004"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8006" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7904"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7906" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7810"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7812" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5934"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5936" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.55904437"
inkscape:cx="498.91476"
inkscape:cy="485.13131"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 569.48922,182.84133 0,536.93787"
id="path3342"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 476.55518,182.84133 0,536.93787"
id="path3346"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 390.18714,182.84133 0,536.93787"
id="path3350"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3352"
d="m 304.82925,182.84133 0,536.93787"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,268.75392 -419.48108,0"
id="path3354"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3356"
d="m 630.8714,359.12582 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,454.81371 -419.48108,0"
id="path3358"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3360"
d="m 630.8714,550.05861 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,649.73349 -419.48108,0"
id="path3362"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 213.41044,182.84133 0,536.93787"
id="path3364"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="643.29187"
y="549.94373"
id="text11422"
sodipodi:linespacing="125%"
transform="scale(1.0677679,0.93653312)"><tspan
sodipodi:role="line"
id="tspan11424"
x="643.29187"
y="549.94373"
style="font-size:65.55731964px">. . .</tspan></text>
<text
sodipodi:linespacing="125%"
id="text11426"
y="-384.24774"
x="803.21533"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0,0.93653312,-1.0677679,0,0,0)"><tspan
style="font-size:65.55731964px"
y="-384.24774"
x="803.21533"
id="tspan11428"
sodipodi:role="line">. . .</tspan></text>
<rect
style="fill:#000000;fill-opacity:0.85806454;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3403"
width="87.649574"
height="97.272865"
x="389.95117"
y="453.85275" />
<rect
y="358.1488"
x="304.09036"
height="97.272865"
width="87.649574"
id="rect6045"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6047"
width="87.649574"
height="97.272865"
x="389.95117"
y="358.1488" />
<rect
y="358.1488"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6049"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6051"
width="87.649574"
height="97.272865"
x="304.09036"
y="453.85275" />
<rect
y="453.85275"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6053"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6055"
width="87.649574"
height="97.272865"
x="479.3895"
y="551.12567" />
<rect
y="551.12567"
x="388.16238"
height="97.272865"
width="87.649574"
id="rect6057"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6059"
width="87.649574"
height="97.272865"
x="302.30157"
y="551.12567" />
<path
inkscape:connector-curvature="0"
id="path6065"
d="m 630.8714,182.89311 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>
labs/lab1-parallel-box-blur-filter/horizontal.png

6.25 KiB

labs/lab1-parallel-box-blur-filter/kernel.png

872 B

labs/lab1-parallel-box-blur-filter/mapping.png

8.23 KiB

This diff is collapsed.
This diff is collapsed.
labs/lab1-parallel-box-blur-filter/vertical.png

7.31 KiB

# Tools Setup
## Note
We recommend using Linux or macOS for this course, we also support Windows but
typically people have more trouble getting everything working correctly on
Windows and it's harder for us to help them since we don't use Windows
ourselves.
**On Windows, if your username has spaces or special characters in it, the IDE might not
work properly. Please create a new user with a username containing only letters.**
# Step 1: Create an account on gitlab.epfl.ch
If you haven't already [log into gitlab](https://gitlab.epfl.ch/users/sign_in)
and fill in [this table](https://docs.google.com/spreadsheets/d/1rcq_UMgR6bAH-iK1L2I6WoClZtCqUoIOLqQO3NJKdgg) with your GASPAR and SCIPER number to initialize your GitLab repository for the course. Do this as soon as possible because it will take some time between the account creation and the lab submission system working for your account.
## Step 2: Installing the Java Development Kit (JDK) and sbt via coursier
We will use coursier to install the correct version of
Java as well as the sbt build tool:
### On Linux
```shell
curl -fLo cs https://git.io/coursier-cli-linux
```
```shell
chmod +x cs
```
```shell
./cs setup -y --jvm 8 --apps cs,sbt
```
Please reboot after this point.
### On macOS
First, install the Homebrew package manager:
```shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```
Use Homebrew to install coursier:
```scala
brew install coursier/formulas/coursier
```
```shell
[ -f ~/.bash_profile ] && sudo chmod 0666 ~/.bash_profile
```
```shell
cs setup -y --jvm 8 --apps sbt
```
### On Windows
Download and install the [Visual C++ 2010 SP1 Redistributable Package](https://www.microsoft.com/en-us/download/details.aspx?id=13523).
Open `cmd.exe` (and not powershell)
First, make sure that you are not in the `System32` directory, instead you
should be in `C:\Users\yourusername`. If you are in `System32` you will need to
change directory to your user directory every time you start a terminal by
running:
```shell
cd %USERPROFILE%
```
Now assuming that you're in the correct directory you can run:
```shell
bitsadmin /transfer cs-cli https://git.io/coursier-cli-windows-exe "%cd%\cs.exe"
```
```shell
.\cs setup -y --jvm 8 --apps cs,sbt
```
(This command might cause your anti-virus to misidentify cs.exe as a virus,
please override that, that might require temporarily turning off your anti-virus
during this setup).
If this command fails with `Error running powershell script`, use the following
alternative instructions (if the command didn't fail, continue to the next
step):
1. Run `.\cs setup --jvm 8 --apps cs,sbt`, at every question answer "n" and
press Enter.
2. The last question should look like "Should we add `C:\...\bin` to your PATH?",
please copy the `C:\...\bin` part here.
3. Edit the Path environment variable and paste the path you just copied to it, see
https://www.architectryan.com/2018/08/31/how-to-change-environment-variables-on-windows-10/
and make sure the path you're adding is the first entry in the Path environment
variable.
4. Start a **new** cmd.exe and continue with the rest of the instructions
**In case of errors please ask on Discord or Gitlab issues for help, but don't
try to run commands as Administrator as this will likely cause further issues!**
## Step 5: Installing git
git is a version control system.
### On Ubuntu and Debian
```shell
sudo apt update && sudo apt install git
```
### On macOS
```shell
brew install git
```
### On Windows
Download and install git from [https://git-scm.com/downloads](https://git-scm.com/downloads).
Once git is installed, open a **new** terminal and run:
```shell
git config --global core.autocrlf false
```
If this command worked it will not print anything.
## Step 6: Installing Code
Visual Studio Code is the IDE we strongly recommend using for this class (you are free to use any editor you want, but we won't don't have the resources to help you configure it for Scala).
### On Linux
See [https://code.visualstudio.com/docs/setup/linux](https://code.visualstudio.com/docs/setup/linux)
### On macOS
```shell
brew cask install visual-studio-code
```
### On Windows
See [https://code.visualstudio.com/docs/setup/windows](https://code.visualstudio.com/docs/setup/windows).
Make sure that the checkbox "Add to PATH (available after restart)" in the
installer is checked.
## Step 7: Installing the Scala support for Code
Open a **new** terminal and run:
```scala
code --install-extension lampepfl.dotty-syntax
```
If you're on Windows and the command is not found, try closing and restarting
the terminal, if that doesn't work
## Step 8: Generate a public/private SSH key pair
To submit labs, you will need an SSH key. If you don't already have one, here's how to generate it:
### Step 8.1: Installing OpenSSH
#### On Ubuntu and Debian
```shell
sudo apt update && sudo apt install openssh-client
```
#### On macOS
Nothing to do, OpenSSH is pre-installed
#### On Windows
Follow the instructions under "Enable OpenSSH Client in Windows 10" on
[https://winaero.com/blog/enable-openssh-client-windows-10/](https://winaero.com/blog/enable-openssh-client-windows-10/)
### Step 8.2: Generating the key pair
Open a **new** terminal and run:
```shell
ssh-keygen -t rsa -b 4096 -C "youremail@example.com"
```
The command will then ask for a location, which you can leave as the default. It will then also ask for a passphrase to encrypt your private key, which you may leave empty. If you don't, make sure to remember your passphrase!
### Adding your public key on Gitlab
To be able to push your code, you'll need to add the public part of your key on Gitlab:
- Go to [gitlab.epfl.ch](https://gitlab.epfl.ch), log in with your EPFL account
- Go to [gitlab.epfl.ch/profile/keys](https://gitlab.epfl.ch/profile/keys) and copy-paste the content of the `id_rsa.pub` file created by the `ssh-keygen` command you just ran (when the command was ran it printed the location where this file was saved).
- Press `Add key`
## Step 9: Follow the example lab
Time to do the [example lab](example-lab.md)!
File deleted
File deleted
File deleted
File deleted
File deleted