<commit_before>var EventEmitter = require('events').EventEmitter;
var WebSocketEmitter = require('./web-socket-emitter');
var uuid = require('hat');

// voxel dependencies
var Coordinates = require('./coordinates');
var encoder = require('./rle-encoder');
var lru = require('./lru');
var debug = true;

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}

module.exports = Server;

function Server(config, chunkStore, serverSettings, clientSettings) {
    // force instantiation via `new` keyword
    //if(!(this instanceof Server)) { return new Server(serverSettings || {}, clientSettings || {}) }
    this.config = config;
    this.chunkStore = chunkStore;
    this.serverSettings = serverSettings;
    this.clientSettings = clientSettings;

    this.requestedChunks = {};

    var chunkSize = config.chunkSize;
    var origin = [0, 0, 0];
    var step = chunkSize * config.worldRadius;
    this.lastWorldChunks = [
        // Lower chunk
        origin[0] - step,
        origin[1] - step,
        origin[2] - step,

        // Farther chunk
        origin[0] + step,
        origin[1] + step,
        origin[2] + step
    ];
    this.initialize();
};

Server.prototype.initialize = function() {
    var self = this;
    var clients = this.clients = {};
    this.emitter = new EventEmitter();
    this.coords = Coordinates(self.config.chunkSize);

    this.encodedChunkCache = new lru(10);

    // chunkId -> {clientIdA: true, clientIdB: true}
    this.chunksForClients = {};

    this.chunkStore.emitter.on('got', function(chunk) {
        if (debug) {
            console.log('got chunk ' + chunk.chunkID);
        }
        self.sendChunk(chunk);
    });

    // Prime our chunk store or LRU
    self.requestNearbyChunks(this.clientSettings.initialPosition);

    // send player position/rotation updates
    setInterval(function() {
        self.sendPlayers();
    }, 1000 / 3);

    // 3 updates per second
    // Send chunks every half-second
    /*
    setInterval(function() {
        var sendChunksBatchSize = 20;
        // Handle chunk generation
        for (var id in self.clients) {
            var client = self.clients[id];
            var ready = [];
            var chunkIDs;
            for (var chunkId in client.requestedChunks) {
                if (ready.length > sendChunksBatchSize) {
                    break;
                }
                // Make sure chunkID is valid, not out of range, etc
                if (self.chunkStore.has(chunkID)) {
                    ready.push(chunkID);
                    delete client.requestedChunks[chunkID];
                }
            }
            if (ready.length > 0) {
                //console.log('Ready to send: ' + ready.length)
                self.sendChunks(client.connection, ready);
            }
        }
    }, 1e3 / 5);
    */
};

// Setup the client connection - register events, etc
Server.prototype.connectClient = function(wseSocket) {
    var self = this;
    var id = wseSocket.id = uuid();
    var client = self.clients[id] = {
        id: id,
        // This gets updated when we get their position updates
        // Server should remove stale clients
        lastSeen: 0,
        connected: true,
        connection: wseSocket,
        avatar: 'player',
        position: null,
        yaw: 0,
        pitch: 0,

        requestedChunks: {},
        // The chunk ids this client cares about
        onlyTheseChunks: []
    };
    // setup client response handlers
    self.bindClientEvents(client);
    // send client id and initial game settings
    wseSocket.emit('settings', self.clientSettings, id);
};

Server.prototype.bindClientEvents = function(client) {
    var self = this;
    var id = client.id;
    var connection = client.connection;

    connection.on('error', function(message) {
        console.log('Client connection error: ' + message);
    });

    connection.on('end', function() {
        client.connected = false;
    });

    connection.on('close', function(error) {
        client.connected = false;
        delete self.clients[client.id];
    });

    // forward chat message
    connection.on('chat', function(message) {
        // ignore if no message provided
        if (!message.text) return;
        if (message.text.match(/script/i)) {
            console.log('Found script tag in message. Dropping');
            return;
        }
        // limit chat message length
        if (message.text.length > 255) message.text = message.text.substr(0, 140);
        self.broadcast(null, 'chat', message);
        self.emitter.emit('chat', message);
    });

    // when user ready ( game created, etc )
    connection.on('created', function() {
        // emit client.created for module consumers
        self.emitter.emit('client.created', client);
    });

    // client sends new position, rotation
    // don't need to lerp on the server AND the client, just the client
    connection.on('myPosition', function(position, yaw, pitch, avatar) {
        client.position = position;
        client.yaw = yaw;
        client.pitch = pitch;
        client.avatar = avatar;
        self.emitter.emit('client.state', client);
    });

    // Client sent us voxel changes for one or more chunks
    connection.on('chunkVoxelIndexValue', function(changes) {
        // Update our chunk store
        self.chunkStore.gotChunkChanges(changes);

        // Re-broadcast this to the other players, too
        for (var chunkID in changes) {
            var chunkChanges = {};
            chunkChanges[chunkID] = changes[chunkID];

            self.encodedChunkCache.remove(chunkID);
            for (var clientId in self.clients) {
                var client;
                var connection;
                // Don't broadcast to the client that sent us the info
                if (clientId === id) {
                    continue;
                }
                client = self.clients[clientId];
                if (!client.connected) {
                    continue;
                }
                if (debug) {
                    console.log('sending to', clientId, args);
                }
                // emit over connection
                client.connection.emit('chunkVoxelIndexValue', chunkChanges);
            }
        }
    });

    // Client tells us which chunks it wants to hear about
    connection.on('onlyTheseChunks', function(chunks) {
        if (debug) {
            console.log('Client only cares about these chunks', chunks);
        }
        client.chunks = chunks;
    });

    // Client wants chunks. Keep track of which client wants chunks
    connection.on('needChunks', function(chunkIds) {
        if (debug) {
            console.log(client.id + ' needs chunks', chunkIds);
        }

        // Request the chunks we want
        for (var i = 0; i < chunkIds.length; i++) {
            var chunkId = chunkIds[i];
            if (!self.isChunkInBounds(chunkId)) {
                continue;
            }

            if (!(chunkId in self.chunksForClients)) {
                self.chunksForClients[chunkId] = {};
            }
            // Keep track of which client wants this chunk
            self.chunksForClients[ chunkId ][ client.id ] = true;
            self.chunkStore.get(chunkId);
        }
    });
};

// send message to all clients
Server.prototype.broadcast = function(id, event) {
    var self = this;
    // normalize arguments
    var len = arguments.length;
    var args = new Array(len);
    // skip client `id` argument
    for (var i = 0, j = 1; j < len; i++, j++) {
        args[i] = arguments[j];
    }
    // emit on self for module consumers, unless specified not to
    if (id !== 'server') {
        self.emitter.emit.apply(self, args);
    }
    for (var clientId in self.clients) {
        var client;
        var connection;
        // Don't broadcast to the client that sent us the info
        if (clientId === id) {
            continue;
        }
        client = self.clients[clientId];
        if (!client.connected) {
            continue;
        }
        if (debug) {
            console.log('sending to', clientId, args);
        }
        // emit over connection
        client.connection.emit.apply(client.connection, args);
    }
};

// broadcast position, rotation updates for each player
Server.prototype.sendPlayers = function() {
    var self = this;
    var clientIds = Object.keys(self.clients);
    if (clientIds.length === 0) {
        return;
    }
    //console.log('Sending updates for ' + clientIds.length + ' clients')
    var players = {};

    clientIds.map(function(id) {
        var client = self.clients[id];
        if (!client.position) {
            return;
        }
        // TODO: Ignore client if they're really stale
        players[id] = {
            positions: [
                client.position[0],
                client.position[1],
                client.position[2],
                client.pitch,
                client.yaw,
                0
            ],
            avatar: client.avatar
        };
    });

    self.broadcast(null, 'players', players);
};

Server.prototype.requestNearbyChunks = function(position) {
    var self = this;
    this.coords.nearbyChunkIDsEach(position, 2, function(chunkID) {
        self.chunkStore.get(chunkID);
    });
};

Server.prototype.sendChunk = function(chunk) {
    var self = this;
    var chunkId = chunk.chunkID;
    if (!(chunkId in this.chunksForClients)) {
        // Nobody's waiting for this chunk
        if (debug) {
            console.log('Nobody is waiting for ', chunkId);
        }
        return;
    }

    // GET IDS SO NO LOOP ITERATION ISSUES
    // LOOPS OVER CLIENT IDS TOO, PRUNING EMPTY OBJECTS
    var clientIds = Object.keys(this.chunksForClients[chunkId]);
    for (var i = 0; i < clientIds.length; i++) {
        var clientId = clientIds[i];
        var client;
        if (clientId in self.clients) {
            client = self.clients[clientId];
            if (client.connected) {
                encoded = this.encodedChunkCache.get(chunkId);
                if (!encoded) {
                    if (debug) {
                        console.log('Adding ' + chunkId + ' to LRU');
                    }
                    encoded = encoder(chunk.voxels);
                    self.encodedChunkCache.set(chunkId, encoded);
                } else {
                    if (debug) {
                        console.log('Found ' + chunkId + ' in LRU');
                    }
                }
                if (debug) {
                    console.log('Sending ' + chunkId + ' to client ' + clientId);
                }
                // Send chunkID so we can use it on the receving end as the key in our chunksToDecodeAndMesh object
                client.connection.emit('chunk', chunkId, encoded);
            }
        } else {
            console.log(clientId, ' not found in self.clients');
        }
        delete this.chunksForClients[chunkId][clientId];
    }

    var chunkIds = Object.keys(this.chunksForClients);
    for (var i = 0; i < chunkIds.length; i++) {
        var chunkId = chunkIds[i];
        var clientIds = Object.keys(this.chunksForClients[chunkId]);
        if (clientIds.length == 0) {
            delete this.chunksForClients[chunkId];
        }
    }
};

Server.prototype.isChunkInBounds = function(chunkID) {
    var self = this;
    var position = chunkID.split('|').map(function(value) {
        return Number(value);
    });
    if (position[0] < self.lastWorldChunks[0] || position[1] < self.lastWorldChunks[1] || position[2] < self.lastWorldChunks[2] || position[0] > self.lastWorldChunks[3] || position[1] > self.lastWorldChunks[4] || position[2] > self.lastWorldChunks[5]) {
        return false;
    }
    return true;
};

Server.prototype.on = function(name, callback) {
    this.emitter.on(name, callback);
};

<commit_msg>oops, turn off debug<commit_after>var EventEmitter = require('events').EventEmitter;
var WebSocketEmitter = require('./web-socket-emitter');
var uuid = require('hat');

// voxel dependencies
var Coordinates = require('./coordinates');
var encoder = require('./rle-encoder');
var lru = require('./lru');
var debug = false;

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}

module.exports = Server;

function Server(config, chunkStore, serverSettings, clientSettings) {
    // force instantiation via `new` keyword
    //if(!(this instanceof Server)) { return new Server(serverSettings || {}, clientSettings || {}) }
    this.config = config;
    this.chunkStore = chunkStore;
    this.serverSettings = serverSettings;
    this.clientSettings = clientSettings;

    this.requestedChunks = {};

    var chunkSize = config.chunkSize;
    var origin = [0, 0, 0];
    var step = chunkSize * config.worldRadius;
    this.lastWorldChunks = [
        // Lower chunk
        origin[0] - step,
        origin[1] - step,
        origin[2] - step,

        // Farther chunk
        origin[0] + step,
        origin[1] + step,
        origin[2] + step
    ];
    this.initialize();
};

Server.prototype.initialize = function() {
    var self = this;
    var clients = this.clients = {};
    this.emitter = new EventEmitter();
    this.coords = Coordinates(self.config.chunkSize);

    this.encodedChunkCache = new lru(10);

    // chunkId -> {clientIdA: true, clientIdB: true}
    this.chunksForClients = {};

    this.chunkStore.emitter.on('got', function(chunk) {
        if (debug) {
            console.log('got chunk ' + chunk.chunkID);
        }
        self.sendChunk(chunk);
    });

    // Prime our chunk store or LRU
    self.requestNearbyChunks(this.clientSettings.initialPosition);

    // send player position/rotation updates
    setInterval(function() {
        self.sendPlayers();
    }, 1000 / 3);

    // 3 updates per second
    // Send chunks every half-second
    /*
    setInterval(function() {
        var sendChunksBatchSize = 20;
        // Handle chunk generation
        for (var id in self.clients) {
            var client = self.clients[id];
            var ready = [];
            var chunkIDs;
            for (var chunkId in client.requestedChunks) {
                if (ready.length > sendChunksBatchSize) {
                    break;
                }
                // Make sure chunkID is valid, not out of range, etc
                if (self.chunkStore.has(chunkID)) {
                    ready.push(chunkID);
                    delete client.requestedChunks[chunkID];
                }
            }
            if (ready.length > 0) {
                //console.log('Ready to send: ' + ready.length)
                self.sendChunks(client.connection, ready);
            }
        }
    }, 1e3 / 5);
    */
};

// Setup the client connection - register events, etc
Server.prototype.connectClient = function(wseSocket) {
    var self = this;
    var id = wseSocket.id = uuid();
    var client = self.clients[id] = {
        id: id,
        // This gets updated when we get their position updates
        // Server should remove stale clients
        lastSeen: 0,
        connected: true,
        connection: wseSocket,
        avatar: 'player',
        position: null,
        yaw: 0,
        pitch: 0,

        requestedChunks: {},
        // The chunk ids this client cares about
        onlyTheseChunks: []
    };
    // setup client response handlers
    self.bindClientEvents(client);
    // send client id and initial game settings
    wseSocket.emit('settings', self.clientSettings, id);
};

Server.prototype.bindClientEvents = function(client) {
    var self = this;
    var id = client.id;
    var connection = client.connection;

    connection.on('error', function(message) {
        console.log('Client connection error: ' + message);
    });

    connection.on('end', function() {
        client.connected = false;
    });

    connection.on('close', function(error) {
        client.connected = false;
        delete self.clients[client.id];
    });

    // forward chat message
    connection.on('chat', function(message) {
        // ignore if no message provided
        if (!message.text) return;
        if (message.text.match(/script/i)) {
            console.log('Found script tag in message. Dropping');
            return;
        }
        // limit chat message length
        if (message.text.length > 255) message.text = message.text.substr(0, 140);
        self.broadcast(null, 'chat', message);
        self.emitter.emit('chat', message);
    });

    // when user ready ( game created, etc )
    connection.on('created', function() {
        // emit client.created for module consumers
        self.emitter.emit('client.created', client);
    });

    // client sends new position, rotation
    // don't need to lerp on the server AND the client, just the client
    connection.on('myPosition', function(position, yaw, pitch, avatar) {
        client.position = position;
        client.yaw = yaw;
        client.pitch = pitch;
        client.avatar = avatar;
        self.emitter.emit('client.state', client);
    });

    // Client sent us voxel changes for one or more chunks
    connection.on('chunkVoxelIndexValue', function(changes) {
        // Update our chunk store
        self.chunkStore.gotChunkChanges(changes);

        // Re-broadcast this to the other players, too
        for (var chunkID in changes) {
            var chunkChanges = {};
            chunkChanges[chunkID] = changes[chunkID];

            self.encodedChunkCache.remove(chunkID);
            for (var clientId in self.clients) {
                var client;
                var connection;
                // Don't broadcast to the client that sent us the info
                if (clientId === id) {
                    continue;
                }
                client = self.clients[clientId];
                if (!client.connected) {
                    continue;
                }
                if (debug) {
                    console.log('sending to', clientId, args);
                }
                // emit over connection
                client.connection.emit('chunkVoxelIndexValue', chunkChanges);
            }
        }
    });

    // Client tells us which chunks it wants to hear about
    connection.on('onlyTheseChunks', function(chunks) {
        if (debug) {
            console.log('Client only cares about these chunks', chunks);
        }
        client.chunks = chunks;
    });

    // Client wants chunks. Keep track of which client wants chunks
    connection.on('needChunks', function(chunkIds) {
        if (debug) {
            console.log(client.id + ' needs chunks', chunkIds);
        }

        // Request the chunks we want
        for (var i = 0; i < chunkIds.length; i++) {
            var chunkId = chunkIds[i];
            if (!self.isChunkInBounds(chunkId)) {
                continue;
            }

            if (!(chunkId in self.chunksForClients)) {
                self.chunksForClients[chunkId] = {};
            }
            // Keep track of which client wants this chunk
            self.chunksForClients[ chunkId ][ client.id ] = true;
            self.chunkStore.get(chunkId);
        }
    });
};

// send message to all clients
Server.prototype.broadcast = function(id, event) {
    var self = this;
    // normalize arguments
    var len = arguments.length;
    var args = new Array(len);
    // skip client `id` argument
    for (var i = 0, j = 1; j < len; i++, j++) {
        args[i] = arguments[j];
    }
    // emit on self for module consumers, unless specified not to
    if (id !== 'server') {
        self.emitter.emit.apply(self, args);
    }
    for (var clientId in self.clients) {
        var client;
        var connection;
        // Don't broadcast to the client that sent us the info
        if (clientId === id) {
            continue;
        }
        client = self.clients[clientId];
        if (!client.connected) {
            continue;
        }
        if (debug) {
            console.log('sending to', clientId, args);
        }
        // emit over connection
        client.connection.emit.apply(client.connection, args);
    }
};

// broadcast position, rotation updates for each player
Server.prototype.sendPlayers = function() {
    var self = this;
    var clientIds = Object.keys(self.clients);
    if (clientIds.length === 0) {
        return;
    }
    //console.log('Sending updates for ' + clientIds.length + ' clients')
    var players = {};

    clientIds.map(function(id) {
        var client = self.clients[id];
        if (!client.position) {
            return;
        }
        // TODO: Ignore client if they're really stale
        players[id] = {
            positions: [
                client.position[0],
                client.position[1],
                client.position[2],
                client.pitch,
                client.yaw,
                0
            ],
            avatar: client.avatar
        };
    });

    self.broadcast(null, 'players', players);
};

Server.prototype.requestNearbyChunks = function(position) {
    var self = this;
    this.coords.nearbyChunkIDsEach(position, 2, function(chunkID) {
        self.chunkStore.get(chunkID);
    });
};

Server.prototype.sendChunk = function(chunk) {
    var self = this;
    var chunkId = chunk.chunkID;
    if (!(chunkId in this.chunksForClients)) {
        // Nobody's waiting for this chunk
        if (debug) {
            console.log('Nobody is waiting for ', chunkId);
        }
        return;
    }

    // GET IDS SO NO LOOP ITERATION ISSUES
    // LOOPS OVER CLIENT IDS TOO, PRUNING EMPTY OBJECTS
    var clientIds = Object.keys(this.chunksForClients[chunkId]);
    for (var i = 0; i < clientIds.length; i++) {
        var clientId = clientIds[i];
        var client;
        if (clientId in self.clients) {
            client = self.clients[clientId];
            if (client.connected) {
                encoded = this.encodedChunkCache.get(chunkId);
                if (!encoded) {
                    if (debug) {
                        console.log('Adding ' + chunkId + ' to LRU');
                    }
                    encoded = encoder(chunk.voxels);
                    self.encodedChunkCache.set(chunkId, encoded);
                } else {
                    if (debug) {
                        console.log('Found ' + chunkId + ' in LRU');
                    }
                }
                if (debug) {
                    console.log('Sending ' + chunkId + ' to client ' + clientId);
                }
                // Send chunkID so we can use it on the receving end as the key in our chunksToDecodeAndMesh object
                client.connection.emit('chunk', chunkId, encoded);
            }
        } else {
            console.log(clientId, ' not found in self.clients');
        }
        delete this.chunksForClients[chunkId][clientId];
    }

    var chunkIds = Object.keys(this.chunksForClients);
    for (var i = 0; i < chunkIds.length; i++) {
        var chunkId = chunkIds[i];
        var clientIds = Object.keys(this.chunksForClients[chunkId]);
        if (clientIds.length == 0) {
            delete this.chunksForClients[chunkId];
        }
    }
};

Server.prototype.isChunkInBounds = function(chunkID) {
    var self = this;
    var position = chunkID.split('|').map(function(value) {
        return Number(value);
    });
    if (position[0] < self.lastWorldChunks[0] || position[1] < self.lastWorldChunks[1] || position[2] < self.lastWorldChunks[2] || position[0] > self.lastWorldChunks[3] || position[1] > self.lastWorldChunks[4] || position[2] > self.lastWorldChunks[5]) {
        return false;
    }
    return true;
};

Server.prototype.on = function(name, callback) {
    this.emitter.on(name, callback);
};

<|endoftext|>


<commit_before>module.exports = {
  devtool: 'cheap-module-source-map',
  output: {
    path: __dirname,
    filename: 'garden.min.js'
  },
  externals: {
    'jquery': '$'
  },
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
    ]
  }
};
<commit_msg>feat(webpack): add uglify/dedupe plugins to webpack<commit_after>const webpack = require('webpack');

module.exports = {
  devtool: 'cheap-module-source-map',
  output: {
    path: __dirname,
    filename: 'garden.min.js'
  },
  externals: {
    'jquery': '$'
  },
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
      { test: /\.js$/, include: /jump/, loader: 'babel-loader' }
    ]
  },
  plugins: [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ]
};
<|endoftext|>


<commit_before>var SocketIO = require('socket.io')
var di = require('di')
var util = require('util')
var Promise = require('bluebird')

var root = global || window || this

var cfg = require('./config')
var logger = require('./logger')
var constant = require('./constants')
var watcher = require('./watcher')
var plugin = require('./plugin')

var ws = require('./web-server')
var preprocessor = require('./preprocessor')
var Launcher = require('./launcher').Launcher
var FileList = require('./file-list')
var reporter = require('./reporter')
var helper = require('./helper')
var events = require('./events')
var EventEmitter = events.EventEmitter
var Executor = require('./executor')
var Browser = require('./browser')
var BrowserCollection = require('./browser_collection')
var EmitterWrapper = require('./emitter_wrapper')
var processWrapper = new EmitterWrapper(process)

function createSocketIoServer (webServer, executor, config) {
  var server = new SocketIO(webServer, {
    // avoid destroying http upgrades from socket.io to get proxied websockets working
    destroyUpgrade: false,
    path: config.urlRoot + 'socket.io/',
    transports: config.transports
  })

  // hack to overcome circular dependency
  executor.socketIoSockets = server.sockets

  return server
}

function setupLogger (level, colors) {
  var logLevel = logLevel || constant.LOG_INFO
  var logColors = helper.isDefined(colors) ? colors : true
  logger.setup(logLevel, logColors, [constant.CONSOLE_APPENDER])
}

// Constructor
var Server = function (cliOptions, done) {
  EventEmitter.call(this)

  setupLogger(cliOptions.logLevel, cliOptions.colors)

  this.log = logger.create()

  var config = cfg.parseConfig(cliOptions.configFile, cliOptions)

  var modules = [{
    helper: ['value', helper],
    logger: ['value', logger],
    done: ['value', done || process.exit],
    emitter: ['value', this],
    launcher: ['type', Launcher],
    config: ['value', config],
    preprocess: ['factory', preprocessor.createPreprocessor],
    fileList: ['type', FileList],
    webServer: ['factory', ws.create],
    socketServer: ['factory', createSocketIoServer],
    executor: ['type', Executor],
    // TODO(vojta): remove
    customFileHandlers: ['value', []],
    // TODO(vojta): remove, once karma-dart does not rely on it
    customScriptTypes: ['value', []],
    reporter: ['factory', reporter.createReporters],
    capturedBrowsers: ['type', BrowserCollection],
    args: ['value', {}],
    timer: ['value', {
      setTimeout: function () {
        return setTimeout.apply(root, arguments)
      },
      clearTimeout: function (timeoutId) {
        clearTimeout(timeoutId)
      }
    }]
  }]

  // Load the plugins
  modules = modules.concat(plugin.resolve(config.plugins))

  this._injector = new di.Injector(modules)
}

// Inherit from events.EventEmitter
util.inherits(Server, EventEmitter)

// Public Methods
// --------------

// Start the server
Server.prototype.start = function () {
  this._injector.invoke(this._start, this)
}

/**
 * Backward-compatibility with karma-intellij bundled with WebStorm.
 * Deprecated since version 0.13, to be removed in 0.14
 */
Server.start = function (cliOptions, done) {
  var server = new Server(cliOptions, done)
  server.start()
}

// Get properties from the injector
//
// token - String
Server.prototype.get = function (token) {
  return this._injector.get(token)
}

// Force a refresh of the file list
Server.prototype.refreshFiles = function () {
  if (!this._fileList) return Promise.resolve()

  return this._fileList.refresh()
}

// Private Methods
// ---------------

Server.prototype._start = function (config, launcher, preprocess, fileList, webServer,
                                    capturedBrowsers, socketServer, executor, done) {
  var self = this

  self._fileList = fileList

  config.frameworks.forEach(function (framework) {
    self._injector.get('framework:' + framework)
  })

  // A map of launched browsers.
  var singleRunDoneBrowsers = Object.create(null)

  // Passing fake event emitter, so that it does not emit on the global,
  // we don't care about these changes.
  var singleRunBrowsers = new BrowserCollection(new EventEmitter())

  // Some browsers did not get captured.
  var singleRunBrowserNotCaptured = false

  webServer.on('error', function (e) {
    if (e.code === 'EADDRINUSE') {
      self.log.warn('Port %d in use', config.port)
      config.port++
      webServer.listen(config.port)
    } else {
      throw e
    }
  })

  var afterPreprocess = function () {
    if (config.autoWatch) {
      self._injector.invoke(watcher.watch)
    }

    webServer.listen(config.port, function () {
      self.log.info('Karma v%s server started at %s//%s:%s%s', constant.VERSION,
        config.protocol, config.hostname, config.port, config.urlRoot)

      if (config.browsers && config.browsers.length) {
        self._injector.invoke(launcher.launch, launcher).forEach(function (browserLauncher) {
          singleRunDoneBrowsers[browserLauncher.id] = false
        })
      }
    })
  }

  fileList.refresh().then(afterPreprocess, afterPreprocess)

  self.on('browsers_change', function () {
    // TODO(vojta): send only to interested browsers
    socketServer.sockets.emit('info', capturedBrowsers.serialize())
  })

  self.on('browser_register', function (browser) {
    launcher.markCaptured(browser.id)

    // TODO(vojta): This is lame, browser can get captured and then
    // crash (before other browsers get captured).
    if (launcher.areAllCaptured()) {
      self.emit('browsers_ready')

      if (config.autoWatch) {
        executor.schedule()
      }
    }
  })

  var EVENTS_TO_REPLY = ['start', 'info', 'karma_error', 'result', 'complete']
  socketServer.sockets.on('connection', function (socket) {
    self.log.debug('A browser has connected on socket ' + socket.id)

    var replySocketEvents = events.bufferEvents(socket, EVENTS_TO_REPLY)

    socket.on('complete', function (data, ack) {
      ack()
    })

    socket.on('register', function (info) {
      var newBrowser
      var isRestart

      if (info.id) {
        newBrowser = capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)
      }

      if (newBrowser) {
        isRestart = newBrowser.state === Browser.STATE_DISCONNECTED
        newBrowser.reconnect(socket)

        // We are restarting a previously disconnected browser.
        if (isRestart && config.singleRun) {
          newBrowser.execute(config.client)
        }
      } else {
        newBrowser = self._injector.createChild([{
          id: ['value', info.id || null],
          fullName: ['value', info.name],
          socket: ['value', socket]
        }]).instantiate(Browser)

        newBrowser.init()

        // execute in this browser immediately
        if (config.singleRun) {
          newBrowser.execute(config.client)
          singleRunBrowsers.add(newBrowser)
        }
      }

      replySocketEvents()
    })
  })

  var emitRunCompleteIfAllBrowsersDone = function () {
    // all browsers done
    var isDone = Object.keys(singleRunDoneBrowsers).reduce(function (isDone, id) {
      return isDone && singleRunDoneBrowsers[id]
    }, true)

    if (isDone) {
      var results = singleRunBrowsers.getResults()
      if (singleRunBrowserNotCaptured) {
        results.exitCode = 1
      }

      self.emit('run_complete', singleRunBrowsers, results)
    }
  }

  if (config.singleRun) {
    self.on('browser_complete', function (completedBrowser) {
      if (completedBrowser.lastResult.disconnected &&
        completedBrowser.disconnectsCount <= config.browserDisconnectTolerance) {
        self.log.info('Restarting %s (%d of %d attempts)', completedBrowser.name,
          completedBrowser.disconnectsCount, config.browserDisconnectTolerance)
        if (!launcher.restart(completedBrowser.id)) {
          singleRunDoneBrowsers[completedBrowser.id] = true
          emitRunCompleteIfAllBrowsersDone()
        }
      } else {
        singleRunDoneBrowsers[completedBrowser.id] = true

        if (launcher.kill(completedBrowser.id)) {
          // workaround to supress "disconnect" warning
          completedBrowser.state = Browser.STATE_DISCONNECTED
        }

        emitRunCompleteIfAllBrowsersDone()
      }
    })

    self.on('browser_process_failure', function (browserLauncher) {
      singleRunDoneBrowsers[browserLauncher.id] = true
      singleRunBrowserNotCaptured = true

      emitRunCompleteIfAllBrowsersDone()
    })

    self.on('run_complete', function (browsers, results) {
      self.log.debug('Run complete, exiting.')
      disconnectBrowsers(results.exitCode)
    })

    self.emit('run_start', singleRunBrowsers)
  }

  if (config.autoWatch) {
    self.on('file_list_modified', function () {
      self.log.debug('List of files has changed, trying to execute')
      if (config.restartOnFileChange) {
        socketServer.sockets.emit('stop')
      }
      executor.schedule()
    })
  }

  var webServerCloseTimeout = 3000
  var disconnectBrowsers = function (code) {
    // Slightly hacky way of removing disconnect listeners
    // to suppress "browser disconnect" warnings
    // TODO(vojta): change the client to not send the event (if disconnected by purpose)
    var sockets = socketServer.sockets.sockets

    sockets.forEach(function (socket) {
      socket.removeAllListeners('disconnect')
      if (!socket.disconnected) {
        // Disconnect asynchronously. Socket.io mutates the `sockets.sockets` array
        // underneath us so this would skip every other browser/socket.
        process.nextTick(socket.disconnect.bind(socket))
      }
    })

    var removeAllListenersDone = false
    var removeAllListeners = function () {
      // make sure we don't execute cleanup twice
      if (removeAllListenersDone) {
        return
      }
      removeAllListenersDone = true
      webServer.removeAllListeners()
      processWrapper.removeAllListeners()
      done(code || 0)
    }

    self.emitAsync('exit').then(function () {
      // don't wait forever on webServer.close() because
      // pending client connections prevent it from closing.
      var closeTimeout = setTimeout(removeAllListeners, webServerCloseTimeout)

      // shutdown the server...
      webServer.close(function () {
        clearTimeout(closeTimeout)
        removeAllListeners()
      })
    })
  }

  processWrapper.on('SIGINT', disconnectBrowsers)
  processWrapper.on('SIGTERM', disconnectBrowsers)

  // Handle all unhandled exceptions, so we don't just exit but
  // disconnect the browsers before exiting.
  processWrapper.on('uncaughtException', function (error) {
    self.log.error(error)
    disconnectBrowsers(1)
  })
}

// Export
// ------

module.exports = Server
<commit_msg>fix(server): Handle new socket.io internal format.<commit_after>var SocketIO = require('socket.io')
var di = require('di')
var util = require('util')
var Promise = require('bluebird')

var root = global || window || this

var cfg = require('./config')
var logger = require('./logger')
var constant = require('./constants')
var watcher = require('./watcher')
var plugin = require('./plugin')

var ws = require('./web-server')
var preprocessor = require('./preprocessor')
var Launcher = require('./launcher').Launcher
var FileList = require('./file-list')
var reporter = require('./reporter')
var helper = require('./helper')
var events = require('./events')
var EventEmitter = events.EventEmitter
var Executor = require('./executor')
var Browser = require('./browser')
var BrowserCollection = require('./browser_collection')
var EmitterWrapper = require('./emitter_wrapper')
var processWrapper = new EmitterWrapper(process)

function createSocketIoServer (webServer, executor, config) {
  var server = new SocketIO(webServer, {
    // avoid destroying http upgrades from socket.io to get proxied websockets working
    destroyUpgrade: false,
    path: config.urlRoot + 'socket.io/',
    transports: config.transports
  })

  // hack to overcome circular dependency
  executor.socketIoSockets = server.sockets

  return server
}

function setupLogger (level, colors) {
  var logLevel = logLevel || constant.LOG_INFO
  var logColors = helper.isDefined(colors) ? colors : true
  logger.setup(logLevel, logColors, [constant.CONSOLE_APPENDER])
}

// Constructor
var Server = function (cliOptions, done) {
  EventEmitter.call(this)

  setupLogger(cliOptions.logLevel, cliOptions.colors)

  this.log = logger.create()

  var config = cfg.parseConfig(cliOptions.configFile, cliOptions)

  var modules = [{
    helper: ['value', helper],
    logger: ['value', logger],
    done: ['value', done || process.exit],
    emitter: ['value', this],
    launcher: ['type', Launcher],
    config: ['value', config],
    preprocess: ['factory', preprocessor.createPreprocessor],
    fileList: ['type', FileList],
    webServer: ['factory', ws.create],
    socketServer: ['factory', createSocketIoServer],
    executor: ['type', Executor],
    // TODO(vojta): remove
    customFileHandlers: ['value', []],
    // TODO(vojta): remove, once karma-dart does not rely on it
    customScriptTypes: ['value', []],
    reporter: ['factory', reporter.createReporters],
    capturedBrowsers: ['type', BrowserCollection],
    args: ['value', {}],
    timer: ['value', {
      setTimeout: function () {
        return setTimeout.apply(root, arguments)
      },
      clearTimeout: function (timeoutId) {
        clearTimeout(timeoutId)
      }
    }]
  }]

  // Load the plugins
  modules = modules.concat(plugin.resolve(config.plugins))

  this._injector = new di.Injector(modules)
}

// Inherit from events.EventEmitter
util.inherits(Server, EventEmitter)

// Public Methods
// --------------

// Start the server
Server.prototype.start = function () {
  this._injector.invoke(this._start, this)
}

/**
 * Backward-compatibility with karma-intellij bundled with WebStorm.
 * Deprecated since version 0.13, to be removed in 0.14
 */
Server.start = function (cliOptions, done) {
  var server = new Server(cliOptions, done)
  server.start()
}

// Get properties from the injector
//
// token - String
Server.prototype.get = function (token) {
  return this._injector.get(token)
}

// Force a refresh of the file list
Server.prototype.refreshFiles = function () {
  if (!this._fileList) return Promise.resolve()

  return this._fileList.refresh()
}

// Private Methods
// ---------------

Server.prototype._start = function (config, launcher, preprocess, fileList, webServer,
                                    capturedBrowsers, socketServer, executor, done) {
  var self = this

  self._fileList = fileList

  config.frameworks.forEach(function (framework) {
    self._injector.get('framework:' + framework)
  })

  // A map of launched browsers.
  var singleRunDoneBrowsers = Object.create(null)

  // Passing fake event emitter, so that it does not emit on the global,
  // we don't care about these changes.
  var singleRunBrowsers = new BrowserCollection(new EventEmitter())

  // Some browsers did not get captured.
  var singleRunBrowserNotCaptured = false

  webServer.on('error', function (e) {
    if (e.code === 'EADDRINUSE') {
      self.log.warn('Port %d in use', config.port)
      config.port++
      webServer.listen(config.port)
    } else {
      throw e
    }
  })

  var afterPreprocess = function () {
    if (config.autoWatch) {
      self._injector.invoke(watcher.watch)
    }

    webServer.listen(config.port, function () {
      self.log.info('Karma v%s server started at %s//%s:%s%s', constant.VERSION,
        config.protocol, config.hostname, config.port, config.urlRoot)

      if (config.browsers && config.browsers.length) {
        self._injector.invoke(launcher.launch, launcher).forEach(function (browserLauncher) {
          singleRunDoneBrowsers[browserLauncher.id] = false
        })
      }
    })
  }

  fileList.refresh().then(afterPreprocess, afterPreprocess)

  self.on('browsers_change', function () {
    // TODO(vojta): send only to interested browsers
    socketServer.sockets.emit('info', capturedBrowsers.serialize())
  })

  self.on('browser_register', function (browser) {
    launcher.markCaptured(browser.id)

    // TODO(vojta): This is lame, browser can get captured and then
    // crash (before other browsers get captured).
    if (launcher.areAllCaptured()) {
      self.emit('browsers_ready')

      if (config.autoWatch) {
        executor.schedule()
      }
    }
  })

  var EVENTS_TO_REPLY = ['start', 'info', 'karma_error', 'result', 'complete']
  socketServer.sockets.on('connection', function (socket) {
    self.log.debug('A browser has connected on socket ' + socket.id)

    var replySocketEvents = events.bufferEvents(socket, EVENTS_TO_REPLY)

    socket.on('complete', function (data, ack) {
      ack()
    })

    socket.on('register', function (info) {
      var newBrowser
      var isRestart

      if (info.id) {
        newBrowser = capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)
      }

      if (newBrowser) {
        isRestart = newBrowser.state === Browser.STATE_DISCONNECTED
        newBrowser.reconnect(socket)

        // We are restarting a previously disconnected browser.
        if (isRestart && config.singleRun) {
          newBrowser.execute(config.client)
        }
      } else {
        newBrowser = self._injector.createChild([{
          id: ['value', info.id || null],
          fullName: ['value', info.name],
          socket: ['value', socket]
        }]).instantiate(Browser)

        newBrowser.init()

        // execute in this browser immediately
        if (config.singleRun) {
          newBrowser.execute(config.client)
          singleRunBrowsers.add(newBrowser)
        }
      }

      replySocketEvents()
    })
  })

  var emitRunCompleteIfAllBrowsersDone = function () {
    // all browsers done
    var isDone = Object.keys(singleRunDoneBrowsers).reduce(function (isDone, id) {
      return isDone && singleRunDoneBrowsers[id]
    }, true)

    if (isDone) {
      var results = singleRunBrowsers.getResults()
      if (singleRunBrowserNotCaptured) {
        results.exitCode = 1
      }

      self.emit('run_complete', singleRunBrowsers, results)
    }
  }

  if (config.singleRun) {
    self.on('browser_complete', function (completedBrowser) {
      if (completedBrowser.lastResult.disconnected &&
        completedBrowser.disconnectsCount <= config.browserDisconnectTolerance) {
        self.log.info('Restarting %s (%d of %d attempts)', completedBrowser.name,
          completedBrowser.disconnectsCount, config.browserDisconnectTolerance)
        if (!launcher.restart(completedBrowser.id)) {
          singleRunDoneBrowsers[completedBrowser.id] = true
          emitRunCompleteIfAllBrowsersDone()
        }
      } else {
        singleRunDoneBrowsers[completedBrowser.id] = true

        if (launcher.kill(completedBrowser.id)) {
          // workaround to supress "disconnect" warning
          completedBrowser.state = Browser.STATE_DISCONNECTED
        }

        emitRunCompleteIfAllBrowsersDone()
      }
    })

    self.on('browser_process_failure', function (browserLauncher) {
      singleRunDoneBrowsers[browserLauncher.id] = true
      singleRunBrowserNotCaptured = true

      emitRunCompleteIfAllBrowsersDone()
    })

    self.on('run_complete', function (browsers, results) {
      self.log.debug('Run complete, exiting.')
      disconnectBrowsers(results.exitCode)
    })

    self.emit('run_start', singleRunBrowsers)
  }

  if (config.autoWatch) {
    self.on('file_list_modified', function () {
      self.log.debug('List of files has changed, trying to execute')
      if (config.restartOnFileChange) {
        socketServer.sockets.emit('stop')
      }
      executor.schedule()
    })
  }

  var webServerCloseTimeout = 3000
  var disconnectBrowsers = function (code) {
    // Slightly hacky way of removing disconnect listeners
    // to suppress "browser disconnect" warnings
    // TODO(vojta): change the client to not send the event (if disconnected by purpose)
    var sockets = socketServer.sockets.sockets

    Object.keys(sockets).forEach(function (id) {
      var socket = sockets[id]
      socket.removeAllListeners('disconnect')
      if (!socket.disconnected) {
        // Disconnect asynchronously. Socket.io mutates the `sockets.sockets` array
        // underneath us so this would skip every other browser/socket.
        process.nextTick(socket.disconnect.bind(socket))
      }
    })

    var removeAllListenersDone = false
    var removeAllListeners = function () {
      // make sure we don't execute cleanup twice
      if (removeAllListenersDone) {
        return
      }
      removeAllListenersDone = true
      webServer.removeAllListeners()
      processWrapper.removeAllListeners()
      done(code || 0)
    }

    self.emitAsync('exit').then(function () {
      // don't wait forever on webServer.close() because
      // pending client connections prevent it from closing.
      var closeTimeout = setTimeout(removeAllListeners, webServerCloseTimeout)

      // shutdown the server...
      webServer.close(function () {
        clearTimeout(closeTimeout)
        removeAllListeners()
      })
    })
  }

  processWrapper.on('SIGINT', disconnectBrowsers)
  processWrapper.on('SIGTERM', disconnectBrowsers)

  // Handle all unhandled exceptions, so we don't just exit but
  // disconnect the browsers before exiting.
  processWrapper.on('uncaughtException', function (error) {
    self.log.error(error)
    disconnectBrowsers(1)
  })
}

// Export
// ------

module.exports = Server
<|endoftext|>


<commit_before>import path from "path"

import webpack from "webpack"
import ExtractTextPlugin from "extract-text-webpack-plugin"
import { phenomicLoader } from "phenomic"
import PhenomicLoaderFeedWebpackPlugin from "phenomic/lib/loader-feed-webpack-plugin"
import PhenomicLoaderSitemapWebpackPlugin from "phenomic/lib/loader-sitemap-webpack-plugin"

import pkg from "./package.json"

export default (config = {}) => {

  // hot loading for postcss config
  // until this is officially supported
  // https://github.com/postcss/postcss-loader/issues/66
  const postcssPluginFile = require.resolve("./postcss.config.js")
  const postcssPlugins = (webpackInstance) => {
    webpackInstance.addDependency(postcssPluginFile)
    delete require.cache[postcssPluginFile]
    return require(postcssPluginFile)(config)
  }

  return {
    ...config.dev && {
      devtool: "#cheap-module-eval-source-map",
    },
    module: {
      noParse: /\.min\.js/,
      rules: [
        // *.md => consumed via phenomic special webpack loader
        // allow to generate collection and rss feed.
        {
          // phenomic requirement
          test: /\.(md|markdown)$/,
          loader: phenomicLoader,
          query: {
            context: path.join(__dirname, config.source),
            // plugins: [
            //   ...require("phenomic/lib/loader-preset-markdown").default
            // ]
            // see https://phenomic.io/docs/usage/plugins/
          },
        },

        // *.json => like in node, return json
        // (not handled by webpack by default)
        {
          test: /\.json$/,
          loader: "json-loader",
        },

        // *.js => babel + eslint
        {
          test: /\.js$/,
          include: [
            path.resolve(__dirname, "scripts"),
            path.resolve(__dirname, "src"),
          ],
          loaders: [
            "babel-loader?cacheDirectory",
            "eslint-loader" + (config.dev ? "?emitWarning" : ""),
          ],
        },

        // ! \\
        // by default *.css files are considered as CSS Modules
        // And *.global.css are considered as global (normal) CSS

        // *.css => CSS Modules
        {
          test: /\.css$/,
          exclude: /\.global\.css$/,
          include: path.resolve(__dirname, "src"),
          use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [
              {
                loader: 'css-loader',
                options: {
                  modules: true,
                  localIdentName: (config.production ? "[hash:base64:5]" : "[path][name]--[local]--[hash:base64:5]")
                }
              },
              {
                loader: "postcss-loader",
                // query for postcss can't be used right now
                // https://github.com/postcss/postcss-loader/issues/99
                // meanwhile, see webpack.LoaderOptionsPlugin in plugins list
                // query: { plugins: postcssPlugins },
              },
            ],
          }),
        },
        // *.global.css => global (normal) css
        {
          test: /\.global\.css$/,
          include: path.resolve(__dirname, "src"),
          loader: ExtractTextPlugin.extract({
            fallbackLoader: "style-loader",
            loader: [
              "css-loader",
              {
                loader: "postcss-loader",
                // query for postcss can't be used right now
                // https://github.com/postcss/postcss-loader/issues/99
                // meanwhile, see webpack.LoaderOptionsPlugin in plugins list
                // query: { plugins: postcssPlugins },
              },
            ],
          }),
        },
        // ! \\
        // If you want global CSS only, just remove the 2 sections above
        // and use the following one
        // ! \\ If you want global CSS for node_modules only, just uncomment
        // this section and the `include` part
        // // webpack 1
        /*
        {
          test: /\.css$/,
          // depending on your need, you might need to scope node_modules
          // for global CSS if you want to keep CSS Modules by default
          // for your own CSS. If so, uncomment the line below
          // include: path.resolve(__dirname, "node_modules"),
          loader: ExtractTextPlugin.extract(
            "style-loader",
            [
              "css-loader",
              "postcss-loader",
            ].join("!")
          ),
        },
        */
        // // webpack 2
        /*
        {
          test: /\.css$/,
          // depending on your need, you might need to scope node_modules
          // for global CSS if you want to keep CSS Modules by default
          // for your own CSS. If so, uncomment the line below
          // include: path.resolve(__dirname, "node_modules"),
          loader: ExtractTextPlugin.extract({
            fallbackLoader: "style-loader",
            loader: [
              "css-loader",
              {
                loader: "postcss-loader",
                query: { "plugins": postcssPlugins },
              },
            ]
          }),
        },
        */
        // ! \\ if you want to use Sass or LESS, you can add sass-loader or
        // less-loader after postcss-loader (or replacing it).
        // ! \\ You will also need to adjust the file extension
        // and to run the following command
        //
        // Sass: `npm install --save-dev node-sass sass-loader`
        // https://github.com/jtangelder/sass-loader
        //
        // LESS: npm install --save-dev less less-loader
        // https://github.com/webpack/less-loader

        // copy assets and return generated path in js
        {
          test: /\.(html|ico|jpe?g|png|gif|eot|otf|webp|ttf|woff|woff2)$/,
          loader: "file-loader",
          query: {
            name: "[path][name].[hash].[ext]",
            context: path.join(__dirname, config.source),
          },
        },

        // svg as raw string to be inlined
        {
          test: /\.svg$/,
          loader: "raw-loader",
        },
      ],
    },

    plugins: [
      // webpack 2
      // You should be able to remove the block below when the following
      // issue has been correctly handled (and postcss-loader supports
      // "plugins" option directly in query, see postcss-loader usage above)
      // https://github.com/postcss/postcss-loader/issues/99
      new webpack.LoaderOptionsPlugin({
        test: /\.css$/,
        options: {
          postcss: postcssPlugins,
          // required to avoid issue css-loader?modules
          // this is normally the default value, but when we use
          // LoaderOptionsPlugin, we must specify it again, otherwise,
          // context is missing (and css modules names can be broken)!
          context: __dirname,
        },
      }),

      new PhenomicLoaderFeedWebpackPlugin({
        // here you define generic metadata for your feed
        feedsOptions: {
          title: pkg.name,
          site_url: pkg.homepage,
        },
        feeds: {
          // here we define one feed, but you can generate multiple, based
          // on different filters
          "feed.xml": {
            collectionOptions: {
              filter: { layout: "Post" },
              sort: "date",
              reverse: true,
              limit: 20,
            },
          },
        },
      }),

      new PhenomicLoaderSitemapWebpackPlugin({
        site_url: pkg.homepage,
      }),

      new ExtractTextPlugin({
        filename: "[name].[hash].css",
        disable: config.dev,
      }),

      ...config.production && [
        // webpack 2
        // DedupePlugin does not work correctly with Webpack 2, yet ;)
        // https://github.com/webpack/webpack/issues/2644
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.UglifyJsPlugin(
          { compress: { warnings: false } }
        ),
      ],
    ],

    output: {
      path: path.join(__dirname, config.destination),
      publicPath: config.baseUrl.pathname,
      filename: "[name].[hash].js",
    },

    resolve: { extensions: [ ".js", ".json" ] },
  }
}
<commit_msg>build(webpack): cleaned up a few webpack deprecation warnings<commit_after>import path from "path"

import webpack from "webpack"
import ExtractTextPlugin from "extract-text-webpack-plugin"
import { phenomicLoader } from "phenomic"
import PhenomicLoaderFeedWebpackPlugin from "phenomic/lib/loader-feed-webpack-plugin"
import PhenomicLoaderSitemapWebpackPlugin from "phenomic/lib/loader-sitemap-webpack-plugin"

import pkg from "./package.json"

export default (config = {}) => {

  // hot loading for postcss config
  // until this is officially supported
  // https://github.com/postcss/postcss-loader/issues/66
  const postcssPluginFile = require.resolve("./postcss.config.js")
  const postcssPlugins = (webpackInstance) => {
    webpackInstance.addDependency(postcssPluginFile)
    delete require.cache[postcssPluginFile]
    return require(postcssPluginFile)(config)
  }

  return {
    ...config.dev && {
      devtool: "#cheap-module-eval-source-map",
    },
    module: {
      noParse: /\.min\.js/,
      rules: [
        // *.md => consumed via phenomic special webpack loader
        // allow to generate collection and rss feed.
        {
          // phenomic requirement
          test: /\.(md|markdown)$/,
          loader: phenomicLoader,
          query: {
            context: path.join(__dirname, config.source),
            // plugins: [
            //   ...require("phenomic/lib/loader-preset-markdown").default
            // ]
            // see https://phenomic.io/docs/usage/plugins/
          },
        },

        // *.json => like in node, return json
        // (not handled by webpack by default)
        {
          test: /\.json$/,
          loader: "json-loader",
        },

        // *.js => babel + eslint
        {
          test: /\.js$/,
          include: [
            path.resolve(__dirname, "scripts"),
            path.resolve(__dirname, "src"),
          ],
          loaders: [
            "babel-loader?cacheDirectory",
            "eslint-loader" + (config.dev ? "?emitWarning" : ""),
          ],
        },

        // ! \\
        // by default *.css files are considered as CSS Modules
        // And *.global.css are considered as global (normal) CSS

        // *.css => CSS Modules
        {
          test: /\.css$/,
          exclude: /\.global\.css$/,
          include: path.resolve(__dirname, "src"),
          use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [
              {
                loader: 'css-loader',
                options: {
                  modules: true,
                  localIdentName: (config.production ? "[hash:base64:5]" : "[path][name]--[local]--[hash:base64:5]")
                }
              },
              {
                loader: "postcss-loader",
                // query for postcss can't be used right now
                // https://github.com/postcss/postcss-loader/issues/99
                // meanwhile, see webpack.LoaderOptionsPlugin in plugins list
                // query: { plugins: postcssPlugins },
              },
            ],
          }),
        },
        // *.global.css => global (normal) css
        {
          test: /\.global\.css$/,
          include: path.resolve(__dirname, "src"),
          use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [
              "css-loader",
              {
                loader: "postcss-loader",
                // query for postcss can't be used right now
                // https://github.com/postcss/postcss-loader/issues/99
                // meanwhile, see webpack.LoaderOptionsPlugin in plugins list
                // query: { plugins: postcssPlugins },
              },
            ],
          }),
        },
        // ! \\
        // If you want global CSS only, just remove the 2 sections above
        // and use the following one
        // ! \\ If you want global CSS for node_modules only, just uncomment
        // this section and the `include` part
        // // webpack 1
        /*
        {
          test: /\.css$/,
          // depending on your need, you might need to scope node_modules
          // for global CSS if you want to keep CSS Modules by default
          // for your own CSS. If so, uncomment the line below
          // include: path.resolve(__dirname, "node_modules"),
          loader: ExtractTextPlugin.extract(
            "style-loader",
            [
              "css-loader",
              "postcss-loader",
            ].join("!")
          ),
        },
        */
        // // webpack 2
        /*
        {
          test: /\.css$/,
          // depending on your need, you might need to scope node_modules
          // for global CSS if you want to keep CSS Modules by default
          // for your own CSS. If so, uncomment the line below
          // include: path.resolve(__dirname, "node_modules"),
          loader: ExtractTextPlugin.extract({
            fallbackLoader: "style-loader",
            loader: [
              "css-loader",
              {
                loader: "postcss-loader",
                query: { "plugins": postcssPlugins },
              },
            ]
          }),
        },
        */
        // ! \\ if you want to use Sass or LESS, you can add sass-loader or
        // less-loader after postcss-loader (or replacing it).
        // ! \\ You will also need to adjust the file extension
        // and to run the following command
        //
        // Sass: `npm install --save-dev node-sass sass-loader`
        // https://github.com/jtangelder/sass-loader
        //
        // LESS: npm install --save-dev less less-loader
        // https://github.com/webpack/less-loader

        // copy assets and return generated path in js
        {
          test: /\.(html|ico|jpe?g|png|gif|eot|otf|webp|ttf|woff|woff2)$/,
          loader: "file-loader",
          query: {
            name: "[path][name].[hash].[ext]",
            context: path.join(__dirname, config.source),
          },
        },

        // svg as raw string to be inlined
        {
          test: /\.svg$/,
          loader: "raw-loader",
        },
      ],
    },

    plugins: [
      // webpack 2
      // You should be able to remove the block below when the following
      // issue has been correctly handled (and postcss-loader supports
      // "plugins" option directly in query, see postcss-loader usage above)
      // https://github.com/postcss/postcss-loader/issues/99
      new webpack.LoaderOptionsPlugin({
        test: /\.css$/,
        options: {
          postcss: postcssPlugins,
          // required to avoid issue css-loader?modules
          // this is normally the default value, but when we use
          // LoaderOptionsPlugin, we must specify it again, otherwise,
          // context is missing (and css modules names can be broken)!
          context: __dirname,
        },
      }),

      new PhenomicLoaderFeedWebpackPlugin({
        // here you define generic metadata for your feed
        feedsOptions: {
          title: pkg.name,
          site_url: pkg.homepage,
        },
        feeds: {
          // here we define one feed, but you can generate multiple, based
          // on different filters
          "feed.xml": {
            collectionOptions: {
              filter: { layout: "Post" },
              sort: "date",
              reverse: true,
              limit: 20,
            },
          },
        },
      }),

      new PhenomicLoaderSitemapWebpackPlugin({
        site_url: pkg.homepage,
      }),

      new ExtractTextPlugin({
        filename: "[name].[hash].css",
        disable: config.dev,
      }),

      ...config.production && [
        new webpack.optimize.UglifyJsPlugin(
          { compress: { warnings: false } }
        ),
      ],
    ],

    output: {
      path: path.join(__dirname, config.destination),
      publicPath: config.baseUrl.pathname,
      filename: "[name].[hash].js",
    },

    resolve: { extensions: [ ".js", ".json" ] },
  }
}
<|endoftext|>


<commit_before>var Watcher = require('./watcher')
var middleware = require('./middleware')
var http = require('http')
var tinylr = require('tiny-lr')
var connect = require('connect')

exports.serve = serve
function serve (builder, options) {
  options = options || {}

  console.log('Serving on http://' + options.host + ':' + options.port + '\n')

  var watcher = new Watcher(builder)

  var app = connect().use(middleware(watcher))

  var server = http.createServer(app)

  process.addListener('exit', function () {
    builder.cleanup()
  })

  // We register these so the 'exit' handler removing temp dirs is called
  process.on('SIGINT', function () {
    process.exit(1)
  })
  process.on('SIGTERM', function () {
    process.exit(1)
  })

  var livereloadServer = new tinylr.Server
  livereloadServer.listen(options.liveReloadPort, function (err) {
    if(err) {
      throw err
    }
  })

  var liveReload = function() {
    // We could pass files: glob.sync('**', {cwd: ...}), but this spams
    // stdout with messages and Chrome LiveReload doesn't seem to care
    // about the specific files.
    livereloadServer.changed({body: {files: ['LiveReload files']}})
  }

  watcher.on('change', function(dir) {
    console.log('Built - ' + builder.buildTime)
    liveReload()
  })

  watcher.on('error', function(err) {
    console.log('Built with error:')
    // Should also show file and line/col if present; see cli.js
    if (err.file) {
      console.log('File: ' + err.file)
    }
    console.log(err.stack)
    console.log('')
    liveReload()
  })

  server.listen(parseInt(options.port, 10), options.host)
}
<commit_msg>Allow custom watcher for serve command.<commit_after>var Watcher = require('./watcher')
var middleware = require('./middleware')
var http = require('http')
var tinylr = require('tiny-lr')
var connect = require('connect')

exports.serve = serve
function serve (builder, options) {
  options = options || {}

  console.log('Serving on http://' + options.host + ':' + options.port + '\n')

  var watcher = options.watcher || new Watcher(builder)

  var app = connect().use(middleware(watcher))

  var server = http.createServer(app)

  process.addListener('exit', function () {
    builder.cleanup()
  })

  // We register these so the 'exit' handler removing temp dirs is called
  process.on('SIGINT', function () {
    process.exit(1)
  })
  process.on('SIGTERM', function () {
    process.exit(1)
  })

  var livereloadServer = new tinylr.Server
  livereloadServer.listen(options.liveReloadPort, function (err) {
    if(err) {
      throw err
    }
  })

  var liveReload = function() {
    // We could pass files: glob.sync('**', {cwd: ...}), but this spams
    // stdout with messages and Chrome LiveReload doesn't seem to care
    // about the specific files.
    livereloadServer.changed({body: {files: ['LiveReload files']}})
  }

  watcher.on('change', function(dir) {
    console.log('Built - ' + builder.buildTime)
    liveReload()
  })

  watcher.on('error', function(err) {
    console.log('Built with error:')
    // Should also show file and line/col if present; see cli.js
    if (err.file) {
      console.log('File: ' + err.file)
    }
    console.log(err.stack)
    console.log('')
    liveReload()
  })

  server.listen(parseInt(options.port, 10), options.host)
}
<|endoftext|>


<commit_before>// @AngularClass

var webpack = require('webpack');
var helpers = require('./helpers');

var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin;

var ENV = process.env.ENV = process.env.NODE_ENV = 'development';
var HMR = helpers.hasProcessFlag('hot');

var metadata = {
  title: 'Angular2 Webpack Starter by @gdi2990 from @AngularClass',
  baseUrl: '/',
  host: 'localhost',
  port: 3000,
  ENV: ENV,
  HMR: HMR
};
/*
 * Config
 * with default values at webpack.default.conf
 */
module.exports = {
  // static data for index.html
  metadata: metadata,
  devtool: 'cheap-module-eval-source-map',
  debug: true,
  // devtool: 'eval' // for faster builds use 'eval'

  // our angular app
  entry: {
    'polyfills': './src/polyfills.ts',
    'vendor': './src/vendor.ts',
    'main': './src/main.ts'
  },

  resolve: {
    extensions: ['', '.ts', '.js']
  },

  // Config for our build files
  output: {
    path: helpers.root('dist'),
    filename: '[name].bundle.js',
    sourceMapFilename: '[name].map',
    chunkFilename: '[id].chunk.js'
  },

  module: {
    preLoaders: [
      // { test: /\.ts$/, loader: 'tslint-loader', exclude: [ helpers.root('node_modules') ] },
      // TODO(gdi2290): `exclude: [ helpers.root('node_modules/rxjs') ]` fixed with rxjs 5 beta.3 release
      { test: /\.js$/, loader: "source-map-loader", exclude: [ helpers.root('node_modules/rxjs') ] }
    ],
    loaders: [
      // Support for .ts files.
      { test: /\.ts$/, loader: 'awesome-typescript-loader', exclude: [ /\.(spec|e2e)\.ts$/ ] },

      // Support for *.json files.
      { test: /\.json$/,  loader: 'json-loader' },

      // Support for CSS as raw text
      { test: /\.css$/,   loader: 'raw-loader' },

      // support for .html as raw text
      { test: /\.html$/,  loader: 'raw-loader', exclude: [ helpers.root('src/index.html') ] }

    ]
  },

  plugins: [
    new ForkCheckerPlugin(),
    new webpack.optimize.OccurenceOrderPlugin(true),
    new webpack.optimize.CommonsChunkPlugin({ name: ['vendor', 'polyfills'], filename: '[name].bundle.js', minChunks: Infinity }),
    // static assets
    new CopyWebpackPlugin([ { from: 'src/assets', to: 'assets' } ]),
    // generating html
    new HtmlWebpackPlugin({ template: 'src/index.html' }),
    // Environment helpers
    new webpack.DefinePlugin({
      'ENV': JSON.stringify(metadata.ENV),
      'HMR': HMR
    })
  ],

  // Other module loader config

  // our Webpack Development Server config
  tslint: {
    emitErrors: false,
    failOnHint: false,
    resourcePath: 'src',
  },
  devServer: {
    port: metadata.port,
    host: metadata.host,
    historyApiFallback: true,
    watchOptions: {
      aggregateTimeout: 300,
      poll: 1000
    }
  },
  node: {
    global: 'window',
    process: HMR ? true : false,
    crypto: 'empty',
    module: false,
    clearImmediate: false,
    setImmediate: false
  }
};
<commit_msg>docs(webpack.config): mention typings<commit_after>// @AngularClass

var webpack = require('webpack');
var helpers = require('./helpers');

var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin;

var ENV = process.env.ENV = process.env.NODE_ENV = 'development';
var HMR = helpers.hasProcessFlag('hot');

var metadata = {
  title: 'Angular2 Webpack Starter by @gdi2990 from @AngularClass',
  baseUrl: '/',
  host: 'localhost',
  port: 3000,
  ENV: ENV,
  HMR: HMR
};
/*
 * Config
 * with default values at webpack.default.conf
 */
module.exports = {
  // static data for index.html
  metadata: metadata,
  devtool: 'cheap-module-eval-source-map',
  debug: true,
  // devtool: 'eval' // for faster builds use 'eval'

  // our angular app
  entry: {
    'polyfills': './src/polyfills.ts',
    'vendor': './src/vendor.ts',
    'main': './src/main.ts'
  },

  resolve: {
    extensions: ['', '.ts', '.js']
  },

  // Config for our build files
  output: {
    path: helpers.root('dist'),
    filename: '[name].bundle.js',
    sourceMapFilename: '[name].map',
    chunkFilename: '[id].chunk.js'
  },

  module: {
    preLoaders: [
      // { test: /\.ts$/, loader: 'tslint-loader', exclude: [ helpers.root('node_modules') ] },
      // TODO(gdi2290): `exclude: [ helpers.root('node_modules/rxjs') ]` fixed with rxjs 5 beta.3 release
      { test: /\.js$/, loader: "source-map-loader", exclude: [ helpers.root('node_modules/rxjs') ] }
    ],
    loaders: [
      // Support for .ts files.
      { test: /\.ts$/, loader: 'awesome-typescript-loader', exclude: [ /\.(spec|e2e)\.ts$/ ] },

      // Support for *.json files.
      { test: /\.json$/,  loader: 'json-loader' },

      // Support for CSS as raw text
      { test: /\.css$/,   loader: 'raw-loader' },

      // support for .html as raw text
      { test: /\.html$/,  loader: 'raw-loader', exclude: [ helpers.root('src/index.html') ] }

    ]
  },

  plugins: [
    new ForkCheckerPlugin(),
    new webpack.optimize.OccurenceOrderPlugin(true),
    new webpack.optimize.CommonsChunkPlugin({ name: ['vendor', 'polyfills'], filename: '[name].bundle.js', minChunks: Infinity }),
    // static assets
    new CopyWebpackPlugin([ { from: 'src/assets', to: 'assets' } ]),
    // generating html
    new HtmlWebpackPlugin({ template: 'src/index.html' }),
    // Environment helpers (when adding more properties make sure you include them in custom-typings.d.ts)
    new webpack.DefinePlugin({
      'ENV': JSON.stringify(metadata.ENV),
      'HMR': HMR
    })
  ],

  // Other module loader config

  // our Webpack Development Server config
  tslint: {
    emitErrors: false,
    failOnHint: false,
    resourcePath: 'src',
  },
  devServer: {
    port: metadata.port,
    host: metadata.host,
    historyApiFallback: true,
    watchOptions: {
      aggregateTimeout: 300,
      poll: 1000
    }
  },
  node: {
    global: 'window',
    process: HMR ? true : false,
    crypto: 'empty',
    module: false,
    clearImmediate: false,
    setImmediate: false
  }
};
<|endoftext|>


<commit_before>"use strict";

var canvas;
var gl;
var program;

var pos_matrix;
var u_pos_matrix;

var perspective;
var u_perspective;

var rot_matrix;

var shape;
var shape_indexes;
var index_buffer;

var x_theta = 0.0;
var y_theta = 0.0;
var z_theta = 0.0;

var vertex_buffer;
var v_position;

var color_buffer;
var v_color;

var to_radians = Math.PI / 180.0;

var primitive = 1;

window.onload = function init()
{
    canvas = document.getElementById("webgl-canvas");
    gl = WebGLUtils.setupWebGL(canvas);
    if(gl)
    {
	setup();
	render();
    }
    else
    { alert("Failed initialising WebGL"); }
}

function setup()
{
    gl.viewport(0 , 0 , gl.drawingBufferWidth , gl.drawingBufferHeight);
    gl.clearColor(1.0 , 1.0 , 1.0 , 1.0);
    gl.lineWidth(10.0);

    program = init_program(gl , "vertex-shader" , "fragment-shader");
    gl.useProgram(program);

    shape = create_sphere(10);
    shape_indexes = create_indexes(10);

    pos_matrix = mat4.create();
    pos_matrix = mat4.identity(pos_matrix);
    pos_matrix = mat4.translate(pos_matrix , pos_matrix , [0.0 , 0.0 , -4.0]);

    perspective = mat4.create();
    perspective = mat4.identity(perspective);
    perspective = mat4.perspective
    (
	perspective ,
	45.0 ,
	gl.viewportWidth / gl.viewportHeight ,
	0.1 ,
	100.0
    );
    perspective[0] = 1.7;

    rot_matrix = mat4.create();
}

function render()
{
    vertex_buffer = bind_buffer(gl , shape , vertex_buffer);
    v_position = bind_attribute(gl , program , "v_position" , 3 , v_position);

    index_buffer = bind_indices(gl , shape_indexes , index_buffer);

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	pos_matrix ,
	x_theta ,
	[1 , 0 , 0]
    );

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	rot_matrix ,
	y_theta ,
	[0 , 1 , 0]
    );

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	rot_matrix ,
	z_theta ,
	[0 , 0 , 1]
    );

    u_pos_matrix = gl.getUniformLocation(program , "u_pos_matrix");
    gl.uniformMatrix4fv(u_pos_matrix , false , rot_matrix);

    u_perspective = gl.getUniformLocation(program , "u_perspective");
    gl.uniformMatrix4fv(u_perspective , false , perspective);

    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.drawElements
    (
	primitive ,
	shape_indexes.length ,
	gl.UNSIGNED_SHORT ,
	0
    );

    requestAnimFrame(render);
}

function update_primitive(type)
{
    if(0 <= primitive && primitive <= 6)
	primitive = type;
}

// learningwebgl / webkit team method.
function create_sphere(slices)
{
    var nodes = [];
    var horizontals = slices;
    var horizontal_slice = Math.PI / horizontals;
    var verticals = slices;
    var vertical_slice = 2 * Math.PI / verticals;
    for(var lattitude = 0; lattitude <= horizontals ; lattitude++)
    {
	var theta = lattitude * horizontal_slice;
	var sin_theta = Math.sin(theta);
	var cos_theta = Math.cos(theta);

	for(var longitude = 0; longitude <= verticals ; longitude++)
	{
	    var phi = longitude * vertical_slice;
	    var sin_phi = Math.sin(phi);
	    var cos_phi = Math.cos(phi);

	    var x = cos_phi * sin_theta;
	    var y = cos_theta;
	    var z = sin_phi * sin_theta;
	    nodes.push(x);
	    nodes.push(y);
	    nodes.push(z);
	}
    }
    return nodes;
}

function create_indexes(slices)
{
    var indexes = [];
    var horizontals = slices;
    var verticals = slices;
    for(var lattitude = 0; lattitude < horizontals ; lattitude++)
    {
	for(var longitude = 0; longitude < verticals ; longitude++)
	{
	    var first = (lattitude * (verticals + 1)) + longitude;
	    var second = first + verticals + 1;
	    indexes.push(first);
	    indexes.push(second);
	    indexes.push(first + 1);
	    indexes.push(second);
	    indexes.push(second + 1);
	    indexes.push(first + 1);
	}
    }
    return indexes ;
}

function rotate_x(angle)
{
    x_theta = angle * to_radians;
}

function rotate_y(angle)
{
    y_theta = angle * to_radians;
}

function rotate_z(angle)
{
    z_theta = angle * to_radians;
}
<commit_msg>Do not render continuously, only when required.<commit_after>"use strict";

var canvas;
var gl;
var program;

var pos_matrix;
var u_pos_matrix;

var perspective;
var u_perspective;

var rot_matrix;

var shape;
var shape_indexes;
var index_buffer;

var x_theta = 0.0;
var y_theta = 0.0;
var z_theta = 0.0;

var vertex_buffer;
var v_position;

var color_buffer;
var v_color;

var to_radians = Math.PI / 180.0;

var primitive = 1;

window.onload = function init()
{
    canvas = document.getElementById("webgl-canvas");
    gl = WebGLUtils.setupWebGL(canvas);
    if(gl)
    {
	setup();
	render();
    }
    else
    { alert("Failed initialising WebGL"); }
}

function setup()
{
    gl.viewport(0 , 0 , gl.drawingBufferWidth , gl.drawingBufferHeight);
    gl.clearColor(1.0 , 1.0 , 1.0 , 1.0);
    gl.lineWidth(10.0);

    program = init_program(gl , "vertex-shader" , "fragment-shader");
    gl.useProgram(program);

    shape = create_sphere(10);
    shape_indexes = create_indexes(10);

    pos_matrix = mat4.create();
    pos_matrix = mat4.identity(pos_matrix);
    pos_matrix = mat4.translate(pos_matrix , pos_matrix , [0.0 , 0.0 , -4.0]);

    perspective = mat4.create();
    perspective = mat4.identity(perspective);
    perspective = mat4.perspective
    (
	perspective ,
	45.0 ,
	gl.viewportWidth / gl.viewportHeight ,
	0.1 ,
	100.0
    );
    perspective[0] = 1.7;

    rot_matrix = mat4.create();
}

function render()
{
    vertex_buffer = bind_buffer(gl , shape , vertex_buffer);
    v_position = bind_attribute(gl , program , "v_position" , 3 , v_position);

    index_buffer = bind_indices(gl , shape_indexes , index_buffer);

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	pos_matrix ,
	x_theta ,
	[1 , 0 , 0]
    );

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	rot_matrix ,
	y_theta ,
	[0 , 1 , 0]
    );

    rot_matrix = mat4.rotate
    (
	rot_matrix ,
	rot_matrix ,
	z_theta ,
	[0 , 0 , 1]
    );

    u_pos_matrix = gl.getUniformLocation(program , "u_pos_matrix");
    gl.uniformMatrix4fv(u_pos_matrix , false , rot_matrix);

    u_perspective = gl.getUniformLocation(program , "u_perspective");
    gl.uniformMatrix4fv(u_perspective , false , perspective);

    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.drawElements
    (
	primitive ,
	shape_indexes.length ,
	gl.UNSIGNED_SHORT ,
	0
    );
}

function update_primitive(type)
{
    if(0 <= primitive && primitive <= 6)
	primitive = type;

    render();
}

// learningwebgl / webkit team method.
function create_sphere(slices)
{
    var nodes = [];
    var horizontals = slices;
    var horizontal_slice = Math.PI / horizontals;
    var verticals = slices;
    var vertical_slice = 2 * Math.PI / verticals;
    for(var lattitude = 0; lattitude <= horizontals ; lattitude++)
    {
	var theta = lattitude * horizontal_slice;
	var sin_theta = Math.sin(theta);
	var cos_theta = Math.cos(theta);

	for(var longitude = 0; longitude <= verticals ; longitude++)
	{
	    var phi = longitude * vertical_slice;
	    var sin_phi = Math.sin(phi);
	    var cos_phi = Math.cos(phi);

	    var x = cos_phi * sin_theta;
	    var y = cos_theta;
	    var z = sin_phi * sin_theta;
	    nodes.push(x);
	    nodes.push(y);
	    nodes.push(z);
	}
    }
    return nodes;
}

function create_indexes(slices)
{
    var indexes = [];
    var horizontals = slices;
    var verticals = slices;
    for(var lattitude = 0; lattitude < horizontals ; lattitude++)
    {
	for(var longitude = 0; longitude < verticals ; longitude++)
	{
	    var first = (lattitude * (verticals + 1)) + longitude;
	    var second = first + verticals + 1;
	    indexes.push(first);
	    indexes.push(second);
	    indexes.push(first + 1);
	    indexes.push(second);
	    indexes.push(second + 1);
	    indexes.push(first + 1);
	}
    }
    return indexes ;
}

function rotate_x(angle)
{
    x_theta = angle * to_radians;

    render();
}

function rotate_y(angle)
{
    y_theta = angle * to_radians;

    render();
}

function rotate_z(angle)
{
    z_theta = angle * to_radians;

    render();
}
<|endoftext|>


<commit_before>const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const NODE_ENV = process.env.NODE_ENV;

module.exports = {
  mode: NODE_ENV || 'production',

  entry: {
    'app': './src/js/app.js',
    'train-number-calc': './src/js/train-number-calc.js',
    '404': './src/js/404.js',
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name].js',
    publicPath: 'dist',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false,
            },
          },
          'sass-loader',
        ],
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.vue'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
    },
  },
  devServer: {
    contentBase: path.resolve(__dirname, './'),
    port: 8888,
    inline: true,
    watchContentBase: true,
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.css',
    }),
  ],
  optimization: {
    minimizer: [
      new UglifyJSPlugin(),
      new OptimizeCSSAssetsPlugin({}),
    ],
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
  },
};
<commit_msg>Convert to object<commit_after>const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const NODE_ENV = process.env.NODE_ENV;

module.exports = {
  mode: NODE_ENV || 'production',

  entry: {
    'app': './src/js/app.js',
    'train-number-calc': './src/js/train-number-calc.js',
    '404': './src/js/404.js',
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name].js',
    publicPath: 'dist',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false,
            },
          },
          {
            loader: 'sass-loader',
          },
        ],
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.vue'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
    },
  },
  devServer: {
    contentBase: path.resolve(__dirname, './'),
    port: 8888,
    inline: true,
    watchContentBase: true,
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.css',
    }),
  ],
  optimization: {
    minimizer: [
      new UglifyJSPlugin(),
      new OptimizeCSSAssetsPlugin({}),
    ],
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
  },
};
<|endoftext|>