<commit_before>/*
 The MIT License (see LICENSE)
 Copyright (C) 2014-2015 Teem2 LLC
*/

/**
 * @class NodeWebSocket {Internal}
 * Clean and simple websocket implementation for node
 */

define(function(require, exports, module){
	module.exports = NodeWebSocket
	var crypto = require('crypto')
	var url = require('url')
	var http = require('http')
	/**
	  * @constructor
	  * @param {Request} req The node request object to construct from
	  * @param {Socket} socket The socket object to connect to
	  */

	function NodeWebSocket(req, socket){
		if(typeof req == 'string'){
			this.initClient(req)
		}
		else{
			this.initServer(req, socket)
		}
	}

	body.call(NodeWebSocket.prototype)

	function body(){

		this.initClient = function(server_url){

			this.url = url.parse(server_url)
			// ok lets connect to a server
			var host = this.url.hostname + ':' + this.url.port
			// begin handshake
			var key = new Buffer(13 + '-' + Date.now()).toString('base64');
			var shasum = crypto.createHash('sha1');
			shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
			this.expectedServerKey = shasum.digest('base64');

			var origin =  host + this.url.path
			var opt = {
				port: this.url.port,
				host: this.url.hostname,
				path: this.url.path,
				headers: {
					'connection': 'Upgrade',
					'upgrade': 'websocket',
					'pragma':'no-cache',
					'host': host,
					'origin': 'http://' + origin,
					'sec-websocket-version': 13,
					'sec-websocket-key': key,
				}
			}
			var req = http.request(opt)

			req.on('error', function(err){
				console.log("WebSocket client " + err)
				if(this.onError) this.onError(err)
			}.bind(this))

			req.once('response', function(){
				console.log('WebSocket unexpected response')
			}.bind(this))

			req.once('upgrade', function(res, socket, upgradehead){
				if(res.headers['sec-websocket-accept'] != this.expectedServerKey){
					console.log('WebSocket unexpected server key')
				}
				this.socket = socket
				this.initState()
				if(this.onConnect) this.onConnect()
			}.bind(this))

			req.end()
		}

		this.initServer = function(req, socket){
			var version = req.headers['sec-websocket-version']
			if(version != 13){
				console.log("Incompatible websocket version requested (need 13) " + version)
				return socket.destroy()
			}

			this.socket = socket

		 	// calc key
			var key = req.headers['sec-websocket-key']
			var sha1 = crypto.createHash('sha1');
			sha1.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
			var ack = 'HTTP/1.1 101 Switching Protocols\r\n'+
				'Upgrade: websocket\r\n'+
				'Connection: Upgrade\r\n'+
				'Sec-WebSocket-Accept: ' + sha1.digest('base64') +'\r\n\r\n'

			this.socket.write(ack)
			this.is_server = true
			this.initState()
			this.first_queue = []
		}

		this.initState = function(){

			this.max = 100000000 // maximum receive buffer size (10 megs)
			this.header = new Buffer(14) // header
			this.output = new Buffer(10000) // output
			this.state = this.opcode // start in the opcode state
			this.expected = 1 // the bytes expected for the next state
			this.written = 0 // how much we have written in the output buffers
			this.read = 0 // the bytes we've read
			this.input = 0 // the input buffer received from the socket
			this.maskoff = 0 // the offset in the mask
			this.maskcount = 0 // mask counter
			this.paylen = 0 // payload length
			this.readyState = 1
			// 10 second ping frames
			this.pingframe = new Buffer(2)
			this.pingframe[0] = 9 | 128
			this.pingframe[1] = 0

			this.pongframe = new Buffer(2)
			this.pongframe[0] = 10 | 128
			this.pongframe[1] = 0

			if(this.is_server){
				this.ping_interval = setInterval(function(){
					if(!this.socket) clearInterval(this.ping_interval)
					else this.socket.write(this.pingframe)
				}.bind(this), 10000)
			}

			// Main socket data loop, uses state function to parse
			this.socket.on('data', function(data){
				this.input = data
				this.read = 0
				while(this.state());
			}.bind(this))

			this.socket.on('close', function(){
				this.close()
			}.bind(this))
		}

		/**
		  * @event onMessage
		  * @param {String} message The incoming message
		  */
		this.onMessage = function(message){
		}

		/**
		  * @event onClose
		  */
		this.onClose = function(){
		}

		/**
		  * @event onError
		  * @param {String} error The error
		  */
		this.onError = function(error){
		}

		this.error = function(t){
			console.log("Error on websocket " + t)
			this.onError(t)
			this.close()
		}

		/**
		  * @method send
		  * Send message on socket
		  * @param {String|Buffer} data Data to send
		  */
		this.send = function(data){
			if(this.first_queue){
				// put a tiny gap between a server connect and first data send
				if(!this.first_queue.length){
					setTimeout(function(){
						var q = this.first_queue
						this.first_queue = undefined
						for(var i = 0;i < q.length;i++){
							this.send(q[i])
						}
					}.bind(this),10)
				}
				this.first_queue.push(data)
				return
			}
			if(typeof data !== 'string' && !(data instanceof Buffer)) data = JSON.stringify(data)
			if(!this.socket) return
			var head
			var buf = new Buffer(data)
			if(buf.length < 126){
				head = new Buffer(2)
				head[1] = buf.length
			}
			else if (buf.length<=65535){
				head = new Buffer(4)
				head[1] = 126
				head.writeUInt16BE(buf.length, 2)
			}
			else {
				head = new Buffer(10)
				head[1] = 127
				head[2] = head[3] = head[4] = head[5] = 0
				head.writeUInt32BE(buf.length, 6)
			}
			head[0] = 128 | 1
			this.socket.write(head)
			this.socket.write(buf)
		}

		/**
		  * @method close
		  * Close socket
		  */
		this.close = function(){
			if(this.socket){
				this.onClose()
				this.socket.destroy()
				clearInterval(this.ping_interval)
				this.readyState = 3
			}
			this.socket = undefined
		}

		/* Internal head state */
		this.head = function(){
			var se = this.expected
			while(this.expected > 0 && this.read < this.input.length && this.written < this.header.length){
				this.header[this.written++] = this.input[this.read++], this.expected--
			}
			if(this.written > this.header.length) return this.err("unexpected data in header"+ se + s.toString())
			return this.expected != 0
		}

		/* Internal data state */
		this.data = function(){
			if(this.masked){
				while(this.expected > 0 && this.read < this.input.length){
					this.output[this.written++] = this.input[this.read++] ^ this.header[this.maskoff + (this.maskcount++&3)]
					this.expected--
				}
			}
			else{
				while(this.expected > 0 && this.read < this.input.length){
					this.output[this.written++] = this.input[this.read++]
					this.expected--
				}
			}

			if(this.expected) return false
			this.onMessage(this.output.toString('utf8', this.masked?0:2, this.written))
			this.expected = 1
			this.written = 0
			this.state = this.opcode
			return true
		}

		/* Internal mask state*/
		this.mask = function(){
			if(this.head()) return false
			if(!this.paylen){
				this.expected = 1
				this.written = 0
				this.state = this.opcode
				return true
			}
			this.maskoff = this.written - 4
			this.written = this.maskcount = 0
			this.expected = this.paylen
			if(this.paylen > this.max) return this.error("buffer size request too large " + l + " > " + max)
			if(this.paylen > this.output.length) this.output = new Buffer(this.paylen)
			this.state = this.data
			return true
		}

		/* Internal len8 state*/
		this.len8 = function(){
			if(this.head()) return false
			this.paylen = this.header.readUInt32BE(this.written - 4)
			if(this.masked){
				this.expected = 4
				this.state = this.mask
			}
			else{
				this.expected = this.paylen
				this.state = this.data
			}
			return true
		}

		/* Internal len2 state*/
		this.len2 = function(){
			if(this.head()) return
			this.paylen = this.header.readUInt16BE(this.written - 2)
			if(this.masked){
				this.expected = 4
				this.state = this.mask
			}
			else{
				this.expected = this.paylen
				this.state = this.data
			}
			return true
		}

		/* Internal len1 state*/
		this.len1 = function(){
			if(this.head()) return false
			// set masked flag
			if(!(this.header[this.written  - 1] & 128)){
				this.masked = false
			}
			else{
				this.masked = true
			}

			var type = this.header[this.written - 1] & 127
			if(type < 126){
				this.paylen = type
				this.expected = 4
				if(!this.masked){
					this.state = this.data
					this.expected = this.header[this.written  - 1]
				}
				else{
					this.state = this.mask
				}
			}
			else if(type == 126){
				this.expected = 2
				this.state = this.len2
			}
			else if(type == 127){
				this.expected = 8
				this.state = this.len8
			}
			return true
		}

		/* Internal pong state*/
		this.ping = function(){
			if(this.head()) return false
			if(this.header[this.written - 1] & 128){
				this.expected = 4
				this.paylen = 0
				this.state = this.mask
				return true
			}
			this.expected = 1
			this.written = 0
			this.state = this.opcode
			this.socket.write(this.pongframe)
			return true
		}

		/* Internal pong state*/
		this.pong = function(){
			if(this.head()) return false
			if(this.header[this.written - 1] & 128){
				this.expected = 4
				this.paylen = 0
				this.state = this.mask
				return true
			}
			this.expected = 1
			this.written = 0
			this.state = this.opcode
			return true
		}

		this.opcode = function(){
			if(this.head()) return
			var frame = this.header[0] & 128
			var type = this.header[0] & 15
			if(type == 1){
				if(!frame) return this.error("only final frames supported")
				this.expected = 1
				this.state = this.len1
				return true
			}
			if(type == 8) return this.close()
			if(type == 9){// ping frame
				this.expected = 1
				this.state = this.ping
				return true
			}
			if(type == 10){
				this.expected = 1
				this.state = this.pong
				return true
			}
			return this.error("opcode not supported " + type)
		}
	}
})<commit_msg>mask fix<commit_after>/*
 The MIT License (see LICENSE)
 Copyright (C) 2014-2015 Teem2 LLC
*/

/**
 * @class NodeWebSocket {Internal}
 * Clean and simple websocket implementation for node
 */

define(function(require, exports, module){
	module.exports = NodeWebSocket
	var crypto = require('crypto')
	var url = require('url')
	var http = require('http')
	/**
	  * @constructor
	  * @param {Request} req The node request object to construct from
	  * @param {Socket} socket The socket object to connect to
	  */

	function NodeWebSocket(req, socket){
		if(typeof req == 'string'){
			this.initClient(req)
		}
		else{
			this.initServer(req, socket)
		}
	}

	body.call(NodeWebSocket.prototype)

	function body(){

		this.initClient = function(server_url){

			this.url = url.parse(server_url)
			// ok lets connect to a server
			var host = this.url.hostname + ':' + this.url.port
			// begin handshake
			var key = new Buffer(13 + '-' + Date.now()).toString('base64');
			var shasum = crypto.createHash('sha1');
			shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
			this.expectedServerKey = shasum.digest('base64');

			var origin =  host + this.url.path
			var opt = {
				port: this.url.port,
				host: this.url.hostname,
				path: this.url.path,
				headers: {
					'connection': 'Upgrade',
					'upgrade': 'websocket',
					'pragma':'no-cache',
					'host': host,
					'origin': 'http://' + origin,
					'sec-websocket-version': 13,
					'sec-websocket-key': key,
				}
			}
			var req = http.request(opt)

			req.on('error', function(err){
				console.log("WebSocket client " + err)
				if(this.onError) this.onError(err)
			}.bind(this))

			req.once('response', function(){
				console.log('WebSocket unexpected response')
			}.bind(this))

			req.once('upgrade', function(res, socket, upgradehead){
				if(res.headers['sec-websocket-accept'] != this.expectedServerKey){
					console.log('WebSocket unexpected server key')
				}
				this.socket = socket
				this.initState()
				if(this.onConnect) this.onConnect()
			}.bind(this))

			req.end()
		}

		this.initServer = function(req, socket){
			var version = req.headers['sec-websocket-version']
			if(version != 13){
				console.log("Incompatible websocket version requested (need 13) " + version)
				return socket.destroy()
			}

			this.socket = socket

		 	// calc key
			var key = req.headers['sec-websocket-key']
			var sha1 = crypto.createHash('sha1');
			sha1.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
			var ack = 'HTTP/1.1 101 Switching Protocols\r\n'+
				'Upgrade: websocket\r\n'+
				'Connection: Upgrade\r\n'+
				'Sec-WebSocket-Accept: ' + sha1.digest('base64') +'\r\n\r\n'

			this.socket.write(ack)
			this.is_server = true
			this.initState()
			this.first_queue = []
		}

		this.initState = function(){

			this.max = 100000000 // maximum receive buffer size (10 megs)
			this.header = new Buffer(14) // header
			this.output = new Buffer(10000) // output
			this.state = this.opcode // start in the opcode state
			this.expected = 1 // the bytes expected for the next state
			this.written = 0 // how much we have written in the output buffers
			this.read = 0 // the bytes we've read
			this.input = 0 // the input buffer received from the socket
			this.maskoff = 0 // the offset in the mask
			this.maskcount = 0 // mask counter
			this.paylen = 0 // payload length
			this.readyState = 1
			// 10 second ping frames
			this.pingframe = new Buffer(2)
			this.pingframe[0] = 9 | 128
			this.pingframe[1] = 0

			this.pongframe = new Buffer(2)
			this.pongframe[0] = 10 | 128
			this.pongframe[1] = 0

			if(this.is_server){
				this.ping_interval = setInterval(function(){
					if(!this.socket) clearInterval(this.ping_interval)
					else this.socket.write(this.pingframe)
				}.bind(this), 10000)
			}

			// Main socket data loop, uses state function to parse
			this.socket.on('data', function(data){
				this.input = data
				this.read = 0
				while(this.state());
			}.bind(this))

			this.socket.on('close', function(){
				this.close()
			}.bind(this))
		}

		/**
		  * @event onMessage
		  * @param {String} message The incoming message
		  */
		this.onMessage = function(message){
		}

		/**
		  * @event onClose
		  */
		this.onClose = function(){
		}

		/**
		  * @event onError
		  * @param {String} error The error
		  */
		this.onError = function(error){
		}

		this.error = function(t){
			console.log("Error on websocket " + t)
			this.onError(t)
			this.close()
		}

		/**
		  * @method send
		  * Send message on socket
		  * @param {String|Buffer} data Data to send
		  */
		this.send = function(data){
			if(this.first_queue){
				// put a tiny gap between a server connect and first data send
				if(!this.first_queue.length){
					setTimeout(function(){
						var q = this.first_queue
						this.first_queue = undefined
						for(var i = 0;i < q.length;i++){
							this.send(q[i])
						}
					}.bind(this),10)
				}
				this.first_queue.push(data)
				return
			}
			if(typeof data !== 'string' && !(data instanceof Buffer)) data = JSON.stringify(data)
			if(!this.socket) return
			var head
			var buf = new Buffer(data)
			if(buf.length < 126){
				head = new Buffer(2)
				head[1] = buf.length
			}
			else if (buf.length<=65535){
				head = new Buffer(4)
				head[1] = 126
				head.writeUInt16BE(buf.length, 2)
			}
			else {
				head = new Buffer(10)
				head[1] = 127
				head[2] = head[3] = head[4] = head[5] = 0
				head.writeUInt32BE(buf.length, 6)
			}
			head[0] = 128 | 1
			this.socket.write(head)
			this.socket.write(buf)
		}

		/**
		  * @method close
		  * Close socket
		  */
		this.close = function(){
			if(this.socket){
				this.onClose()
				this.socket.destroy()
				clearInterval(this.ping_interval)
				this.readyState = 3
			}
			this.socket = undefined
		}

		/* Internal head state */
		this.head = function(){
			var se = this.expected
			while(this.expected > 0 && this.read < this.input.length && this.written < this.header.length){
				this.header[this.written++] = this.input[this.read++], this.expected--
			}
			if(this.written > this.header.length) return this.err("unexpected data in header"+ se + s.toString())
			return this.expected != 0
		}

		/* Internal data state */
		this.data = function(){
			if(this.masked){
				while(this.expected > 0 && this.read < this.input.length){
					this.output[this.written++] = this.input[this.read++] ^ this.header[this.maskoff + (this.maskcount++&3)]
					this.expected--
				}
			}
			else{
				while(this.expected > 0 && this.read < this.input.length){
					this.output[this.written++] = this.input[this.read++]
					this.expected--
				}
			}

			if(this.expected) return false
			this.onMessage(this.output.toString('utf8', this.masked?0:this.mask_correct, this.written))
			this.expected = 1
			this.written = 0
			this.state = this.opcode
			return true
		}

		/* Internal mask state*/
		this.mask = function(){
			if(this.head()) return false
			if(!this.paylen){
				this.expected = 1
				this.written = 0
				this.state = this.opcode
				return true
			}
			this.maskoff = this.written - 4
			this.written = this.maskcount = 0
			this.expected = this.paylen
			if(this.paylen > this.max) return this.error("buffer size request too large " + l + " > " + max)
			if(this.paylen > this.output.length) this.output = new Buffer(this.paylen)
			this.state = this.data
			return true
		}

		/* Internal len8 state*/
		this.len8 = function(){
			if(this.head()) return false
			this.paylen = this.header.readUInt32BE(this.written - 4)
			if(this.masked){
				this.expected = 4
				this.state = this.mask
			}
			else{
				this.mask_correct = 8
				this.expected = this.paylen
				this.state = this.data
			}
			return true
		}

		/* Internal len2 state*/
		this.len2 = function(){
			if(this.head()) return
			this.paylen = this.header.readUInt16BE(this.written - 2)
			if(this.masked){
				this.expected = 4
				this.state = this.mask
			}
			else{
				this.mask_correct = 4
				this.expected = this.paylen
				this.state = this.data
			}
			return true
		}

		/* Internal len1 state*/
		this.len1 = function(){
			if(this.head()) return false
			// set masked flag
			if(!(this.header[this.written  - 1] & 128)){
				this.masked = false
				this.mask_correct = 2
			}
			else{
				this.masked = true
			}

			var type = this.header[this.written - 1] & 127
			if(type < 126){
				this.paylen = type
				this.expected = 4
				if(!this.masked){
					this.state = this.data
					this.expected = this.header[this.written  - 1]
				}
				else{
					this.state = this.mask
				}
			}
			else if(type == 126){
				this.expected = 2
				this.state = this.len2
			}
			else if(type == 127){
				this.expected = 8
				this.state = this.len8
			}
			return true
		}

		/* Internal pong state*/
		this.ping = function(){
			if(this.head()) return false
			if(this.header[this.written - 1] & 128){
				this.expected = 4
				this.paylen = 0
				this.state = this.mask
				return true
			}
			this.expected = 1
			this.written = 0
			this.state = this.opcode
			this.socket.write(this.pongframe)
			return true
		}

		/* Internal pong state*/
		this.pong = function(){
			if(this.head()) return false
			if(this.header[this.written - 1] & 128){
				this.expected = 4
				this.paylen = 0
				this.state = this.mask
				return true
			}
			this.expected = 1
			this.written = 0
			this.state = this.opcode
			return true
		}

		this.opcode = function(){
			if(this.head()) return
			var frame = this.header[0] & 128
			var type = this.header[0] & 15
			if(type == 1){
				if(!frame) return this.error("only final frames supported")
				this.expected = 1
				this.state = this.len1
				return true
			}
			if(type == 8) return this.close()
			if(type == 9){// ping frame
				this.expected = 1
				this.state = this.ping
				return true
			}
			if(type == 10){
				this.expected = 1
				this.state = this.pong
				return true
			}
			return this.error("opcode not supported " + type)
		}
	}
})<|endoftext|>


<commit_before>// # DB API
// API for DB operations
var dataExport       = require('../data/export'),
    dataImport       = require('../data/import'),
    dataProvider     = require('../models'),
    fs               = require('fs-extra'),
    Promise          = require('bluebird'),
    _                = require('lodash'),
    path             = require('path'),
    errors           = require('../../server/errors'),
    canThis          = require('../permissions').canThis,
    api              = {},
    db;

api.settings         = require('./settings');

function isValidFile(ext) {
    if (ext === '.json') {
        return true;
    }
    return false;
}
/**
 * ## DB API Methods
 *
 * **See:** [API Methods](index.js.html#api%20methods)
 */
db = {
    /**
     * ### Export Content
     * Generate the JSON to export
     *
     * @public
     * @param {{context}} options
     * @returns {Promise} Ghost Export JSON format
     */
    exportContent: function (options) {
        options = options || {};

        // Export data, otherwise send error 500
        return canThis(options.context).exportContent.db().then(function () {
            return dataExport().then(function (exportedData) {
                return {db: [exportedData]};
            }).catch(function (error) {
                return Promise.reject(new errors.InternalServerError(error.message || error));
            });
        }, function () {
            return Promise.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
        });
    },
    /**
     * ### Import Content
     * Import posts, tags etc from a JSON blob
     *
     * @public
     * @param {{context}} options
     * @returns {Promise} Success
     */
    importContent: function (options) {
        options = options || {};
        var databaseVersion,
            type,
            ext,
            filepath;

        return canThis(options.context).importContent.db().then(function () {
            if (!options.importfile || !options.importfile.type || !options.importfile.path) {
                return Promise.reject(new errors.NoPermissionError('Please select a file to import.'));
            }

            type = options.importfile.type;
            ext = path.extname(options.importfile.name).toLowerCase();
            filepath = options.importfile.path;

            return Promise.resolve(isValidFile(ext)).then(function (result) {
                if (!result) {
                    return Promise.reject(new errors.UnsupportedMediaTypeError('Please select a .json file to import.'));
                }
            }).then(function () {
                return api.settings.read(
                    {key: 'databaseVersion', context: {internal: true}}
                ).then(function (response) {
                    var setting = response.settings[0];

                    return setting.value;
                });
            }).then(function (version) {
                databaseVersion = version;
                // Read the file contents
                return Promise.promisify(fs.readFile)(filepath);
            }).then(function (fileContents) {
                var importData;

                // Parse the json data
                try {
                    importData = JSON.parse(fileContents);

                    // if importData follows JSON-API format `{ db: [exportedData] }`
                    if (_.keys(importData).length === 1 && Array.isArray(importData.db)) {
                        importData = importData.db[0];
                    }
                } catch (e) {
                    errors.logError(e, 'API DB import content', 'check that the import file is valid JSON.');
                    return Promise.reject(new errors.BadRequest('Failed to parse the import JSON file'));
                }

                if (!importData.meta || !importData.meta.version) {
                    return Promise.reject(
                        new errors.ValidationError('Import data does not specify version', 'meta.version')
                    );
                }

                // Import for the current version
                return dataImport(databaseVersion, importData);
            }).then(api.settings.updateSettingsCache)
            .return({db: []})
            .finally(function () {
                // Unlink the file after import
                return Promise.promisify(fs.unlink)(filepath);
            });
        }, function () {
            return Promise.reject(new errors.NoPermissionError('You do not have permission to import data. (no rights)'));
        });
    },
    /**
     * ### Delete All Content
     * Remove all posts and tags
     *
     * @public
     * @param {{context}} options
     * @returns {Promise} Success
     */
    deleteAllContent: function (options) {
        options = options || {};

        return canThis(options.context).deleteAllContent.db().then(function () {
            return Promise.resolve(dataProvider.deleteAllContent())
                .return({db: []})
                .catch(function (error) {
                    return Promise.reject(new errors.InternalServerError(error.message || error));
                });
        }, function () {
            return Promise.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
        });
    }
};

module.exports = db;
<commit_msg>Fix DB API<commit_after>// # DB API
// API for DB operations
var dataExport       = require('../data/export'),
    dataImport       = require('../data/import'),
    dataProvider     = require('../models'),
    fs               = require('fs-extra'),
    Promise          = require('bluebird'),
    _                = require('lodash'),
    path             = require('path'),
    errors           = require('../../server/errors'),
    canThis          = require('../permissions').canThis,
    api              = {},
    db;

api.settings         = require('./settings');

function isValidFile(ext) {
    if (ext === '.json') {
        return true;
    }
    return false;
}
/**
 * ## DB API Methods
 *
 * **See:** [API Methods](index.js.html#api%20methods)
 */
db = {
    /**
     * ### Export Content
     * Generate the JSON to export
     *
     * @public
     * @param {{context}} options
     * @returns {Promise} Ghost Export JSON format
     */
    exportContent: function (options) {
        options = options || {};

        // Export data, otherwise send error 500
        return canThis(options.context).exportContent.db().then(function () {
            return dataExport().then(function (exportedData) {
                return {db: [exportedData]};
            }).catch(function (error) {
                return Promise.reject(new errors.InternalServerError(error.message || error));
            });
        }, function () {
            return Promise.reject(new errors.NoPermissionError('You do not have permission to export data (no rights).'));
        });
    },
    /**
     * ### Import Content
     * Import posts, tags etc from a JSON blob
     *
     * @public
     * @param {{context}} options
     * @returns {Promise} Success
     */
    importContent: function (options) {
        options = options || {};
        var databaseVersion,
            type,
            ext,
            filepath;

        return canThis(options.context).importContent.db().then(function () {
            if (!options.importfile || !options.importfile.type || !options.importfile.path) {
                return Promise.reject(new errors.NoPermissionError('Please select a file to import.'));
            }

            type = options.importfile.type;
            ext = path.extname(options.importfile.name).toLowerCase();
            filepath = options.importfile.path;

            return Promise.resolve(isValidFile(ext)).then(function (result) {
                if (!result) {
                    return Promise.reject(new errors.UnsupportedMediaTypeError('Please select a .json file to import.'));
                }
            }).then(function () {
                return api.settings.read(
                    {key: 'databaseVersion', context: {internal: true}}
                ).then(function (response) {
                    var setting = response.settings[0];

                    return setting.value;
                });
            }).then(function (version) {
                databaseVersion = version;
                // Read the file contents
                return Promise.promisify(fs.readFile)(filepath);
            }).then(function (fileContents) {
                var importData;

                // Parse the json data
                try {
                    importData = JSON.parse(fileContents);

                    // if importData follows JSON-API format `{ db: [exportedData] }`
                    if (_.keys(importData).length === 1 && Array.isArray(importData.db)) {
                        importData = importData.db[0];
                    }
                } catch (e) {
                    errors.logError(e, 'API DB import content', 'check that the import file is valid JSON.');
                    return Promise.reject(new errors.BadRequestError('Failed to parse the import JSON file.'));
                }

                if (!importData.meta || !importData.meta.version) {
                    return Promise.reject(
                        new errors.ValidationError('Import data does not specify version', 'meta.version')
                    );
                }

                // Import for the current version
                return dataImport(databaseVersion, importData);
            }).then(api.settings.updateSettingsCache)
            .return({db: []})
            .finally(function () {
                // Unlink the file after import
                return Promise.promisify(fs.unlink)(filepath);
            });
        }, function () {
            return Promise.reject(new errors.NoPermissionError('You do not have permission to import data (no rights).'));
        });
    },
    /**
     * ### Delete All Content
     * Remove all posts and tags
     *
     * @public
     * @param {{context}} options
     * @returns {Promise} Success
     */
    deleteAllContent: function (options) {
        options = options || {};

        return canThis(options.context).deleteAllContent.db().then(function () {
            return Promise.resolve(dataProvider.deleteAllContent())
                .return({db: []})
                .catch(function (error) {
                    return Promise.reject(new errors.InternalServerError(error.message || error));
                });
        }, function () {
            return Promise.reject(new errors.NoPermissionError('You do not have permission to export data (no rights).'));
        });
    }
};

module.exports = db;
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-tidoop (FI-WARE project).
 *
 * fiware-tidoop is free software: you can redistribute it and/or modify it under the terms of the GNU Affero
 * General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * fiware-tidoop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with fiware-tidoop. If not, see
 * http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License please contact with
 * francisco dot romerobueno at telefonica dot com
 */

/**
 * cosmos-gui main app
 *
 * Author: frb
 */

// Module dependencies
var express = require('express');
var boom = require('boom');
var stylus = require('stylus');
var nib = require('nib');
var config = require('../conf/cosmos-gui.json');
var mysqlDriver = require('./mysql_driver.js');
var OAuth2 = require('./oauth2').OAuth2;
var cmdRunner = require('./cmd_runner.js');

// Express configuration
var app = express();

app.set('views', __dirname + '/../views');
app.set('view engine', 'jade');
app.use(express.logger());
app.use(stylus.middleware(
    { src: __dirname + '/../public',
        compile: compile
    }
));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({secret: "skjghskdjfhbqigohqdiouk"}));
app.configure(function () {
    "use strict";
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
    app.use(express.static(__dirname + '/../public'));
});

function compile(str, path) {
    return stylus(str)
        .set('filename', path)
        .use(nib());
}

// Global variables
var port = config.gui.port;
var client_id = config.oauth2.client_id;
var client_secret = config.oauth2.client_secret;
var idmURL = config.oauth2.idmURL;
var response_type = config.oauth2.response_type;
var callbackURL = config.oauth2.callbackURL;
var hdfsQuota = config.hdfs.quota;

// Creates oauth library object with the config data
var oa = new OAuth2(client_id,
    client_secret,
    idmURL,
    '/oauth2/authorize',
    '/oauth2/token',
    callbackURL);

// Handles requests to the main page
app.get('/', function (req, res) {
    var access_token = req.session.access_token;

    // Check if the user had a session
    if (access_token) {
        // Get user information given its access token
        oa.get(idmURL + '/user/', access_token, function (error, response) {
            if (error) {
                res.send(boom.internal('There was some error when getting user information from the IdM', error));
            } else {
                // Get the user's IdM email (username)
                var idm_username = JSON.parse(response).email;
                req.session.idm_username = idm_username;

                // Check if the user, given its IdM username, has a Cosmos account
                mysqlDriver.getUser(idm_username, function(error, result) {
                    if (error) {
                        res.send(boom.internal('There was some error when getting user information from the ' +
                            'database', error));
                    } else if (result[0]) {
                        if (result[0].password) {
                            res.render('dashboard'); // both old and new Cosmos users with password
                        } else {
                            res.render('new_password'); // old Cosmos users not having a password
                        } // if else
                    } else {
                        res.render('new_account'); // new Cosmos users not having a username
                    } // if else
                });
            } // if else
        });
    } else {
        res.render('login');
    } // if else
});

// Redirection to IDM authentication portal
app.get('/login', function(req, res) {
    var path = oa.getAuthorizeUrl(response_type);
    res.redirect(path);
});

// Handles requests from IDM with the access code
app.get('/auth', function(req, res) {
    // Using the access code goes again to the IDM to obtain the access_token
    oa.getOAuthAccessToken(req.query.code, function (e, results){
    // Stores the access_token in a session cookie
        req.session.access_token = results.access_token;
        res.redirect('/');
    });
});

app.post('/new_account', function(req, res) {
    var idm_username = req.session.idm_username;
    var username = idm_username.split('@')[0];
    var password1 = req.body.password1;
    var password2 = req.body.password2;

    if (password1 === password2) {
        mysqlDriver.addUser(idm_username, username, password1, function(error, result) {
            if (error) {
                res.send(boom.internal('There was some error when putting user information in the database', error));
            } // if

            cmdRunner.run('bash', ['-c', 'useradd ' + username], function(error, result) {
                if (error) {
                    res.send(boom.internal('There was an error while adding the Unix user ' + username, error));
                } // if

                console.log('Successful command executed: \'bash -c useradd ' + username + '\'');
                cmdRunner.run('bash', ['-c', 'echo ' + password1 + ' | passwd ' + username + ' --stdin'], function(error, result) {
                    if (error) {
                        res.send(boom.internal('There was an error while setting the password for the user ' + username, error));
                    } // if

                    console.log('Successful command executed: \'bash -c echo ' + password1 + ' | passwd ' + username + ' --stdin\'');
                    cmdRunner.run('bash', ['-c', 'sudo -u hdfs hadoop fs -mkdir /user/' + username], function(error, result) {
                        if (error) {
                            res.send(boom.internal('There was an error while creating the HDFS folder for the user ' + username, error));
                        } // if

                        console.log('Successful command executed: \'bash -c sudo -u hdfs hadoop fs -mkdir /user/' + username + '\'');
                        cmdRunner.run('bash', ['-c', 'sudo -u hdfs hadoop fs -chown -R ' + username + ':' + username + ' /user/' + username], function(error, result) {
                            if (error) {
                                res.send(boom.internal('There was an error while changing the ownership of /user/' + username, error));
                            } // if

                            console.log('Successful command executed: \'bash -c sudo -u hdfs hadoop fs -chown -R ' + username + ':' + username + ' /user/' + username + '\'');
                            cmdRunner.run('bash', ['-c', 'sudo -u hdfs hadoop dfsadmin -setSpaceQuota ' + hdfsQuota + 'g /user/' + username], function(error, result) {

                                if (error) {
                                    res.send(boom.internal('There was an error while setting the quota to /user/' + username, error));
                                } // if

                                console.log('Successful command executed: \'bash -c sudo -u hdfs hadoop dfsadmin -setSpaceQuota ' + hdfsQuota + 'g /user/' + username + '\'');
                                res.redirect('/');
                            })
                        })
                    })
                })
            })
        });
    } else {
        res.redirect('/');
    } // if else
});

app.post('/new_password', function(req, res) {
    var idm_username = req.session.idm_username;
    var password1 = req.body.password1;
    var password2 = req.body.password2;

    if (password1 === password2) {
        mysqlDriver.addPassword(idm_username, password1, function(error, result) {
            if (error) {
                res.send(boom.internal('', error));
            } else {
                res.redirect('/');
            } // if else
        })
    } else {
        res.redirect('/');
    } // if else
});

// Handles logout requests to remove access_token from the session cookie
app.get('/logout', function(req, res){
    req.session.access_token = undefined;
    res.redirect('/');
});

// Create a permanent connection to MySQL, and start the server
mysqlDriver.connect(function(error, result) {
    if (error) {
        console.log('There was some error when connecting to MySQL database. The server will not be run. ' +
            'Details: ' + error);
    } else {
        // Start the application, listening at the configured port
        console.log("cosmos-gui running at http://localhost:" + port);
        app.listen(port);
    } // if else
});
<commit_msg>UPDATE the routes<commit_after>/**
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-tidoop (FI-WARE project).
 *
 * fiware-tidoop is free software: you can redistribute it and/or modify it under the terms of the GNU Affero
 * General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * fiware-tidoop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with fiware-tidoop. If not, see
 * http://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License please contact with
 * francisco dot romerobueno at telefonica dot com
 */

/**
 * cosmos-gui main app
 *
 * Author: frb
 */

// Module dependencies
var express = require('express');
var boom = require('boom');
var stylus = require('stylus');
var nib = require('nib');
var config = require('../conf/cosmos-gui.json');
var mysqlDriver = require('./mysql_driver.js');
var OAuth2 = require('./oauth2').OAuth2;
var cmdRunner = require('./cmd_runner.js');

// Express configuration
var app = express();

app.set('views', __dirname + '/../views');
app.set('view engine', 'jade');
app.use(express.logger());
app.use(stylus.middleware(
    { src: __dirname + '/../public',
        compile: compile
    }
));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({secret: "skjghskdjfhbqigohqdiouk"}));
app.configure(function () {
    "use strict";
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
    app.use(express.static(__dirname + '/../public'));
});

function compile(str, path) {
    return stylus(str)
        .set('filename', path)
        .use(nib());
}

// Global variables
var port = config.gui.port;
var client_id = config.oauth2.client_id;
var client_secret = config.oauth2.client_secret;
var idmURL = config.oauth2.idmURL;
var response_type = config.oauth2.response_type;
var callbackURL = config.oauth2.callbackURL;
var hdfsQuota = config.hdfs.quota;

// Creates oauth library object with the config data
var oa = new OAuth2(client_id,
    client_secret,
    idmURL,
    '/oauth2/authorize',
    '/oauth2/token',
    callbackURL);

// Handles requests to the main page
app.get('/', function (req, res) {
    var access_token = req.session.access_token;

    // Check if the user had a session
    if (access_token) {
        // Get user information given its access token
        oa.get(idmURL + '/user/', access_token, function (error, response) {
            if (error) {
                res.send(boom.internal('There was some error when getting user information from the IdM', error));
            } else {
                // Get the user's IdM email (username)
                var idm_username = JSON.parse(response).email;
                req.session.idm_username = idm_username;

                // Check if the user, given its IdM username, has a Cosmos account
                mysqlDriver.getUser(idm_username, function(error, result) {
                    if (error) {
                        res.send(boom.internal('There was some error when getting user information from the ' +
                            'database', error));
                    } else if (result[0]) {
                        if (result[0].password) {
                            res.render('dashboard'); // both old and new Cosmos users with password
                        } else {
                            res.render('new_password'); // old Cosmos users not having a password
                        } // if else
                    } else {
                        res.render('new_account'); // new Cosmos users not having a username
                    } // if else
                });
            } // if else
        });
    } else {
        res.render('login');
    } // if else
});

// Redirection to IDM authentication portal
app.get('/login', function(req, res) {
    var path = oa.getAuthorizeUrl(response_type);
    res.redirect(path);
});

// Handles requests from IDM with the access code
app.get('/auth', function(req, res) {
    // Using the access code goes again to the IDM to obtain the access_token
    oa.getOAuthAccessToken(req.query.code, function (e, results){
    // Stores the access_token in a session cookie
        req.session.access_token = results.access_token;
        res.redirect('/');
    });
});

app.post('/new_account', function(req, res) {
    var idm_username = req.session.idm_username;
    var username = idm_username.split('@')[0];
    var password1 = req.body.password1;
    var password2 = req.body.password2;

    if (password1 === password2) {
        mysqlDriver.addUser(idm_username, username, password1, function(error, result) {
            if (error) {
                res.send(boom.internal('There was some error when adding information in the database for user ' + username, error));
            } // if

            cmdRunner.run('bash', ['-c', 'useradd ' + username], function(error, result) {
                if (error) {
                    res.send(boom.internal('There was an error while adding the Unix user ' + username, error));
                } // if

                console.log('Successful command executed: \'bash -c useradd ' + username + '\'');
                cmdRunner.run('bash', ['-c', 'echo ' + password1 + ' | passwd ' + username + ' --stdin'], function(error, result) {
                    if (error) {
                        res.send(boom.internal('There was an error while setting the password for user ' + username, error));
                    } // if

                    console.log('Successful command executed: \'bash -c echo ' + password1 + ' | passwd ' + username + ' --stdin\'');
                    cmdRunner.run('bash', ['-c', 'sudo -u hdfs hadoop fs -mkdir /user/' + username], function(error, result) {
                        if (error) {
                            res.send(boom.internal('There was an error while creating the HDFS folder for user ' + username, error));
                        } // if

                        console.log('Successful command executed: \'bash -c sudo -u hdfs hadoop fs -mkdir /user/' + username + '\'');
                        cmdRunner.run('bash', ['-c', 'sudo -u hdfs hadoop fs -chown -R ' + username + ':' + username + ' /user/' + username], function(error, result) {
                            if (error) {
                                res.send(boom.internal('There was an error while changing the ownership of /user/' + username, error));
                            } // if

                            console.log('Successful command executed: \'bash -c sudo -u hdfs hadoop fs -chown -R ' + username + ':' + username + ' /user/' + username + '\'');
                            cmdRunner.run('bash', ['-c', 'sudo -u hdfs hadoop dfsadmin -setSpaceQuota ' + hdfsQuota + 'g /user/' + username], function(error, result) {

                                if (error) {
                                    res.send(boom.internal('There was an error while setting the quota to /user/' + username, error));
                                } // if

                                console.log('Successful command executed: \'bash -c sudo -u hdfs hadoop dfsadmin -setSpaceQuota ' + hdfsQuota + 'g /user/' + username + '\'');
                                res.redirect('/');
                            })
                        })
                    })
                })
            })
        });
    } else {
        res.redirect('/');
    } // if else
});

app.post('/new_password', function(req, res) {
    var idm_username = req.session.idm_username;
    var username = idm_username.split('@')[0];
    var password1 = req.body.password1;
    var password2 = req.body.password2;

    if (password1 === password2) {
        mysqlDriver.addPassword(idm_username, password1, function(error, result) {
            if (error) {
                res.send(boom.internal('There was an error while setting up the password for user ' + username, error));
            } else {
                res.redirect('/');
            } // if else
        })
    } else {
        res.redirect('/');
    } // if else
});

// Handles logout requests to remove access_token from the session cookie
app.get('/logout', function(req, res){
    req.session.access_token = undefined;
    res.redirect('/');
});

// Create a permanent connection to MySQL, and start the server
mysqlDriver.connect(function(error, result) {
    if (error) {
        console.log('There was some error when connecting to MySQL database. The server will not be run. ' +
            'Details: ' + error);
    } else {
        // Start the application, listening at the configured port
        console.log("cosmos-gui running at http://localhost:" + port);
        app.listen(port);
    } // if else
});
<|endoftext|>


<commit_before>'use strict';

const nodeBuiltinModules = require('module').builtinModules;
const readFileSync = require('fs').readFileSync;
const babel = require('rollup-plugin-babel');
const resolve = require('rollup-plugin-node-resolve');
const cwd = process.cwd();
const pkg = JSON.parse(readFileSync(`${cwd}/package.json`));

const pobConfig = JSON.parse(readFileSync(`${cwd}/.yo-rc.json`)).pob['pob-config'];

const hasReact = Boolean(
  (pkg.dependencies && pkg.dependencies.react) ||
    (pkg.peerDependencies && pkg.peerDependencies.react)
);

const nodeVersion = version => {
  switch (String(version)) {
    case '8':
      return '8.3';
    case '6':
      return '6.5';
    default:
      return version;
  }
};

const externalModules = nodeBuiltinModules
  .concat(Object.keys(pkg.dependencies || {}))
  .concat(Object.keys(pkg.peerDependencies || {}));

const createConfigForEnv = (entry, env, production) => {
  const devSuffix = production ? '' : '-dev';
  return {
    input: require.resolve(`./src/${entry}`, { paths: [cwd] }),
    output: env.formats.map(format => ({
      file: `dist/${entry}-${env.target}${env.version || ''}${devSuffix}.${format}.js`,
      format,
      sourcemap: true,
    })),
    external: externalModules,
    plugins: [
      babel({
        babelrc: false,
        presets: [
          [
            require.resolve('babel-preset-pob-env'),
            {
              modules: false,
              target: env.target,
              version: env.target === 'node' ? nodeVersion(env.version) : env.version,
              production,
              flow: true,
              react: hasReact,
            },
          ],
        ],
        plugins: [require.resolve('babel-plugin-external-helpers')],
        externalHelpers: false,
        exclude: 'node_modules/**',
      }),

      resolve({
        customResolveOptions: {
          extensions: ['.js', hasReact && '.jsx'].filter(Boolean), // TODO: add json ?
          moduleDirectory: [], // don't resolve node_modules
        },
      }),
    ],
  };
};

module.exports = () =>
  Array.prototype.concat.apply(
    [],
    pobConfig.envs.map(env =>
      Array.prototype.concat.apply(
        [],
        pobConfig.entries.map(entry => [
          createConfigForEnv(entry, env, true),
          createConfigForEnv(entry, env, false),
        ])
      )
    )
  );
<commit_msg>fix: external modules and disable exportDefaultName<commit_after>'use strict';

const nodeBuiltinModules = require('module').builtinModules;
const readFileSync = require('fs').readFileSync;
const babel = require('rollup-plugin-babel');
const resolve = require('rollup-plugin-node-resolve');
const cwd = process.cwd();
const pkg = JSON.parse(readFileSync(`${cwd}/package.json`));

const pobConfig = JSON.parse(readFileSync(`${cwd}/.yo-rc.json`)).pob['pob-config'];

const hasReact = Boolean(
  (pkg.dependencies && pkg.dependencies.react) ||
    (pkg.peerDependencies && pkg.peerDependencies.react)
);

const nodeVersion = version => {
  switch (String(version)) {
    case '8':
      return '8.3';
    case '6':
      return '6.5';
    default:
      return version;
  }
};

const externalModules = nodeBuiltinModules
  .concat(Object.keys(pkg.dependencies || {}))
  .concat(Object.keys(pkg.peerDependencies || {}));

const createConfigForEnv = (entry, env, production) => {
  const devSuffix = production ? '' : '-dev';
  return {
    input: require.resolve(`./src/${entry}`, { paths: [cwd] }),
    output: env.formats.map(format => ({
      file: `dist/${entry}-${env.target}${env.version || ''}${devSuffix}.${format}.js`,
      format,
      sourcemap: true,
    })),
    external: path => {
      if (path.includes('node_modules')) return true;
      // !path.startsWith('@') &&
      if (/^[a-z].*\//.test(path)) path = path.replace(/^([^/]+)\/.*$/, '$1');
      return externalModules.includes(path);
    },
    plugins: [
      babel({
        babelrc: false,
        presets: [
          [
            require.resolve('babel-preset-pob-env'),
            {
              modules: false,
              target: env.target,
              version: env.target === 'node' ? nodeVersion(env.version) : env.version,
              production,
              flow: true,
              react: hasReact,
              exportDefaultName: false, // this breaks the build (https://github.com/rollup/rollup/pull/2001 ?)
            },
          ],
        ],
        plugins: [require.resolve('babel-plugin-external-helpers')],
        externalHelpers: false,
        exclude: 'node_modules/**',
      }),

      resolve({
        customResolveOptions: {
          extensions: ['.js', hasReact && '.jsx'].filter(Boolean), // TODO: add json ?
          moduleDirectory: [], // don't resolve node_modules
        },
      }),
    ],
  };
};

module.exports = () =>
  Array.prototype.concat.apply(
    [],
    pobConfig.envs.map(env =>
      Array.prototype.concat.apply(
        [],
        pobConfig.entries.map(entry => [
          createConfigForEnv(entry, env, true),
          createConfigForEnv(entry, env, false),
        ])
      )
    )
  );
<|endoftext|>


<commit_before>/*
 * fis
 * http://web.baidu.com/
 */

'use strict';

exports.name = 'release';
exports.desc = 'build and deploy your project';
exports.register = function(commander, fis){

    function watch(opt){
        var root = fis.project.getProjectPath();
        var isWin = fis.util.isWin();
        var ignored = [];
        [ 'output', fis.project.conf.substring(root.length + 1) ].forEach(function(pattern){
            pattern = isWin ? pattern.replace(/\//g, '\\') : pattern;
            ignored.push('^' + fis.util.escapeReg(pattern) + '\b');
        });
        if(isWin){
            ignored.push(fis.util.escapeReg('\\.'));
        } else {
            ignored.push(fis.util.escapeReg('/.'));
        }
        ignored = new RegExp(ignored.join('|'), 'i');
        var timer = -1;
        var safePathReg = /^[:\\\/ _\-.\w]+$/i;
        function listener(path){
            if(safePathReg.test(path)){
                clearTimeout(timer);
                timer = setTimeout(function(){
                    release(opt);
                }, 500);
            }
        }
        require('chokidar')
            .watch(root, {
                ignored : /\\output\b/i,
                persistent: true
            })
            .on('add', listener)
            .on('change', listener)
            .on('unlink', function(path){
                fis.log.notice('delete file [' + path + ']');
            })
            .on('error', function(err){
                fis.log.error(err);
            });
    }

    var lastModified = {};
    var collection = {};
    var deploy = require('./lib/deploy.js');

    function release(opt){
        //write a white space.
        process.stdout.write(' ');
        //compile hooks
        var flag, cost, index = 0;
        opt.beforeEach = function(){
            flag = '.';
            cost = (new Date).getTime();
        };
        opt.afterEach = function(file){
            //cal compile time
            cost = (new Date).getTime() - cost;
            if(cost > 200){
                flag = flag.bold.yellow;
            } else if(cost < 100){
                flag = flag.grey;
            }
            if(index > 0 && index % 50 === 0){
                process.stdout.write('\n ');
            }
            process.stdout.write(flag);
            //collect file to deploy
            if(file.cache && file.cache.expired){
                collection[file.subpath] = file;
            } else {
                var mtime = file.getMtime().getTime();
                if(lastModified[file.subpath] !== mtime){
                    collection[file.subpath] = file;
                    lastModified[file.subpath] = mtime;
                }
            }
            index++;
        };

        //release
        fis.release(opt, function(ret){
            process.stdout.write('\n');
            fis.util.map(ret.pkg, collection, true);
            deploy(opt.dest, opt.md5, collection, fis);
            collection = {};
        });
    }

    commander
        .option('-d, --dest <names>', 'release output destination', String, 'preview')
        .option('-w, --watch', 'monitor the changes of project')
        .option('-c, --clean', 'clean cache before releasing')
        .option('-t, --type <ext>', 'resouce map type', String, 'php')
        .option('-m, --md5 <level>', 'md5 release option', parseInt, 0)
        .option('-D, --domain', 'add domain', Boolean, false)
        .option('-H, --no-hint', 'without hint', Boolean, true)
        .option('-O, --no-optimize', 'without optimize', Boolean, true)
        .option('-P, --no-package', 'without package', Boolean, true)
        .option('--debug', 'debug mode', Boolean, false)
        .action(function(options){
            var cwd = fis.util.realpath(process.cwd()),
                filename = fis.config.get('system.conf', fis.project.DEFAULT_CONF_FILE),
                pos = cwd.length, conf;
            do {
                cwd  = cwd.substring(0, pos);
                conf = cwd + '/' + filename;
                if(fis.util.exists(conf)){
                    //merge standard conf
                    fis.config.merge(fis.util.readJSON(__dirname + '/standard.json'));
                    //init project
                    fis.project.init(cwd, conf, function(){

                        //configure log
                        fis.log.level = options.debug ? fis.log.L_ALL : fis.log.level;
                        fis.log.throw = true;

                        //compile setup
                        var tmp = fis.compile.setup({
                            debug    : options.debug,
                            optimize : options.optimize,
                            hint     : options.hint,
                            hash     : options.md5 > 0,
                            domain   : options.domain
                        });

                        if(options.clean){
                            fis.cache.clean(tmp);
                        }

                        if(options.watch){
                            watch(options);
                        } else {
                            release(options);
                        }
                    });
                    return;
                }
            } while(pos > 0);
            fis.log.error('unable to find fis-conf file [' + filename + ']');
        });
};<commit_msg>修复编译bug<commit_after>/*
 * fis
 * http://web.baidu.com/
 */

'use strict';

exports.name = 'release';
exports.desc = 'build and deploy your project';
exports.register = function(commander, fis){

    function watch(opt){
        var root = fis.project.getProjectPath();
        var isWin = fis.util.isWin();
        var ignored = [];
        [ 'output', fis.project.conf.substring(root.length + 1) ].forEach(function(pattern){
            pattern = isWin ? pattern.replace(/\//g, '\\') : pattern;
            ignored.push('^' + fis.util.escapeReg(pattern) + '\b');
        });
        if(isWin){
            ignored.push(fis.util.escapeReg('\\.'));
        } else {
            ignored.push(fis.util.escapeReg('/.'));
        }
        ignored = new RegExp(ignored.join('|'), 'i');
        var timer = -1;
        var safePathReg = /^[:\\\/ _\-.\w]+$/i;
        function listener(path){
            if(safePathReg.test(path)){
                clearTimeout(timer);
                timer = setTimeout(function(){
                    release(opt);
                }, 500);
            }
        }
        require('chokidar')
            .watch(root, {
                ignored : /\\output\b/i,
                persistent: true
            })
            .on('add', listener)
            .on('change', listener)
            .on('unlink', function(path){
                fis.log.notice('delete file [' + path + ']');
            })
            .on('error', function(err){
                fis.log.error(err);
            });
    }

    var lastModified = {};
    var collection = {};
    var deploy = require('./lib/deploy.js');

    function release(opt){
        //write a white space.
        process.stdout.write(' ');
        //compile hooks
        var flag, cost, index = 0;
        opt.beforeEach = function(){
            flag = '.';
            cost = (new Date).getTime();
        };
        opt.afterEach = function(file){
            //cal compile time
            cost = (new Date).getTime() - cost;
            if(cost > 200){
                flag = flag.bold.yellow;
            } else if(cost < 100){
                flag = flag.grey;
            }
            var collected = false;
            //collect file to deploy
            if(file.cache && file.cache.expired){
                collection[file.subpath] = file;
                collected = true;
            } else {
                var mtime = file.getMtime().getTime();
                if(lastModified[file.subpath] !== mtime){
                    lastModified[file.subpath] = mtime;
                    collection[file.subpath] = file;
                    collected = true;
                }
            }
            if(collected){
                if(index > 0 && index % 50 === 0){
                    process.stdout.write('\n ');
                }
                process.stdout.write(flag);
            }
            index++;
        };

        //release
        fis.release(opt, function(ret){
            process.stdout.write('\n');
            fis.util.map(ret.pkg, collection, true);
            deploy(opt.dest, opt.md5, collection, fis);
            collection = {};
        });
    }

    commander
        .option('-d, --dest <names>', 'release output destination', String, 'preview')
        .option('-w, --watch', 'monitor the changes of project')
        .option('-c, --clean', 'clean cache before releasing')
        .option('-t, --type <ext>', 'resouce map type', String, 'php')
        .option('-m, --md5 <level>', 'md5 release option', parseInt, 0)
        .option('-D, --domain', 'add domain', Boolean, false)
        .option('-H, --no-hint', 'without hint', Boolean, true)
        .option('-O, --no-optimize', 'without optimize', Boolean, true)
        .option('-P, --no-package', 'without package', Boolean, true)
        .option('--debug', 'debug mode', Boolean, false)
        .action(function(options){
            var cwd = fis.util.realpath(process.cwd()),
                filename = fis.config.get('system.conf', fis.project.DEFAULT_CONF_FILE),
                pos = cwd.length, conf;
            do {
                cwd  = cwd.substring(0, pos);
                conf = cwd + '/' + filename;
                if(fis.util.exists(conf)){
                    //merge standard conf
                    fis.config.merge(fis.util.readJSON(__dirname + '/standard.json'));
                    //init project
                    fis.project.init(cwd, conf, function(){

                        //configure log
                        fis.log.level = options.debug ? fis.log.L_ALL : fis.log.level;
                        fis.log.throw = true;

                        //compile setup
                        var tmp = fis.compile.setup({
                            debug    : options.debug,
                            optimize : options.optimize,
                            hint     : options.hint,
                            hash     : options.md5 > 0,
                            domain   : options.domain
                        });

                        if(options.clean){
                            fis.cache.clean(tmp);
                        }

                        if(options.watch){
                            watch(options);
                        } else {
                            release(options);
                        }
                    });
                    return;
                }
            } while(pos > 0);
            fis.log.error('unable to find fis-conf file [' + filename + ']');
        });
};<|endoftext|>


<commit_before>'use strict';

var instanceCount = require('../../common/diagramPlugins/instanceCount');

var fs = require('fs');
var template = fs.readFileSync(__dirname + '/overlayAction.html', 'utf8');

module.exports = ['ViewsProvider',  function(ViewsProvider) {
  ViewsProvider.registerDefaultView('cockpit.processDefinition.diagram.action', {
    id: 'activity-instance-statistics-overlay',
    template:template,
    controller: [
      '$scope', 'Loaders', 'get','$filter', '$rootScope', '$translate','configuration',
      function($scope, Loaders, get, $filter, $rootScope, $translate, configuration
      ) {

        $scope.toggle = configuration.getRuntimeActivityInstanceMetrics();
        $scope.isLoading = false;

        showOverlays();
        $scope.toggleOverlay = function() {
          $scope.toggle = !$scope.toggle;
          if($scope.toggle) {
            showOverlays();
          } else {
            removeOverlays();
          }
        };

        function toggleIsLoading() {
          $scope.isLoading = !$scope.isLoading;
        }

        function showOverlays() {
          $scope.isLoading = true;

          var callbacks = {
            observe: observe,
            getData: getInstancesCountsForElement,
            updateOverlayNodes: updateOverlayNodes,
            isActive: isActive,
            toggleIsLoading: toggleIsLoading
          };

          if(!$scope.processDiagram) {
            $scope.processData.observe('processDiagram', function(processDiagram) {
              $scope.processDiagram = processDiagram;
              instanceCount($scope, $scope.viewer, $scope.processData, $scope.processDiagram, Loaders, $rootScope, callbacks);
            });
          } else {
            instanceCount($scope, $scope.viewer, $scope.processData, $scope.processDiagram, Loaders, $rootScope, callbacks);
          }
        }

        function removeOverlays() {
          Array.from(document.getElementsByClassName('djs-overlay')).forEach( function(element) { element.remove(); });
        }

        function observe(callback) {
          $scope.processData.observe(['activityInstanceStatistics'], function(activityInstanceStatistics) {
            callback([activityInstanceStatistics]);
          });
        }

        function isActive(data) {
          return data.instances || data.incidents;
        }

        var getIncidentCount = function(incidents) {
          if(!incidents) {
            return 0;
          }

          return incidents.reduce(function(sum, incident) {
            return sum + incident.incidentCount;
          }, 0);
        };

        function getInstancesCountsForElement(element, activityInstanceStatistics) {
          var stats = getStatsWithId(activityInstanceStatistics, element.id);
          var statsMi = getStatsWithId(activityInstanceStatistics, element.id + '#multiInstanceBody');

          var statsIncidents = get(stats, ['incidents'], []);
          var statsMiIncidents = get(statsMi, ['incidents'], []);
          var incidents = statsIncidents.concat(statsMiIncidents);
          var incidentsCount = getIncidentCount(incidents);

          return {
            instances: get(stats, ['instances'], 0) + get(statsMi, ['instances'], 0),
            incidents: incidentsCount
          };
        }

        function getStatsWithId(activityInstanceStatistics, id) {
          return activityInstanceStatistics.filter(function(entry) {
            return entry.id === id;
          })[0];
        }
        function updateOverlayNodes(nodes, data) {
          nodes.instancesNode.text(
            $filter('abbreviateNumber')(data.instances)
          );

          nodes.incidentsNode.text(
            $filter('abbreviateNumber')(data.incidents)
          );

          if (data.instances <= 0) {
            nodes.instancesNode.hide();
          } else {
            nodes.instancesNode.show();
            nodes.instancesNode.tooltip({
              container: 'body',
              title: $translate.instant('PLUGIN_ACTIVITY_INSTANCE_RUNNING_ACTIVITY_INSTANCES'),
              placement: 'top',
              animation: false
            });
          }

          if (data.incidents) {
            nodes.incidentsNode.show();
            nodes.incidentsNode.tooltip({
              container: 'body',
              title: $translate.instant('PLUGIN_ACTIVITY_INSTANCE_OPEN_INCIDENTS'),
              placement: 'top',
              animation: false
            });
          } else {
            nodes.incidentsNode.hide();
          }
        }
      }
    ]
  });
}];
<commit_msg>chore(maintain): reformat code of instanceCount<commit_after>'use strict';

var instanceCount = require('../../common/diagramPlugins/instanceCount');

var fs = require('fs');
var template = fs.readFileSync(__dirname + '/overlayAction.html', 'utf8');

module.exports = ['ViewsProvider',  function(ViewsProvider) {
  ViewsProvider.registerDefaultView('cockpit.processDefinition.diagram.action', {
    id: 'activity-instance-statistics-overlay',
    template:template,
    controller: [
      '$scope', 'Loaders', 'get','$filter', '$rootScope', '$translate','configuration',
      function($scope, Loaders, get, $filter, $rootScope, $translate, configuration
      ) {

        $scope.toggle = configuration.getRuntimeActivityInstanceMetrics();
        $scope.isLoading = false;

        showOverlays();
        $scope.toggleOverlay = function() {
          $scope.toggle = !$scope.toggle;
          if($scope.toggle) {
            showOverlays();
          } else {
            removeOverlays();
          }
        };

        function toggleIsLoading() {
          $scope.isLoading = !$scope.isLoading;
        }

        function showOverlays() {
          $scope.isLoading = true;

          var callbacks = {
            observe: observe,
            getData: getInstancesCountsForElement,
            updateOverlayNodes: updateOverlayNodes,
            isActive: isActive,
            toggleIsLoading: toggleIsLoading
          };

          instanceCount($scope, $scope.viewer, $scope.processData, $scope.processDiagram, Loaders, $rootScope, callbacks);
        }

        function removeOverlays() {
          Array.from(document.getElementsByClassName('djs-overlay')).forEach( function(element) { element.remove(); });
        }

        $scope.processData.observe('processDiagram', function(processDiagram) {
          $scope.processDiagram = processDiagram;
          showOverlays();
        });

        function observe(callback) {
          $scope.processData.observe(['activityInstanceStatistics'], function(activityInstanceStatistics) {
            callback([activityInstanceStatistics]);
          });
        }

        function isActive(data) {
          return data.instances || data.incidents;
        }

        var getIncidentCount = function(incidents) {
          if(!incidents) {
            return 0;
          }

          return incidents.reduce(function(sum, incident) {
            return sum + incident.incidentCount;
          }, 0);
        };

        function getInstancesCountsForElement(element, activityInstanceStatistics) {
          var stats = getStatsWithId(activityInstanceStatistics, element.id);
          var statsMi = getStatsWithId(activityInstanceStatistics, element.id + '#multiInstanceBody');

          var statsIncidents = get(stats, ['incidents'], []);
          var statsMiIncidents = get(statsMi, ['incidents'], []);
          var incidents = statsIncidents.concat(statsMiIncidents);
          var incidentsCount = getIncidentCount(incidents);

          return {
            instances: get(stats, ['instances'], 0) + get(statsMi, ['instances'], 0),
            incidents: incidentsCount
          };
        }

        function getStatsWithId(activityInstanceStatistics, id) {
          return activityInstanceStatistics.filter(function(entry) {
            return entry.id === id;
          })[0];
        }
        function updateOverlayNodes(nodes, data) {
          nodes.instancesNode.text(
            $filter('abbreviateNumber')(data.instances)
          );

          nodes.incidentsNode.text(
            $filter('abbreviateNumber')(data.incidents)
          );

          if (data.instances <= 0) {
            nodes.instancesNode.hide();
          } else {
            nodes.instancesNode.show();
            nodes.instancesNode.tooltip({
              container: 'body',
              title: $translate.instant('PLUGIN_ACTIVITY_INSTANCE_RUNNING_ACTIVITY_INSTANCES'),
              placement: 'top',
              animation: false
            });
          }

          if (data.incidents) {
            nodes.incidentsNode.show();
            nodes.incidentsNode.tooltip({
              container: 'body',
              title: $translate.instant('PLUGIN_ACTIVITY_INSTANCE_OPEN_INCIDENTS'),
              placement: 'top',
              animation: false
            });
          } else {
            nodes.incidentsNode.hide();
          }
        }
      }
    ]
  });
}];
<|endoftext|>


<commit_before>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2017 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import PropTypes from 'prop-types';
import React from 'react';

import SideNavLayout from './../SideNavLayout';
import * as routes from './../../constants/routes';

const links = [
  {
    id: 'COMPONENTS',
    category: 'Web components',
    sort: true,
    links: [
      { id: 'TYPOGRAPHY', route: routes.TYPOGRAPHY, children: 'Typography' },
      { id: 'BUTTONS', route: routes.BUTTONS, children: 'Buttons' },
      { id: 'ICONS', route: routes.ICONS, children: 'Icons' },
      { id: 'SPINNERS', route: routes.SPINNERS, children: 'Spinners' },
      { id: 'FORMS', route: routes.FORMS, children: 'Forms' },
      { id: 'CARDS', route: routes.CARDS, children: 'Cards' },
      { id: 'CHIPS', route: routes.CHIPS, children: 'Chips' },
      { id: 'BADGE', route: routes.BADGE, children: 'Badge' },
      { id: 'PANELS', route: routes.PANELS, children: 'Panels' },
      { id: 'IMAGES', route: routes.IMAGES, children: 'Images' },
      { id: 'BANNER_ALERTS', route: routes.BANNER_ALERTS, children: 'Banner alerts' },
      { id: 'MODALS', route: routes.MODALS, children: 'Modals' },
      { id: 'AUTOSUGGEST', route: routes.AUTOSUGGEST, children: 'Autosuggest' },
      { id: 'POPOVERS', route: routes.POPOVERS, children: 'Popovers' },
      { id: 'CALENDAR', route: routes.CALENDAR, children: 'Calendar' },
      { id: 'DATEPICKER', route: routes.DATEPICKER, children: 'Datepicker' },
      { id: 'TOOLTIPS', route: routes.TOOLTIPS, children: 'Tooltips' },
      { id: 'ACCORDIONS', route: routes.ACCORDIONS, children: 'Accordions' },
      { id: 'NUDGERS', route: routes.NUDGERS, children: 'Nudgers' },
      { id: 'PROGRESS', route: routes.PROGRESS, children: 'Progress bars' },
      { id: 'TICKETS', route: routes.TICKETS, children: 'Tickets' },
      { id: 'HORIZONTAL_NAV', route: routes.HORIZONTAL_NAV, children: 'Horizontal navigation' },
      { id: 'FIELDSETS', route: routes.FIELDSETS, children: 'Fieldsets' },
      { id: 'STAR_RATINGS', route: routes.STAR_RATING, children: 'Star rating' },
      { id: 'BAR_CHARTS', route: routes.BARCHARTS, children: 'Bar charts' },
      { id: 'PAGINATION', route: routes.PAGINATION, children: 'Pagination' },
      { id: 'SLIDERS', route: routes.SLIDERS, children: 'Sliders' },
      { id: 'DRAWER', route: routes.DRAWER, children: 'Drawer' },
      { id: 'CAROUSELS', route: null, children: 'Carousel' },
      { id: 'TOASTS', route: null, children: 'Toast' },
      { id: 'VERTICAL_NAV', route: null, children: 'Vertical navigation' },
      { id: 'OVERFLOW_NAV', route: null, children: 'Overflow navigation' },
      { id: 'BREADCRUMBS', route: null, children: 'Breadcrumbs' },
      { id: 'NUMERICAL_RATING', route: null, children: 'Numerical rating' },
      { id: 'FLIGHT_ITINERARIES', route: null, children: 'Flight itinerary' },
      { id: 'DIALOGS', route: null, children: 'Dialogs' },
      { id: 'BREAKPOINTS', route: routes.BREAKPOINTS, children: 'Breakpoints' },
      { id: 'HORIZONTAL_GRID', route: routes.HORIZONTAL_GRID, children: 'Horizontal grid' },
    ],
  },
  {
    id: 'NATIVE',
    category: 'Native components',
    sort: true,
    links: [
      { id: 'NATIVE_BANNER_ALERT', route: routes.NATIVE_BANNER_ALERT, children: 'Banner alerts' },
      { id: 'NATIVE_BUTTON', route: routes.NATIVE_BUTTON, children: 'Button' },
      { id: 'NATIVE_CARDS', route: routes.NATIVE_CARDS, children: 'Cards' },
      { id: 'NATIVE_HORIZONTAL_NAV', route: routes.NATIVE_HORIZONTAL_NAV, children: 'Horizontal navigation' },
      { id: 'NATIVE_ICONS', route: routes.NATIVE_ICONS, children: 'Icons' },
      { id: 'NATIVE_INPUT', route: routes.NATIVE_INPUT, children: 'Text input' },
      { id: 'NATIVE_SPINNER', route: routes.NATIVE_SPINNER, children: 'Spinners' },
      { id: 'NATIVE_SWITCH', route: routes.NATIVE_SWITCH, children: 'Switches' },
      { id: 'NATIVE_TEXT', route: routes.NATIVE_TEXT, children: 'Text' },
      { id: 'NATIVE_TICKETS', route: null, children: 'Tickets' },
      { id: 'NATIVE_STAR_RATING', route: null, children: 'Star rating' },
      { id: 'NATIVE_NUDGER', route: null, children: 'Nudger' },
    ],
  },
  {
    id: 'UTILITIES',
    category: 'Utilities',
    sort: true,
    links: [
      { id: 'ALIGNMENT', route: routes.ALIGNMENT, children: 'Alignment' },
      { id: 'THEMING', route: routes.THEMING, children: 'Theming' },
    ],
  },
];

const DocsLayout = ({ children, ...rest }) => <SideNavLayout links={links} {...rest}>{children}</SideNavLayout>;

DocsLayout.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]).isRequired,
};

export default DocsLayout;
<commit_msg>[NOJIRA] Hide pagination docs page for now<commit_after>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2017 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import PropTypes from 'prop-types';
import React from 'react';

import SideNavLayout from './../SideNavLayout';
import * as routes from './../../constants/routes';

const links = [
  {
    id: 'COMPONENTS',
    category: 'Web components',
    sort: true,
    links: [
      { id: 'TYPOGRAPHY', route: routes.TYPOGRAPHY, children: 'Typography' },
      { id: 'BUTTONS', route: routes.BUTTONS, children: 'Buttons' },
      { id: 'ICONS', route: routes.ICONS, children: 'Icons' },
      { id: 'SPINNERS', route: routes.SPINNERS, children: 'Spinners' },
      { id: 'FORMS', route: routes.FORMS, children: 'Forms' },
      { id: 'CARDS', route: routes.CARDS, children: 'Cards' },
      { id: 'CHIPS', route: routes.CHIPS, children: 'Chips' },
      { id: 'BADGE', route: routes.BADGE, children: 'Badge' },
      { id: 'PANELS', route: routes.PANELS, children: 'Panels' },
      { id: 'IMAGES', route: routes.IMAGES, children: 'Images' },
      { id: 'BANNER_ALERTS', route: routes.BANNER_ALERTS, children: 'Banner alerts' },
      { id: 'MODALS', route: routes.MODALS, children: 'Modals' },
      { id: 'AUTOSUGGEST', route: routes.AUTOSUGGEST, children: 'Autosuggest' },
      { id: 'POPOVERS', route: routes.POPOVERS, children: 'Popovers' },
      { id: 'CALENDAR', route: routes.CALENDAR, children: 'Calendar' },
      { id: 'DATEPICKER', route: routes.DATEPICKER, children: 'Datepicker' },
      { id: 'TOOLTIPS', route: routes.TOOLTIPS, children: 'Tooltips' },
      { id: 'ACCORDIONS', route: routes.ACCORDIONS, children: 'Accordions' },
      { id: 'NUDGERS', route: routes.NUDGERS, children: 'Nudgers' },
      { id: 'PROGRESS', route: routes.PROGRESS, children: 'Progress bars' },
      { id: 'TICKETS', route: routes.TICKETS, children: 'Tickets' },
      { id: 'HORIZONTAL_NAV', route: routes.HORIZONTAL_NAV, children: 'Horizontal navigation' },
      { id: 'FIELDSETS', route: routes.FIELDSETS, children: 'Fieldsets' },
      { id: 'STAR_RATINGS', route: routes.STAR_RATING, children: 'Star rating' },
      { id: 'BAR_CHARTS', route: routes.BARCHARTS, children: 'Bar charts' },
      { id: 'SLIDERS', route: routes.SLIDERS, children: 'Sliders' },
      { id: 'DRAWER', route: routes.DRAWER, children: 'Drawer' },
      { id: 'PAGINATION', route: null, children: 'Pagination' },
      { id: 'CAROUSELS', route: null, children: 'Carousel' },
      { id: 'TOASTS', route: null, children: 'Toast' },
      { id: 'VERTICAL_NAV', route: null, children: 'Vertical navigation' },
      { id: 'OVERFLOW_NAV', route: null, children: 'Overflow navigation' },
      { id: 'BREADCRUMBS', route: null, children: 'Breadcrumbs' },
      { id: 'NUMERICAL_RATING', route: null, children: 'Numerical rating' },
      { id: 'FLIGHT_ITINERARIES', route: null, children: 'Flight itinerary' },
      { id: 'DIALOGS', route: null, children: 'Dialogs' },
      { id: 'BREAKPOINTS', route: routes.BREAKPOINTS, children: 'Breakpoints' },
      { id: 'HORIZONTAL_GRID', route: routes.HORIZONTAL_GRID, children: 'Horizontal grid' },
    ],
  },
  {
    id: 'NATIVE',
    category: 'Native components',
    sort: true,
    links: [
      { id: 'NATIVE_BANNER_ALERT', route: routes.NATIVE_BANNER_ALERT, children: 'Banner alerts' },
      { id: 'NATIVE_BUTTON', route: routes.NATIVE_BUTTON, children: 'Button' },
      { id: 'NATIVE_CARDS', route: routes.NATIVE_CARDS, children: 'Cards' },
      { id: 'NATIVE_HORIZONTAL_NAV', route: routes.NATIVE_HORIZONTAL_NAV, children: 'Horizontal navigation' },
      { id: 'NATIVE_ICONS', route: routes.NATIVE_ICONS, children: 'Icons' },
      { id: 'NATIVE_INPUT', route: routes.NATIVE_INPUT, children: 'Text input' },
      { id: 'NATIVE_SPINNER', route: routes.NATIVE_SPINNER, children: 'Spinners' },
      { id: 'NATIVE_SWITCH', route: routes.NATIVE_SWITCH, children: 'Switches' },
      { id: 'NATIVE_TEXT', route: routes.NATIVE_TEXT, children: 'Text' },
      { id: 'NATIVE_TICKETS', route: null, children: 'Tickets' },
      { id: 'NATIVE_STAR_RATING', route: null, children: 'Star rating' },
      { id: 'NATIVE_NUDGER', route: null, children: 'Nudger' },
    ],
  },
  {
    id: 'UTILITIES',
    category: 'Utilities',
    sort: true,
    links: [
      { id: 'ALIGNMENT', route: routes.ALIGNMENT, children: 'Alignment' },
      { id: 'THEMING', route: routes.THEMING, children: 'Theming' },
    ],
  },
];

const DocsLayout = ({ children, ...rest }) => <SideNavLayout links={links} {...rest}>{children}</SideNavLayout>;

DocsLayout.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]).isRequired,
};

export default DocsLayout;
<|endoftext|>