Commit 466ee467 authored by totara-thib's avatar totara-thib
Browse files

chore: remove old mkdocs website

parent d8d7bdea
Loading
Loading
Loading
Loading

docs/concept.md

deleted100644 → 0
+0 −30
Original line number Diff line number Diff line
---
title: Collaborative hub of CI/CD jobs ready to use
description: Discover R2Devops and learn about the goal of the hub. See how CI/CD implementation can be simplified using this platform!
---

# Concept

The **R2Devops hub** is a collaborative [Hub](/r2bulary/#hub) of CI & CD
**ready to use** jobs which helps you to easily build powerful Pipelines for your projects.

!!! info
    Currently, the hub is focused to provide only **Gitlab 🦊** jobs. We plan
    to support more CI/CD platforms in the future.

Each Job of the hub can be used independently to create fully **customized pipelines.**
You can use them for any kind of software and deployment type. Each job can be
customized through configuration.

<a alt="Use the hub" href="/use-the-hub">
    <button class="md-button border-radius-10 md-button-center" >
        I want to use the hub <img alt="" class="heart" src="../images/rocket.png">
    </button>
</a>


## Overview

![hub overview](images/g2shub_mvp.jpg)

--8<-- "includes/abbreviations.md"

docs/create-update-job.md

deleted100644 → 0
+0 −385
Original line number Diff line number Diff line
---
title: Contribution | Creating or updating a job 
description: See all the steps to contribute in R2Devops, by creating or updating a job! You’ll be guided in contribution thanks to guidelines and best practices
---

# Create or update a job

This page describes how to create or update a job in the
[R2Devops/hub](https://gitlab.com/r2devops/hub/) repository. It's the guide!

!!! info
      In order to contribute efficiently, we recommend you to know the following topics:

      * [x] [R2Devops hub job structure](/job-structure/)
      * [x] [GitLab CI/CD](https://docs.gitlab.com/ee/ci/){:target=blank}

!!! tip
      If you are hesitant about what job to create/update, you can get inspired by our pre-made job issues on Gitlab under the label `Easy first step`, click [here](https://gitlab.com/r2devops/hub/-/issues?label_name%5B%5D=Contributing%3A%3AEasy+first+step){:target=blank} to see.  
     
## Contributing workflow

Follow the 3 simple steps below to contribute efficiently in the hub. You'll see, it will all go smoothly! 👇

### 🍴 Step 1: Fork!

The first step is to create your own copy of [`r2devops/hub`](https://gitlab.com/r2devops/hub/) repository, to be
able to work on it before merging your update in the real project.

1. Go on the fork page creation: [`r2devops/hub`](https://gitlab.com/r2devops/hub/-/forks/new).
1. Select the group in which you want to create the fork.

### 💻 Step 2: Work in your fork

!!! error "Do not alter **`.gitlab-ci.yml`**"
    To leverage the R2Devops validity and security checks on your job, do not
    update the CI/CD configuration file in your fork (`.gitlab-ci.yml` file).

    If you alter it, we will not be able to merge your job in `r2devops/hub`
    repository (yes, what a shame, after all your hard work...). 😕

1. If you want to create a new job:
      1. Make sure that you have NPM installed, more about that [here](https://nodejs.org/en/download/){:target=blank}
      1. Install the package `Cookicutter` by executing this command:
        ```shell
        npm install -g cookiecutter
        ```
      1. In the `hub` folder, run this command and input the necessary information:
        ```shell
        npx cookiecutter
        ```

    !!! info
        Alternatively, you can do the last steps manually by creating a new directory dedicated to your job in `jobs/` folder if you want to add a new job. You can use the [job template](https://gitlab.com/r2devops/hub/-/tree/latest/tools/job_template/r2_jobname) as a starting point. If you want to modify an existing job, you don't have to create a new directory.

1. Be sure to respect the rules we describe in this guide.
1. Do not update the CI/CD configuration file `.gitlab-ci.yml`.
1. Test your job and ensure it works!

### 🚀 Step 3: Merge request

!!! note "1. Ensure that the last pipeline in your fork passed before going further (check it in `CI/CD > Pipelines`)"

??? note "2. Create a new merge request in your fork (`Merge Requests > New merge request`) 👇"
    1. Select branches
        * As `Source branch`, select the branch in which you have worked in
        your fork (usually `latest`).
        * As `Target branch`, select latest in `r2devops/hub` project.
        * Click on `Compare branches and continue`.
    1. In `Title`: add short description of your contribution.
    1. In `Description`:
        * Do not remove the default content, this is the Definition of Done (DoD)
        * Add a description of your contribution with all information
          permitting us to understand what you have done and why. If your
          contribution is related to an existing issue, add a reference:
            ```md
            ## Contribution
            Addition of a new job permitting to build golang binaries. Issue
            related: r2devops/hub#945

            ## Definition of Done
            [...]
            ```
        * Add a link to your job running and working in a publicly accessible
          Gitlab project.
    1. If you want to allow commits from hub maintainers inside your fork
       branch, check the box
       [`Contribution`](https://docs.gitlab.com/ee/user/project/merge_requests/allow_collaboration.html)
        (this isn't available for protected branches like `latest`).

!!! note "3. In the newly created MR, ensure to fulfill all the steps of the job's Definition of Done, and tick the related boxes"

Thanks a lot for your contribution 😀🎉 !

Now, we will take a look at your work and merge it if everything is ok.
👀 Meanwhile, you can join our [Discord community](https://discord.r2devops.io/?utm_medium=website&utm_source=r2devops) to tell us more about your fresh new contribution.
We love talking with our contributors and users!

## Guidelines (Required)

!!! warning
    Following these guidelines is required to contribute to
    [R2Devops/hub](https://gitlab.com/r2devops/hub/) repository.

Each jobs must be compliant with these following rules:

* [ ] Be compliant with the [job structure](/job-structure/).
* [ ] Use the `image` option. The goal is to provide **plug and play** jobs working
  in any environments thanks to containers.
* [ ] Use **fixed tag** for docker image and any external tool used inside the
  job. **It shouldn't be `latest` or any tag/version that will be overwritten**.
* [ ] Use only resource with license compatible with the job license, and
  permitting anyone to use it.
* [ ] Pass our Continuous Integration pipeline, which includes security check
  jobs (the pipeline will be run automatically inside your fork 🎢).
* [ ] Be compliant with [our job definition](/r2bulary/#job).


## Best practices (Optional)

!!! info
    Following these best practices is recommended to contribute to
    [R2Devops/hub](https://gitlab.com/r2devops/hub/) repository.

### 🤖 Job definition

#### 🧮 Variables

In order to be customizable, your job should use `variables`. This section
allows to define environment variables, usable by the job script.

!!! tip
    Set default values to your variables to reflect the most common use-case. 
    With this, your job will remain plug-and-play while being customizable!

Example of relevant situation to use variable:

* File name.
* Path to files or folders.
* Any options/parameters used by the job.
* Enable or disable job features.
* Version of tools retrieved during the job.

Here is an example for `newman` job 👇

=== "Job content"

    ```yaml
    newman:
        image: node:15.4.0
        stage: dynamic_tests
        variables:
            NEWMAN_COLLECTION: "postman_collection.json"
            NEWMAN_GLOBALS_FILE: ""
            NEWMAN_ADDITIONAL_OPTIONS: ""
            NEWMAN_JUNIT_REPORT: "newman-report.xml"
            NEWMAN_FAIL_ON_ERROR: "true"
            NEWMAN_ITERATIONS_NUMBER: "2"
        script:
            - npm install -g newman newman-reporter-junitfull
            - if [[ ! -z ${NEWMAN_GLOBALS_FILE} ]]; then
            -   NEWMAN_ADDITIONAL_OPTIONS+=" -g ${NEWMAN_GLOBALS_FILE}"
            - fi
            - if [[ ! ${NEWMAN_FAIL_ON_ERROR} == "true" ]]; then
            -   NEWMAN_ADDITIONAL_OPTIONS+=" --suppress-exit-code"
            - fi
            - newman run ${NEWMAN_COLLECTION} -r cli,junitfull
              --reporter-junitfull-export ${NEWMAN_JUNIT_REPORT}
              -n ${NEWMAN_ITERATIONS_NUMBER} ${NEWMAN_ADDITIONAL_OPTIONS}
        artifacts:
            [...]
    ```

=== "Variables"

    | Name | Description | Default |
    | ---- | ----------- | ------- |
    | `NEWMAN_COLLECTION` <img width=105/> | Name of the Postman collection <img width=175/> | `postman_collection.json` <img width=100/> |
    | `NEWMAN_GLOBALS_FILE` | Name of the Postman globals file for [variables](https://learning.postman.com/docs/sending-requests/variables/) | ` ` |
    | `NEWMAN_ADDITIONAL_OPTIONS` | Other [options](https://learning.postman.com/docs/running-collections/using-newman-cli/command-line-integration-with-newman/) you may want to use with Newman | ` ` |
    | `NEWMAN_FAIL_ON_ERROR` | Fail job on a request/test error | `true` |
    | `NEWMAN_ITERATIONS_NUMBER` | Number of Newman iterations to run (see [documentation](https://learning.postman.com/docs/running-collections/using-newman-cli/command-line-integration-with-newman/#misc)) | `2` |

#### 🐳 Docker image

!!! info
    As described in [our guidelines](#guidelines), all jobs are run inside a
    container instance, so they must specify the Docker image to use. Depending on
    your job, it can be tricky to find the perfect image.

The better place to find a docker image is the [docker
hub](https://hub.docker.com/search?q=&type=image). You can start your research
there with the following steps:

??? note "1. Search for an image prepared with the tool you want to run"
    * This is the best situation: a ready-to-use docker image that
          doesn't require any additional installation.
    * *Example for `mkdocs` job:
          [`squidfunk/mkdocs-material`](https://hub.docker.com/r/squidfunk/mkdocs-material)*.
    * If you find it, check it with the general guidelines below.

??? note "2. If there isn't any image prepared for the tool you want to run, search for more general images"
    * This case will require to install needed tool as first step of your job.
      If the installation is long or heavy, you should considers to build your
      own image with the tool already installed.
    * The vast majority of operating system and languages provides official
      images, choose the more appropriate for your job. Some examples:
      [`alpine`](https://hub.docker.com/_/alpine),
      [`debian`](https://hub.docker.com/_/debian),
      [`ubuntu`](https://hub.docker.com/_/ubuntu),
      [`python`](https://hub.docker.com/_/python),
      [`node`](https://hub.docker.com/_/node).

!!! note "3. If you decide to build your own image: the image must be stored in a publicly reachable registry, like Docker hub or Gitlab registry"


**General guidelines to choose the image**

* The first thing to check is if the image is official (`OFFICIAL IMAGE` badge on docker hub): this is the
  perfect image for your use case ![Docker official
  badge](images/docker_official_badge.png){: .docker_official_badge }.
* If it is not, the following points should be considered to choose an image:
    * The image must be versioned and not only with `latest` tag. ==If image
      isn't versioned: it's not usable for your job==.
    * It should be actively maintained, with frequent updates, and should contain
      recent versions.
    * The image should be small, containing only required tools.
    * The image should be efficient to run the job.
    * A large usage of the image can be a good indicator, but be aware, it
      doesn't guarantee the quality neither the security of the image.

#### 📦 Artifacts

The vast majority of jobs produce a result. This result can be of different
kinds:

* Test report.
* Build result.

In both case, the result should be exposed by the job using the
[`artifact`](https://docs.gitlab.com/ee/ci/yaml/#artifacts){:target=blank}
option. It permits passing an artifact to another job of the pipeline and
expose results to users.

!!! info
    * In the case of a test report, you need to use `when: always` option under
      `artifacts` if you want to expose result even if job fails.
    * You can combine both a build result and a test report by using both
      `artifacts:paths` and `artifacts:reports`.

An artifact can be configured at different level of integration in Gitlab
interface:

1. Best integration: Gitlab [`artifacts:reports`](https://docs.gitlab.com/ee/ci/yaml/#artifactsreports){:target=blank}

    This is a way to integrate a report result in an user-friendly way in Gitlab's
    interface. We encourage all job contributors to adapt their job output to a
    format compatible with a Gitlab report.

    ??? example "Example of `artifacts:reports:junit` report"
        Job [`trivy_image`](/jobs/dynamic_tests/trivy_image/) that
        uses its output as `junit` report in `artifacts:reports:junit` section:
        ```yaml
        trivy_image:
          [...]
          artifacts:
            reports:
              junit: "$TRIVY_OUTPUT"
        ```

2. Quick integration with [`artifacts:expose_as`](https://docs.gitlab.com/ee/ci/yaml/#artifactsexpose_as){:target=blank}

    This is a way to quickly integrate any format of report in Gitlab Merge
    Request interface. Technically, you don't have to shape your report output
    in a specific format, but we recommend to use `HTML` format. In this way,
    the report is one-click readable from any Merge Request.

    ??? example "Example of `artifacts:expose_as` report"
        Job [`nmap`](/jobs/dynamic_tests/nmap/) uses `artifacts:expose_as`
        to expose its `HTML` report:
        ```yaml
        nmap:
          [...]
          artifacts:
            expose_as: "nmap-report"
            paths:
              - "${HTML_OUTPUT}"
            when: always
        ```

3. Simple artifact without integration

    ??? example "Example of `artifacts`"
        Job that specify an `artifact`:
        ```yaml
        job_name:
          [...]
          artifacts:
            paths:
              - "output"
            when: always
        ```

#### 🔩 Keep your job generic

The jobs of the hub should remain as generic as possible. In order to ensure it:

* Try to avoid using `rules` options, that is strongly linked to the context of
  the user and so should be set by the user. Also, some features requiring
  specific workflows, as [Gitlab Merge
  Trains](https://docs.gitlab.com/ee/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/){:target=blank},
  are more easily implemented by users if you don't specify `rules` in your
  job.
* Try to avoid using `before_script` and `after_script` to let users the
  possibility to redefine these options while exploiting to the maximum your
  job.

!!! info
    The jobs of the hub can be dynamically
    [customized](/use-the-hub/#jobs-customization) by users.


### 📖 Job documentation

As described in [R2Devops/hub job
structure](/job-structure/#job-documentation), the documentation of a job is
written inside its `README.md` file.

!!! tip
    Don't hesitate to copy the documentation from another job as starting
    point. For example, the raw content of [openapi
    `README.md`](https://gitlab.com/r2devops/hub/-/raw/latest/jobs/openapi/README.md)! 

We recommend including at least the following sections in your documentation:

* Objective: describe the goal of your job.
* How to use it: a list of steps to quickly use your job.
* Job details: describes details of the job (name, docker image, stage, etc).
* Variables: table listing variables used by the job (name, description,
  default value, mandatory if needed).
* Artifacts: describes artifact(s) defined by the job.

### 🚄 Compliance with another job

Several jobs of the hub can be used together without any configuration. This is
currently implemented for all jobs producing an `HTML` output and the job
[`pages`](/jobs/deploy/pages/) which deploys the `HTML` on a webserver.

!!! info
    This feature is empowered by the `artifacts` option: jobs producing a
    static website output give it to the `pages` job through an artifact stored
    in a standard path: `${CI_PROJECT_DIR}/website_build`.

So, if your job produce a static website output, ensure to store the result of
the build in `${CI_PROJECT_DIR}/website_build`, and to configure this path as
artifact. You can see an example in [`mkdocs`](/jobs/build/mkdocs/) job.

### 🧪 Test your job

In order to test your job before merging it into the hub, we recommend you to
follow these steps:

1. Test the behavior of your job inside a local container on your machine (with
   the same image you want to use for the job). To simulate the GitLab job
   that will run it on your project, you can mount the repository folder inside
   the container:
      ```shell
      # Example if your job will use node:15.7-buster as Docker image
      docker run -v /path/to/your/repo:/mnt --entrypoint "/bin/sh" -it node:15.7-buster
      ```

2. Create your job configuration in a repository and test it locally using
   [`include
   local`](https://docs.gitlab.com/ee/ci/yaml/#includelocal){:target=blank},
   instead of `remote` from the hub. For example:

    ```yaml
    include:
        - local: 'my-work-in-progress-job.yml'
    ```


!!! success "Congratulation, you did it!"
      You went through all our guideline. 🥳

      If never something feel unclear or you're having a doubt, join us on [Discord](https://discord.r2devops.io/?utm_medium=website&utm_source=r2devops) to ask us anything! We'll be more than happy to help.

docs/css/custom_admonitions.css

deleted100644 → 0
+0 −27
Original line number Diff line number Diff line
:root {
  --md-admonition-icon--heart: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z"/></svg>')
}
.md-typeset .admonition.heart,
.md-typeset details.heart {
  border-color: rgb(220, 10, 22);
}
.md-typeset .heart > .admonition-title,
.md-typeset .heart > summary {
  background-color: rgba(220, 10, 22, 0.1);
}
.md-typeset .heart > .admonition-title::before,
.md-typeset .heart > summary::before {
  background-color: rgb(220, 10, 22);
  -webkit-mask-image: var(--md-admonition-icon--heart);
          mask-image: var(--md-admonition-icon--heart);
  animation: heart 1000ms infinite;
}

@keyframes heart {
  0%, 40%, 80%, 100% {
    transform: scale(1);
  }
  20%, 60% {
    transform: scale(1.15);
  }
}

docs/css/extra.css

deleted100644 → 0
+0 −394

File deleted.

Preview size limit exceeded, changes collapsed.

docs/css/juxtapose/juxtapose.css

deleted100644 → 0
+0 −352
Original line number Diff line number Diff line
/* juxtapose - v1.1.6 - 2015-09-09
 * Copyright (c) 2015 Alex Duner and Northwestern University Knight Lab
 */
div.juxtapose {
	width: 100%;
	font-family: Helvetica, Arial, sans-serif;
}

div.jx-slider {
	width: 100%;
	height: 100%;
	position: relative;
	overflow: hidden;
	cursor: pointer;
}

div.jx-handle {
	position: absolute;
	height: 100%;
	width: 40px;
	cursor: col-resize;
	z-index: 2;
	margin-left: -20px;
}


.vertical div.jx-handle {
	height: 40px;
	width: 100%;
	cursor: row-resize;
	margin-top: -20px;
	margin-left: 0;
}

div.jx-control {
	height: 100%;
	margin-right: auto;
	margin-left: auto;
	width: 3px;
	background-color: white;
}


.vertical div.jx-control {
	height: 3px;
	width: 100%;
	background-color: white;
	position: relative;
	top: 50%;
	transform: translateY(-50%);
}

div.jx-controller {
	position: absolute;
	margin: auto;
	top: 0;
	bottom: 0;
	height: 60px;
	width: 9px;
	margin-left: -3px;
	background-color: white;
}

.vertical div.jx-controller {
	height: 9px;
	width: 100px;
	margin-left: auto;
	margin-right: auto;
	top: -3px;
	position: relative;
}

div.jx-arrow {
	position: absolute;
	margin: auto;
	top: 0;
	bottom: 0;
	width: 0;
	height: 0;
	transition: all .2s ease;
}

.vertical div.jx-arrow {
	position: absolute;
	margin: 0 auto;
	left: 0;
	right: 0;
	width: 0;
	height: 0;
	transition: all .2s ease;
}


div.jx-arrow.jx-left {
	left: 2px;
	border-style: solid;
	border-width: 8px 8px 8px 0;
	border-color: transparent #FFF transparent transparent;
}

div.jx-arrow.jx-right {
	right: 2px;
	border-style: solid;
	border-width: 8px 0 8px 8px;
	border-color: transparent transparent transparent #FFF;
}

.vertical div.jx-arrow.jx-left {
	left: 0px;
	top: 2px;
	border-style: solid;
	border-width: 0px 8px 8px 8px;
	border-color: transparent transparent #FFF transparent;
}

.vertical div.jx-arrow.jx-right {
	right: 0px;
	top: initial;
	bottom: 2px;
	border-style: solid;
	border-width: 8px 8px 0 8px;
	border-color: #FFF transparent transparent transparent;
}

div.jx-handle:hover div.jx-arrow.jx-left,
div.jx-handle:active div.jx-arrow.jx-left {
	left: -2px;
}

div.jx-handle:hover div.jx-arrow.jx-right,
div.jx-handle:active div.jx-arrow.jx-right {
	right: -2px;
}

.vertical div.jx-handle:hover div.jx-arrow.jx-left,
.vertical div.jx-handle:active div.jx-arrow.jx-left {
	left: 0px;
	top: 0px;
}

.vertical div.jx-handle:hover div.jx-arrow.jx-right,
.vertical div.jx-handle:active div.jx-arrow.jx-right {
	right: 0px;
	bottom: 0px;
}


div.jx-image {
	position: absolute;
	height: 100%;
	display: inline-block;
	top: 0;
	overflow: hidden;
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
}

.vertical div.jx-image {
	width: 100%;
	left: 0;
	top: initial;
}

div.jx-image img {
	height: 100%;
	z-index: 1;
	position: absolute;

	max-height: none;
	max-width: none;
	max-height: initial;
	max-width: initial;
}

.vertical div.jx-image img {
	height: initial;
	width: 100%;
}

div.jx-image.jx-left {
	left: 0;
	background-position: left;
}

div.jx-image.jx-left img {
	left: 0;
}

div.jx-image.jx-right {
	right: 0;
	background-position: right;
}

div.jx-image.jx-right img {
	right: 0;
	bottom: 0;
}


.veritcal div.jx-image.jx-left {
	top: 0;
	background-position: top;
}

.veritcal div.jx-image.jx-left img {
	top: 0;
}

.vertical div.jx-image.jx-right {
	bottom: 0;
	background-position: bottom;
}

.veritcal div.jx-image.jx-right img {
	bottom: 0;
}


div.jx-image div.jx-label {
	font-size: 1em;
	padding: .25em .75em;
	position: relative;
	display: inline-block;
	top: 0;
	background-color: #000; /* IE 8 */
	background-color: rgba(0,0,0,.7);
	color: white;
	z-index: 2;
	white-space: nowrap;
	line-height: 18px;
	vertical-align: middle;
}

div.jx-image.jx-left div.jx-label {
	float: left;
	left: 0;
}

div.jx-image.jx-right div.jx-label {
	float: right;
	right: 0;
}

.vertical div.jx-image div.jx-label {
	display: table;
	position: absolute;
}

.vertical div.jx-image.jx-right div.jx-label {
	left: 0;
	bottom: 0;
	top: initial;
}

div.jx-credit {
	line-height: 1.1;
	font-size: 0.75em;
}

div.jx-credit em {
	font-weight: bold;
	font-style: normal;
}


/* Animation */

div.jx-image.transition {
	transition: width .5s ease;
}

div.jx-handle.transition {
	transition: left .5s ease;
}

.vertical div.jx-image.transition {
	transition: height .5s ease;
}

.vertical div.jx-handle.transition {
	transition: top .5s ease;
}

/* Knight Lab Credit */
a.jx-knightlab {
	background-color: #000; /* IE 8 */
	background-color: rgba(0,0,0,.25);
	bottom: 0;
	display: table;
	height: 14px;
	line-height: 14px;
	padding: 1px 4px 1px 5px;
	position: absolute;
	right: 0;
	text-decoration: none;
	z-index: 2;
}

a.jx-knightlab div.knightlab-logo {
	display: inline-block;
	vertical-align: middle;
	height: 8px;
	width: 8px;
	background-color: #c34528;
	transform: rotate(45deg);
	-ms-transform: rotate(45deg);
	-webkit-transform: rotate(45deg);
	top: -1.25px;
	position: relative;
	cursor: pointer;
}

a.jx-knightlab:hover {
	background-color: #000; /* IE 8 */
	background-color: rgba(0,0,0,.35);
}
a.jx-knightlab:hover div.knightlab-logo {
	background-color: #ce4d28;
}

a.jx-knightlab span.juxtapose-name {
	display: table-cell;
	margin: 0;
	padding: 0;
	font-family: Helvetica, Arial, sans-serif;
	font-weight: 300;
	color: white;
	font-size: 10px;
	padding-left: 0.375em;
  	vertical-align: middle;
  	line-height: normal;
}

/* keyboard accessibility */
div.jx-controller:focus,
div.jx-image.jx-left div.jx-label:focus,
div.jx-image.jx-right div.jx-label:focus,
a.jx-knightlab:focus {
	background: #eae34a;
	color: #000;
}
a.jx-knightlab:focus span.juxtapose-name{
	color: #000;
	border: none;
}

/* Custom */
div.jx-controller:hover {
	height: 75px;
	background-color: #bfbfbf;
	transition: all .2s ease;
}
 No newline at end of file
Loading