Browse Source

Init files

master
Haris Razis 4 years ago
parent
commit
938507bfd8
  1. 1
      .gitignore
  2. 78
      app.js
  3. 90
      bin/www
  4. 5
      locales/el.json
  5. 18
      locales/en.json
  6. 1392
      package-lock.json
  7. 21
      package.json
  8. BIN
      public/images/annie-spratt-QckxruozjRg-unsplash.jpg
  9. BIN
      public/images/markus-spiske-qjnAnF0jIGk-unsplash.jpg
  10. BIN
      public/images/thomas-jensen-ISG-rUel0Uw-unsplash.jpg
  11. BIN
      public/images/yancy-min-842ofHC6MaI-unsplash.jpg
  12. 5
      public/javascripts/bs-init.js
  13. 0
      public/javascripts/fetchLabs.js
  14. 90
      public/stylesheets/Footer-Dark.css
  15. 203
      public/stylesheets/Navigation-with-Button.css
  16. 11506
      public/stylesheets/bootstrap.min.css
  17. 9
      routes/index.js
  18. 9
      routes/users.js
  19. 3
      views/error.ejs
  20. 210
      views/index.ejs

1
.gitignore

@ -0,0 +1 @@
node_modules/

78
app.js

@ -0,0 +1,78 @@
var createError = require('http-errors'),
express = require('express'),
path = require('path'),
cookieParser = require('cookie-parser'),
logger = require('morgan'),
i18next = require("i18next"),
session = require('express-session'),
i18nextMiddleware = require("i18next-express-middleware"),
FilesystemBackend = require("i18next-node-fs-backend");
var indexRouter = require('./routes/index');
var enTranslations = require("./locales/en.json");
var elTranslations = require("./locales/el.json");
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
i18next
.use(i18nextMiddleware.LanguageDetector)
.use(FilesystemBackend)
.init({
detection: {
order: ["querystring", "cookie"],
caches: ["cookie"]
},
preload: ["en", "el"],
fallbackLng: "en",
debug: false,
resources: {
en: enTranslations,
el: elTranslations
},
saveMissing: true
});
app.use(
session({
cookie: {
maxAge: 60000
},
secret: "secret",
resave: false,
saveUninitialized: false
})
);
app.use(i18nextMiddleware.handle(i18next));
app.use('/', indexRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;

90
bin/www

@ -0,0 +1,90 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('swarmlab.io:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

5
locales/el.json

@ -0,0 +1,5 @@
{
"translation": {
"welcome": "Home"
}
}

18
locales/en.json

@ -0,0 +1,18 @@
{
"translation": {
"welcome": "Welcome to Swarmlab",
"welcome_text": "Swarmlab is a powerful collaboration tool that connects tutors and students in a unique all-in-one environment that gets work done fast and easily.",
"features_01_header": "Fast Deployment",
"features_01_text": "Tutors bootstrap their lab-rooms using our tools",
"features_02_header": "Collaboration ready",
"features_02_text": "Both teacher and students can use the latest collaboration tools",
"features_03_header": "Easy to Use",
"features_03_text": "Ready-to-Use Virtual Labs one click away",
"on_demand": "On demand Lab-rooms",
"on_demand_text": "Create and share your ideas on our lab-room platform. Join tutors labs, learn more about your interests and broaden your horizon.",
"git": "Git",
"git_text": "The wolds leading, powerful collaboration tool at your disposal on our servers. Keep in touch with your workmates and make sharing simpler then ever.",
"available_swarmlab": "Available Swarmlab Labrooms",
"bug": "Found a bug? Help us fix it!"
}
}

1392
package-lock.json

File diff suppressed because it is too large

21
package.json

@ -0,0 +1,21 @@
{
"name": "swarmlab.io",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "nodemon ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"ejs": "~2.6.1",
"express": "~4.16.1",
"express-session": "^1.17.1",
"http-errors": "~1.6.3",
"i18next": "^19.6.2",
"i18next-express-middleware": "^2.0.0",
"i18next-node-fs-backend": "^2.1.3",
"morgan": "~1.9.1",
"nodemon": "^2.0.4"
}
}

BIN
public/images/annie-spratt-QckxruozjRg-unsplash.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

BIN
public/images/markus-spiske-qjnAnF0jIGk-unsplash.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

BIN
public/images/thomas-jensen-ISG-rUel0Uw-unsplash.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

BIN
public/images/yancy-min-842ofHC6MaI-unsplash.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 KiB

5
public/javascripts/bs-init.js

@ -0,0 +1,5 @@
$(document).ready(function(){
$('[data-bs-hover-animate]')
.mouseenter( function(){ var elem = $(this); elem.addClass('animated ' + elem.attr('data-bs-hover-animate')) })
.mouseleave( function(){ var elem = $(this); elem.removeClass('animated ' + elem.attr('data-bs-hover-animate')) });
});

0
public/javascripts/fetchLabs.js

90
public/stylesheets/Footer-Dark.css

@ -0,0 +1,90 @@
.footer-dark {
padding: 50px 0;
color: #f0f9ff;
background-color: #282d32;
}
.footer-dark h3 {
margin-top: 0;
margin-bottom: 12px;
font-weight: bold;
font-size: 16px;
}
.footer-dark ul {
padding: 0;
list-style: none;
line-height: 1.6;
font-size: 14px;
margin-bottom: 0;
}
.footer-dark ul a {
color: inherit;
text-decoration: none;
opacity: 0.6;
}
.footer-dark ul a:hover {
opacity: 0.8;
}
@media (max-width:767px) {
.footer-dark .item:not(.social) {
text-align: center;
padding-bottom: 20px;
}
}
.footer-dark .item.text {
margin-bottom: 36px;
}
@media (max-width:767px) {
.footer-dark .item.text {
margin-bottom: 0;
}
}
.footer-dark .item.text p {
opacity: 0.6;
margin-bottom: 0;
}
.footer-dark .item.social {
text-align: center;
}
@media (max-width:991px) {
.footer-dark .item.social {
text-align: center;
margin-top: 20px;
}
}
.footer-dark .item.social > a {
font-size: 20px;
width: 36px;
height: 36px;
line-height: 36px;
display: inline-block;
text-align: center;
border-radius: 50%;
box-shadow: 0 0 0 1px rgba(255,255,255,0.4);
margin: 0 8px;
color: #fff;
opacity: 0.75;
}
.footer-dark .item.social > a:hover {
opacity: 0.9;
}
.footer-dark .copyright {
text-align: center;
padding-top: 24px;
opacity: 0.3;
font-size: 13px;
margin-bottom: 0;
}

203
public/stylesheets/Navigation-with-Button.css

@ -0,0 +1,203 @@
.navigation-clean-button {
background: #fff;
padding-top: .75rem;
padding-bottom: .75rem;
color: #333;
border-radius: 0;
box-shadow: none;
border: none;
margin-bottom: 0;
}
@media (min-width:768px) {
.navigation-clean-button {
padding-top: 1rem;
padding-bottom: 1rem;
}
}
.navigation-clean-button .navbar-brand {
font-weight: bold;
color: inherit;
}
.navigation-clean-button .navbar-brand:hover {
color: #222;
}
.navigation-clean-button.navbar-dark .navbar-brand:hover {
color: #f0f0f0;
}
.navigation-clean-button .navbar-brand img {
height: 100%;
display: inline-block;
margin-right: 10px;
width: auto;
}
.navigation-clean-button .navbar-toggler {
border-color: #ddd;
}
.navigation-clean-button .navbar-toggler:hover, .navigation-clean-button .navbar-toggler:focus {
background: none;
}
.navigation-clean-button.navbar-dark .navbar-toggler {
border-color: #555;
}
.navigation-clean-button .navbar-toggler {
color: #888;
}
.navigation-clean-button.navbar-dark .navbar-toggler {
color: #eee;
}
.navigation-clean-button .navbar-collapse, .navigation-clean-button .form-inline {
border-top-color: #ddd;
}
.navigation-clean-button.navbar-dark .navbar-collapse, .navigation-clean-button.navbar-dark .form-inline {
border-top-color: #333;
}
.navigation-clean-button .navbar-nav a.active, .navigation-clean-button .navbar-nav > .show > a {
background: none;
box-shadow: none;
}
.navigation-clean-button.navbar-light .navbar-nav a.active, .navigation-clean-button.navbar-light .navbar-nav a.active:focus, .navigation-clean-button.navbar-light .navbar-nav a.active:hover {
color: #8f8f8f;
box-shadow: none;
background: none;
pointer-events: none;
}
.navigation-clean-button.navbar .navbar-nav .nav-link {
padding-left: 18px;
padding-right: 18px;
}
.navigation-clean-button.navbar-light .navbar-nav .nav-link {
color: #465765;
}
.navigation-clean-button.navbar-light .navbar-nav .nav-link:focus, .navigation-clean-button.navbar-light .navbar-nav .nav-link:hover {
color: #37434d !important;
background-color: transparent;
}
.navigation-clean-button .navbar-nav > li > .dropdown-menu {
margin-top: -5px;
box-shadow: 0 4px 8px rgba(0,0,0,.1);
background-color: #fff;
border-radius: 2px;
}
.navigation-clean-button .dropdown-menu .dropdown-item:focus, .navigation-clean-button .dropdown-menu .dropdown-item {
line-height: 2;
font-size: 14px;
color: #37434d;
}
.navigation-clean-button .dropdown-menu .dropdown-item:focus, .navigation-clean-button .dropdown-menu .dropdown-item:hover {
background: #eee;
color: inherit;
}
@media (max-width:767px) {
.navigation-clean-button .navbar-nav .show .dropdown-menu {
box-shadow: none;
}
}
@media (max-width:767px) {
.navigation-clean-button .navbar-nav .show .dropdown-menu .dropdown-item {
color: #37434d;
padding-top: 12px;
padding-bottom: 12px;
line-height: 1;
}
}
.navigation-clean-button.navbar-dark {
background-color: #1f2021;
color: #fff;
}
.navigation-clean-button.navbar-dark .navbar-nav a.active, .navigation-clean-button.navbar-dark .navbar-nav a.active:focus, .navigation-clean-button.navbar-dark .navbar-nav a.active:hover {
color: #8f8f8f;
box-shadow: none;
background: none;
pointer-events: none;
}
.navigation-clean-button.navbar-dark .navbar-nav .nav-link {
color: #dfe8ee;
}
.navigation-clean-button.navbar-dark .navbar-nav .nav-link:focus, .navigation-clean-button.navbar-dark .navbar-nav .nav-link:hover {
color: #fff !important;
background-color: transparent;
}
.navigation-clean-button.navbar-dark .navbar-nav > li > .dropdown-menu {
background-color: #1f2021;
}
.navigation-clean-button.navbar-dark .dropdown-menu .dropdown-item:focus, .navigation-clean-button.navbar-dark .dropdown-menu .dropdown-item {
color: #f2f5f8;
}
.navigation-clean-button.navbar-dark .dropdown-menu .dropdown-item:focus, .navigation-clean-button.navbar-dark .dropdown-menu .dropdown-item:hover {
background: #363739;
}
@media (max-width:767px) {
.navigation-clean-button.navbar-dark .navbar-nav .show .dropdown-menu .dropdown-item {
color: #fff;
}
}
.navigation-clean-button .actions .login {
margin-right: 1rem;
text-decoration: none;
color: #465765;
}
.navigation-clean-button.navbar-dark .actions .login {
color: #dfe8ee;
}
.navigation-clean-button.navbar-dark .actions .login:hover {
color: #fff;
}
.navigation-clean-button .navbar-text .action-button, .navigation-clean-button .navbar-text .action-button:active, .navigation-clean-button .navbar-text .action-button:hover {
background: #56c6c6;
border-radius: 20px;
font-size: inherit;
color: #fff;
box-shadow: none;
border: none;
text-shadow: none;
padding: .5rem 1rem;
transition: background-color 0.25s;
font-size: inherit;
}
.navigation-clean-button .navbar-text .action-button:hover {
background: #66d7d7;
}
.navigation-clean-button.navbar-dark .action-button, .navigation-clean-button.navbar-dark .action-button:active {
background: #208f8f;
}
.navigation-clean-button.navbar-dark .action-button:hover {
background: #269d9d;
}

11506
public/stylesheets/bootstrap.min.css

File diff suppressed because it is too large

9
routes/index.js

@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', (req, res, next) => {
res.render('index');
});
module.exports = router;

9
routes/users.js

@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;

3
views/error.ejs

@ -0,0 +1,3 @@
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>

210
views/index.ejs

@ -0,0 +1,210 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>swarmlab.io</title>
<link rel="stylesheet" href="/stylesheets/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css">
<link rel="stylesheet" href="/stylesheets/Footer-Dark.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
<link rel="stylesheet" href="/stylesheets/Navigation-with-Button.css">
</head>
<body>
<nav class="navbar navbar-light navbar-expand-md navigation-clean-button">
<div class="container"><a class="navbar-brand text-monospace" href="index.html">swarmlab.io</a><button
data-toggle="collapse" class="navbar-toggler" data-target="#navcol-1"><span class="sr-only">Toggle
navigation</span><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navcol-1">
<ul class="nav navbar-nav mr-auto">
<li class="nav-item" role="presentation"><a class="nav-link" href="#features">Features</a></li>
<li class="nav-item" role="presentation"><a class="nav-link" href="#services">Services</a></li>
<li class="nav-item" role="presentation"><a class="nav-link" href="#lab-rooms">Lab-rooms</a></li>
</ul><span class="navbar-text actions"> <a class="login" href="#">Log In</a><a
class="btn btn-light action-button" role="button" href="#">Sign Up</a></span>
</div>
</div>
</nav>
<header class="masthead text-white text-center"
style="background: url(/images/markus-spiske-qjnAnF0jIGk-unsplash.jpg) top / cover;">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-xl-9 mx-auto">
<h1 class="mb-5" style="height: 20px;"><%= t('welcome') %></h1>
<p style="font-size: 24px;"><%= t('welcome_text') %></p>
</div>
</div>
</div>
</header>
<section class="features-icons bg-light text-center" id="features">
<div class="container">
<div class="row">
<div class="col-lg-4">
<div class="mx-auto features-icons-item mb-5 mb-lg-0 mb-lg-3">
<div class="d-flex features-icons-icon"><i class="icon-screen-desktop m-auto text-primary"
data-bs-hover-animate="pulse"></i></div>
<h3><%= t('features_01_header') %></h3>
<p class="lead mb-0"><%= t('features_01_text') %></p>
</div>
</div>
<div class="col-lg-4">
<div class="mx-auto features-icons-item mb-5 mb-lg-0 mb-lg-3">
<div class="d-flex features-icons-icon"><i class="icon-layers m-auto text-primary"
data-bs-hover-animate="pulse"></i></div>
<h3><%= t('features_02_header') %></h3>
<p class="lead mb-0"><%= t('features_02_text') %></p>
</div>
</div>
<div class="col-lg-4">
<div class="mx-auto features-icons-item mb-5 mb-lg-0 mb-lg-3">
<div class="d-flex features-icons-icon"><i class="icon-check m-auto text-primary"
data-bs-hover-animate="pulse"></i></div>
<h3><%= t('features_03_header') %></h3>
<p class="lead mb-0"><%= t('features_03_text') %></p>
</div>
</div>
<div class="col"><a class="btn btn-primary btn-lg" role="button" data-bs-hover-animate="pulse"
style="color: rgb(255,255,255);margin-top: 80px;">Documentation</a></div>
</div>
</div>
</section>
<section class="showcase" id="services">
<div class="container-fluid p-0">
<div class="row no-gutters">
<div class="col-lg-6 order-lg-2 text-white showcase-img"
style="background: url(/images/thomas-jensen-ISG-rUel0Uw-unsplash.jpg) center / cover;"><span></span></div>
<div class="col-lg-6 my-auto order-lg-1 showcase-text">
<h2><strong><%= t('on_demand') %>&nbsp; </strong></h2>
<p class="lead mb-0"><%= t('on_demand_text') %></p><a class="btn btn-light border-dark" role="button"
data-bs-hover-animate="pulse" style="margin: 0;margin-top: 20px;"
href="https://api-client.swarmlab.io:8088">api-client.swarmlab</a>
</div>
</div>
<div class="row no-gutters">
<div class="col-lg-6 text-white showcase-img"
style="background: url(/images/yancy-min-842ofHC6MaI-unsplash.jpg) center / cover;"><span></span></div>
<div class="col-lg-6 my-auto order-lg-1 showcase-text" style="margin: 0;">
<h2><strong><%= t('git') %></strong></h2>
<p class="lead mb-0"><%= t('git_text') %></p><a class="btn btn-light border-dark" role="button"
data-bs-hover-animate="pulse" style="margin: 0;margin-top: 20px;"
href="https://git.swarmlab.io:3000">git.swarmlab</a>
</div>
</div>
</div>
</section>
<section class="testimonials text-center bg-light" id="lab-rooms">
<div class="container">
<h2 class="mb-5"><%= t('available_swarmlab') %></h2>
<div class="row">
<div class="col">
<div class="card-group">
<div class="card" style="margin: 10px;">
<div class="card-body">
<h4 class="card-title">Title</h4>
<p class="card-text">Nullam id dolor id nibh ultricies vehicula ut id elit. Cras justo odio, dapibus ac
facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus.</p><a
class="btn btn-light btn-sm border-dark" role="button">More Info</a>
</div>
</div>
<div class="card" style="margin: 10px;">
<div class="card-body">
<h4 class="card-title">Title</h4>
<p class="card-text">Nullam id dolor id nibh ultricies vehicula ut id elit. Cras justo odio, dapibus ac
facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus.</p><a
class="btn btn-light border-dark" role="button">Button</a>
</div>
</div>
<div class="card" style="margin: 10px;">
<div class="card-body">
<h4 class="card-title">Title</h4>
<p class="card-text">Nullam id dolor id nibh ultricies vehicula ut id elit. Cras justo odio, dapibus ac
facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus.</p><a
class="btn btn-light border-dark" role="button">Button</a>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-center justify-content-xl-center">
<nav class="d-flex justify-content-center" style="width: auto;margin-top: 25px;color: rgb(33,37,41);">
<ul class="pagination">
<li class="page-item"><a class="page-link" href="#" aria-label="Previous"><span
aria-hidden="true">«</span></a></li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">4</a></li>
<li class="page-item"><a class="page-link" href="#">5</a></li>
<li class="page-item"><a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">»</span></a>
</li>
</ul>
</nav>
</div>
</div>
</section>
<section class="call-to-action text-white text-center"
style="background: url(/images/annie-spratt-QckxruozjRg-unsplash.jpg) center / cover;height: 400;" id="feedback">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-xl-9 mx-auto">
<h2 class="mb-4"> <%= t('bug') %></h2>
</div>
<div class="col-md-10 col-lg-8 col-xl-7 mx-auto">
<div class="row d-flex justify-content-center justify-content-xl-center"><a
class="btn btn-secondary btn-lg border-secondary justify-content-center" role="button"
data-bs-hover-animate="pulse" style="margin: 0;margin-top: 20px;background-color: rgb(40,45,51);"
href=" https://git.swarmlab.io:3000/swarmlab/feedback">Feedback</a></div>
</div>
</div>
</div>
</section>
<div class="footer-dark">
<footer>
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-3 item">
<h3>Menu</h3>
<ul>
<li><a href="#features">Features</a></li>
<li><a href="#">Documentation</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#lab-rooms">Lab-rooms</a></li>
<li><a href="#feedback">Feedback</a></li>
<li><a href="#">FAQ</a></li>
</ul>
</div>
<div class="col-sm-6 col-md-3 item">
<h3>Translations</h3>
<ul>
<li><a href="?lng=en">English</a></li>
<li><a href="?lng=el">Greek</a></li>
<li></li>
</ul>
</div>
<div class=" col-md-6 item text">
<h3>swarmlab.io</h3>
<p><%= t('welcome_text') %></p>
</div>
<div class="col item social"><span class="actions"> <a class="btn btn-light btn-lg text-light action-button"
role="button" href="#" style="background-color: rgba(248,249,250,0);">Log In</a><a
class="btn btn-light btn-lg text-light action-button" role="button" href="#"
style="margin: 20px;background-color: rgba(248,249,250,0);color: rgb(255,255,255);">Sign Up</a></span>
</div>
</div>
<p class="copyright">swarmlab.io © <%= new Date().getFullYear(); %></p>
</div>
</footer>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
<script src="/javascripts/bs-init.js"></script>
</body>
</html>
Loading…
Cancel
Save