text: // * ———————————————————————————————————————————————————————— * //
  // * 	enduro's production server
  // *
  // *	runs production server with password protection and
  // *	admin ui and better routing
  // *
  // *	uses express mvc
  // * ———————————————————————————————————————————————————————— * //
  const enduro_server = function () {}
  
  // * vendor dependencies
  const express = require('express')
  const app = express()
  const session = require('express-session')
  const cors = require('cors')
  const multiparty_middleware = require('connect-multiparty')()
  const cookieParser = require('cookie-parser')
  
  // * enduro dependencies
  const admin_api = require(enduro.enduro_path + '/libs/admin_api')
  const website_app = require(enduro.enduro_path + '/libs/website_app')
  const trollhunter = require(enduro.enduro_path + '/libs/trollhunter')
  const logger = require(enduro.enduro_path + '/libs/logger')
  const ab_tester = require(enduro.enduro_path + '/libs/ab_testing/ab_tester')
  const brick_handler = require(enduro.enduro_path + '/libs/bricks/brick_handler')
  const global_data = require(enduro.enduro_path + '/libs/global_data')
  const components_handler = require(enduro.enduro_path + '/libs/components_handler')
  const helper_handler = require(enduro.enduro_path + '/libs/helper_handler')
  
  var cluster = require('cluster');
  
  // initialization of the sessions
  app.set('trust proxy', 1)
  app.use(session({
  	secret: 'keyboard cat',
  	resave: false,
  	saveUninitialized: true,
  	cookie: {},
  }))
  
  app.use(cookieParser())
  
  app.use(cors())
  
  // add enduro.js header
  app.use(function (req, res, next) {
  	res.header('X-Powered-By', 'enduro.js')
  	next()
  })
  
  // * ———————————————————————————————————————————————————————— * //
  // * 	server run
  // *
  // * 	starts the production server
  // *	@param {boolean} development_mode - if true, prevents enduro render on start to prevent double rendering
  // *	@return {}
  // * ———————————————————————————————————————————————————————— * //
  enduro_server.prototype.run = async function (server_setup) {
  	// stores current enduro_server instance
  	const self = this
  
  	server_setup = server_setup || {}
  
  	// overrides the port by system environment variable
  	enduro.config.port = process.env.PORT || enduro.flags.port || enduro.config.port || 5000
  
  	if (enduro.flags.cluster && cluster.isMaster) {
  		console.log('clustering enduro..');
          cluster.schedulingPolicy = cluster.SCHED_RR;
          if (!server_setup.development_mode && !enduro.flags.nocompile) {
              await enduro.actions.render();
          }
          for (var i = 0; i < enduro.flags.cluster; i += 1) {
              cluster.fork();
          }
          return;
  	}
  
  	if (enduro.flags.cluster && !cluster.isMaster) {
          console.log('Enduro worker %d running!', cluster.worker.id);
          await global_data.get_global_data();
          await components_handler.read_components()
          await helper_handler.read_helpers()
      }
  
      if (!server_setup.development_mode && !enduro.flags.nocompile && (!enduro.flags.cluster || cluster.isMaster)) {
          await enduro.actions.render();
      }
  
      // starts listening to request on specified port
  	enduro.server = app.listen(enduro.config.port, function () {
  		logger.timestamp('Production server started at port ' + enduro.config.port, 'enduro_events')
  	})
  
  	// forward the app and server to running enduro application
  	website_app.forward(app, enduro.server)
  
  	// serve static files from /_generated folder
  	app.use('/admin', express.static(enduro.config.admin_folder))
  	app.use('/assets', express.static(enduro.project_path + '/' + enduro.config.build_folder + '/assets'))
  	app.use('/_prebuilt', express.static(enduro.project_path + '/' + enduro.config.build_folder + '/_prebuilt'))
  	app.use('/remote', express.static(enduro.project_path + '/remote'))
  
  	// handle for executing enduro refresh from client
  	app.get('/admin_api_refresh', function (req, res) {
  		enduro.actions.render()
  			.then(() => {
  				res.send({ success: true, message: 'enduro refreshed successfully' })
  			})
  	})
  
  	// robots.txt
  	app.get('/robots.txt', function (req, res) {
  		res.type('text/plain')
  		res.send("User-agent: *\nAllow: /")
  	})
  
  	// serve bricks' static assets
  	brick_handler.serve_brick_static_assets(app, express)
  
  	// handle for all admin api calls
  	app.all('/admin_api/*', multiparty_middleware, function (req, res) {
  		admin_api.call(req, res, self)
  	})
  
  	// handle for all website api calls
  	app.use(function (req, res, next) {
  		logger.timestamp('requested: ' + req.url, 'server_usage')
  
  		// exclude admin calls and access to static assets
  		if (!/admin\/(.*)/.test(req.url) && !/assets\/(.*)/.test(req.url)) {
  
  			trollhunter.login(req)
  				.then(() => {
  
  					let requested_url = req.url
  
  					let a = requested_url.split('/').filter(x => x.length)
  					// serves index.html when empty or culture-only url is provided
  					if (requested_url.length <= 1 ||
  						(requested_url.split('/')[1] && enduro.config.cultures.indexOf(requested_url.split('/')[1]) + 1 && requested_url.split('/').length <= 2) ||
  						a[a.length - 1].indexOf('.') === -1
  					) {
  						requested_url += requested_url.slice(-1) === '/' ? 'index' : '/index'
  					}
  
  					// applies ab testing
  					return ab_tester.get_ab_tested_filepath(requested_url, req, res)
  
  				}, () => {
  					throw new Error('user not logged in')
  				})
  				.then((requested_url) => {
  					// serves the requested file
  					res.sendFile(enduro.project_path + '/' + enduro.config.build_folder + requested_url + '.html')
  				}, () => {
  					res.sendFile(enduro.config.admin_folder + '/enduro_login/index.html')
  				})
  		}
  	})
  
  	// init socket and store everybody in global enduro.sockets
  	const io = require('socket.io')(enduro.server)
  	enduro.sockets = io.sockets
  }
  
  enduro_server.prototype.stop = function () {
  	return new Promise(function (resolve, reject) {
  		enduro.server.close(() => {
  			resolve()
  		})
  	})
  }
  
  module.exports = new enduro_server()
  