<commit_before>const parser = require('ua-parser-js');

class SnapdropServer {

    constructor(port) {
        const WebSocket = require('ws');
        this._wss = new WebSocket.Server({ port: port });
        this._wss.on('connection', (socket, request) => this._onConnection(new Peer(socket, request)));
        this._wss.on('headers', (headers, response) => this._onHeaders(headers, response));

        this._rooms = {};

        console.log('Snapdrop is running on port', port);
    }

    _onConnection(peer) {
        this._joinRoom(peer);
        peer.socket.on('message', message => this._onMessage(peer, message));
        this._keepAlive(peer);
    }

    _onHeaders(headers, response) {
        if (response.headers.cookie && response.headers.cookie.indexOf('peerid=') > -1) return;
        response.peerId = Peer.uuid();
        headers.push('Set-Cookie: peerid=' + response.peerId);
    }

    _onMessage(sender, message) {
        message = JSON.parse(message);

        switch (message.type) {
            case 'disconnect':
                this._leaveRoom(sender);
                break;
            case 'pong':
                sender.lastBeat = Date.now();
                break;
        }

        // relay message to recipient
        if (message.to && this._rooms[sender.ip]) {
            const recipientId = message.to; // TODO: sanitize
            const recipient = this._rooms[sender.ip][recipientId];
            delete message.to;
            // add sender id
            message.sender = sender.id;
            this._send(recipient, message);
            return;
        }
    }

    _joinRoom(peer) {
        // if room doesn't exist, create it
        if (!this._rooms[peer.ip]) {
            this._rooms[peer.ip] = {};
        }

        // notify all other peers
        for (const otherPeerId in this._rooms[peer.ip]) {
            const otherPeer = this._rooms[peer.ip][otherPeerId];
            this._send(otherPeer, {
                type: 'peer-joined',
                peer: peer.getInfo()
            });
        }

        // notify peer about the other peers
        const otherPeers = [];
        for (const otherPeerId in this._rooms[peer.ip]) {
            otherPeers.push(this._rooms[peer.ip][otherPeerId].getInfo());
        }

        this._send(peer, {
            type: 'peers',
            peers: otherPeers
        });

        // add peer to room
        this._rooms[peer.ip][peer.id] = peer;
    }

    _leaveRoom(peer) {
        if (!this._rooms[peer.ip] || !this._rooms[peer.ip][peer.id]) return;
        this._cancelKeepAlive(this._rooms[peer.ip][peer.id]);

        // delete the peer
        delete this._rooms[peer.ip][peer.id];

        peer.socket.terminate();
        //if room is empty, delete the room
        if (!Object.keys(this._rooms[peer.ip]).length) {
            delete this._rooms[peer.ip];
        } else {
            // notify all other peers
            for (const otherPeerId in this._rooms[peer.ip]) {
                const otherPeer = this._rooms[peer.ip][otherPeerId];
                this._send(otherPeer, { type: 'peer-left', peerId: peer.id });
            }
        }
    }

    _send(peer, message) {
        if (!peer) return console.error('undefined peer');
        if (this._wss.readyState !== this._wss.OPEN) return console.error('Socket is closed');
        message = JSON.stringify(message);
        peer.socket.send(message, error => error ? console.log(error): '');
    }

    _keepAlive(peer) {
        this._cancelKeepAlive(peer);
        var timeout = 10000;
        if (!peer.lastBeat) {
            peer.lastBeat = Date.now();
        }
        if (Date.now() - peer.lastBeat > 2 * timeout) {
            this._leaveRoom(peer);
            return;
        }

        this._send(peer, { type: 'ping' });

        peer.timerId = setTimeout(() => this._keepAlive(peer), timeout);
    }

    _cancelKeepAlive(peer) {
        if (peer && peer.timerId) {
            clearTimeout(peer.timerId);
        }
    }
}

class Peer {

    constructor(socket, request) {
        // set socket
        this.socket = socket;

        // set remote ip
        this._setIP(request);

        // set peer id
        this._setPeerId(request)
        // is WebRTC supported ?
        this.rtcSupported = request.url.indexOf('webrtc') > -1;
        // set name
        this._setName(request);
        // for keepalive
        this.timerId = 0;
        this.lastBeat = Date.now();
    }

    _setIP(request) {
        if (request.headers['x-forwarded-for']) {
            this.ip = request.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
        } else {
            this.ip = request.connection.remoteAddress;
        }
    }

    _setPeerId(request) {
        if (request.peerId) {
            this.id = request.peerId;
        } else {
            this.id = request.headers.cookie.replace('peerid=', '');
        }
    }

    toString() {
        return `<Peer id=${this.id} ip=${this.ip} rtcSupported=${this.rtcSupported}>`
    }

    _setName(req) {
        var ua = parser(req.headers['user-agent']);
        this.name = {
            model: ua.device.model,
            os: ua.os.name,
            browser: ua.browser.name,
            type: ua.device.type
        };
    }

    getInfo() {
        return {
            id: this.id,
            name: this.name,
            rtcSupported: this.rtcSupported
        }
    }

    // return uuid of form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
    static uuid() {
        let uuid = '',
            ii;
        for (ii = 0; ii < 32; ii += 1) {
            switch (ii) {
                case 8:
                case 20:
                    uuid += '-';
                    uuid += (Math.random() * 16 | 0).toString(16);
                    break;
                case 12:
                    uuid += '-';
                    uuid += '4';
                    break;
                case 16:
                    uuid += '-';
                    uuid += (Math.random() * 4 | 8).toString(16);
                    break;
                default:
                    uuid += (Math.random() * 16 | 0).toString(16);
            }
        }
        return uuid;
    };
}

const server = new SnapdropServer(process.env.PORT || 3000);<commit_msg>Make IPv4 and IPv6 localhost connections use the same room.<commit_after>const parser = require('ua-parser-js');

class SnapdropServer {

    constructor(port) {
        const WebSocket = require('ws');
        this._wss = new WebSocket.Server({ port: port });
        this._wss.on('connection', (socket, request) => this._onConnection(new Peer(socket, request)));
        this._wss.on('headers', (headers, response) => this._onHeaders(headers, response));

        this._rooms = {};

        console.log('Snapdrop is running on port', port);
    }

    _onConnection(peer) {
        let room = this._joinRoom(peer);
        peer.socket.on('message', message => this._onMessage(peer, room, message));
        this._keepAlive(peer);
    }

    _onHeaders(headers, response) {
        if (response.headers.cookie && response.headers.cookie.indexOf('peerid=') > -1) return;
        response.peerId = Peer.uuid();
        headers.push('Set-Cookie: peerid=' + response.peerId);
    }

    _onMessage(sender, roomName, message) {
        message = JSON.parse(message);

        switch (message.type) {
            case 'disconnect':
                this._leaveRoom(sender, roomName);
                break;
            case 'pong':
                sender.lastBeat = Date.now();
                break;
        }

        // relay message to recipient
        if (message.to && this._rooms[roomName]) {
            const recipientId = message.to; // TODO: sanitize
            const recipient = this._rooms[roomName][recipientId];
            delete message.to;
            // add sender id
            message.sender = sender.id;
            this._send(recipient, message);
            return;
        }
    }

    _joinRoom(peer) {
        let roomName = peer.ip;

        // localhost can use multiple IP addresses
        if (roomName == '::1' || roomName == '::ffff:127.0.0.1') {
            roomName = '127.0.0.1';
        }

        // if room doesn't exist, create it
        if (!this._rooms[roomName]) {
            this._rooms[roomName] = {};
        }

        // notify all other peers
        for (const otherPeerId in this._rooms[roomName]) {
            const otherPeer = this._rooms[roomName][otherPeerId];
            this._send(otherPeer, {
                type: 'peer-joined',
                peer: peer.getInfo()
            });
        }

        // notify peer about the other peers
        const otherPeers = [];
        for (const otherPeerId in this._rooms[roomName]) {
            otherPeers.push(this._rooms[roomName][otherPeerId].getInfo());
        }

        this._send(peer, {
            type: 'peers',
            peers: otherPeers
        });

        // add peer to room
        this._rooms[roomName][peer.id] = peer;

        return roomName;
    }

    _leaveRoom(peer, roomName) {
        if (!this._rooms[roomName] || !this._rooms[roomName][peer.id]) return;
        this._cancelKeepAlive(this._rooms[roomName][peer.id]);

        // delete the peer
        delete this._rooms[roomName][peer.id];

        peer.socket.terminate();
        //if room is empty, delete the room
        if (!Object.keys(this._rooms[roomName]).length) {
            delete this._rooms[roomName];
        } else {
            // notify all other peers
            for (const otherPeerId in this._rooms[roomName]) {
                const otherPeer = this._rooms[roomName][otherPeerId];
                this._send(otherPeer, { type: 'peer-left', peerId: peer.id });
            }
        }
    }

    _send(peer, message) {
        if (!peer) return console.error('undefined peer');
        if (this._wss.readyState !== this._wss.OPEN) return console.error('Socket is closed');
        message = JSON.stringify(message);
        peer.socket.send(message, error => error ? console.log(error): '');
    }

    _keepAlive(peer) {
        this._cancelKeepAlive(peer);
        var timeout = 10000;
        if (!peer.lastBeat) {
            peer.lastBeat = Date.now();
        }
        if (Date.now() - peer.lastBeat > 2 * timeout) {
            this._leaveRoom(peer);
            return;
        }

        this._send(peer, { type: 'ping' });

        peer.timerId = setTimeout(() => this._keepAlive(peer), timeout);
    }

    _cancelKeepAlive(peer) {
        if (peer && peer.timerId) {
            clearTimeout(peer.timerId);
        }
    }
}

class Peer {

    constructor(socket, request) {
        // set socket
        this.socket = socket;

        // set remote ip
        this._setIP(request);

        // set peer id
        this._setPeerId(request)
        // is WebRTC supported ?
        this.rtcSupported = request.url.indexOf('webrtc') > -1;
        // set name
        this._setName(request);
        // for keepalive
        this.timerId = 0;
        this.lastBeat = Date.now();
    }

    _setIP(request) {
        if (request.headers['x-forwarded-for']) {
            this.ip = request.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
        } else {
            this.ip = request.connection.remoteAddress;
        }
    }

    _setPeerId(request) {
        if (request.peerId) {
            this.id = request.peerId;
        } else {
            this.id = request.headers.cookie.replace('peerid=', '');
        }
    }

    toString() {
        return `<Peer id=${this.id} ip=${this.ip} rtcSupported=${this.rtcSupported}>`
    }

    _setName(req) {
        var ua = parser(req.headers['user-agent']);
        this.name = {
            model: ua.device.model,
            os: ua.os.name,
            browser: ua.browser.name,
            type: ua.device.type
        };
    }

    getInfo() {
        return {
            id: this.id,
            name: this.name,
            rtcSupported: this.rtcSupported
        }
    }

    // return uuid of form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
    static uuid() {
        let uuid = '',
            ii;
        for (ii = 0; ii < 32; ii += 1) {
            switch (ii) {
                case 8:
                case 20:
                    uuid += '-';
                    uuid += (Math.random() * 16 | 0).toString(16);
                    break;
                case 12:
                    uuid += '-';
                    uuid += '4';
                    break;
                case 16:
                    uuid += '-';
                    uuid += (Math.random() * 4 | 8).toString(16);
                    break;
                default:
                    uuid += (Math.random() * 16 | 0).toString(16);
            }
        }
        return uuid;
    };
}

const server = new SnapdropServer(process.env.PORT || 3000);<|endoftext|>


<commit_before>var _ = require('lodash')
var moment = require('moment')
var excelWriter = require('./excel-writer')
var fs = require('fs')
var enums = require('../shared/enums')

var dateFormat = 'DD.MM.YYYY'

exports.createProviderRegistration = function createProviderRegistration(accountRows) {
  return createBilling(accountRows, _.curry(providerBillingHeader)(null), providerRowDescription, _.curry(providerBillingFooter)(accountRows))
}

exports.createYearlyProviderRegistration = function createYearlyProviderRegistration(year, accountRows) {
  return createBilling(accountRows, _.curry(providerBillingHeader)(moment().year()), providerRowDescription, _.curry(providerBillingFooter)(accountRows))
}

function providerBillingHeader(year, invoice) {
  return 'Valvontamaksu, vuosi ' + (year ? year : invoice.registrationDate.getFullYear()) + '. ' + invoice.invoiceText
}

function providerRowDescription(invoice) {
  return [moment(invoice.registrationDate).format(dateFormat), enums.providingType[invoice.providingType], invoice.name].join(', ')
}

function providerBillingFooter(accountRows, invoice) {
  var account = findAccountHavingInvoice(accountRows, invoice)
  return 'Lasku yhteensä ' + price(account.rows) + ' EUR'
}

exports.createClassificationRegistration = function createClassificationRegistration(dateRange, accountRows) {
  function billingHeader(invoice) {
    var period = dateRange.begin + ' - ' + dateRange.end
    return 'KOONTILASKUTUS ' + period + '. ' + invoice.invoiceText
  }
  function rowDescription(invoice) {
    return [
      invoice.programSequenceId,
      moment(invoice.registrationDate).format(dateFormat),
      invoice.name
    ].join(' ')
  }
  function billingFooter(invoice) {
    function summaryText(type, rows) {
      var typeString = { classification: 'luokiteltu', reclassification: 'uudelleenluokiteltu', registration: 'rekisteröity' }
      var plural = rows.length > 1 ? ' kuvaohjelmaa ' : ' kuvaohjelma '
      return rows.length + plural + typeString[type] + ', yhteensä ' + price(rows) + ' EUR.'
    }
    var account = findAccountHavingInvoice(accountRows, invoice)
    var rowsPerType = _.groupBy(account.rows, 'type')
    return _.pairs(rowsPerType).map(function (item) {
      return summaryText(item[0], item[1])
    }).join(' ')
  }
  return createBilling(accountRows, billingHeader, rowDescription, billingFooter)
}

function findAccountHavingInvoice(accountRows, invoice) {
  return _.find(accountRows, function (account) { return _.indexOf(account.rows, invoice) != -1 })
}

function price(arr) {
  return _(arr).pluck('price').reduce(function (a, b) {
    return a + b
  }, 0) / 100
}

function createBilling(accounts, billingDescription, rowDescription, billingFooter) {
  var billingData = _.flatten(_.map(accounts, function (ac) {
    var account = ac.account
    var rows = ac.rows
    var first = _.first(rows)
    var invoiceText = account.billing ? (account.billing.invoiceText || '').replace(/\n/g, ' ') : ''
    var accountAddress = customerNumber ? {} : account.billingPreference == 'address' ? account.billing.address : account.address
    return _.map(rows, function (row) {
      return _.extend(row, {
        first: row === first ? 1 : 0,
        accountName: account.name,
        accountContactName: account.contactName,
        accountStreetAddress: accountAddress.street,
        accountZipCode: accountAddress.zip,
        accountCity: accountAddress.city,
        invoiceItemCode: enums.invoiceItemCode(row.providingType ? row.providingType : row.type, row.duration),
        invoiceText: invoiceText,
        euroPrice: row.price / 100
      })
    })
  }))
  var columns = [
    { name: 'T', value: invoiceValue('first'), repeatable: true, width: 2 },
    { name: 'Tilauslaji', value: constantValue('Z001') },
    { name: 'Myyntiorg', value: constantValue('6008') },
    { name: 'Jakelutie', value: constantValue('02') },
    { name: 'Sektori', value: constantValue('01') },
    { name: 'Myyntitsto', value: constantValue('') },
    { name: 'Viitelasku', value: constantValue('') },
    { name: 'Asiakasnro', value: constantValue('??') },
    { name: 'Nimi', value: invoiceValue('accountName'), width: 30 },
    { name: 'Lähiosoite', value: invoiceValue('accountStreetAddress') },
    { name: 'PostiNo', value: invoiceValue('accountZipCode') },
    { name: 'Toimipaikka', value: invoiceValue('accountCity') },
    { name: 'Laskutusasiakasnro', value: constantValue('') },
    { name: 'Laskutusasiakas nimi', value: constantValue('') },
    { name: 'Maksaja-asiakasnro', value: constantValue('') },
    { name: 'Maksaja-asiakas nimi', value: constantValue('') },
    { name: 'Toimitusasiakasnro', value: constantValue('') },
    { name: 'Palvelun luontipvm', value: constantValue('') },
    { name: 'Laskuttaja', value: constantValue('??') },
    { name: 'Asiaviite', value: invoiceValue('accountContactName'), width: 15 },
    { name: 'Tilausnumero', value: constantValue('') },
    { name: 'Otsikkoteksti: Otsikkomuistio 1 (tekstilaji 0002) tulostuu ennen rivejä. Huom. Kirjoita teksti katkeamattomasti, ei rivivaihtoja eikä alt+enter painikkeita', value: billingDescription, width: 20 },
    { name: 'Otsikkoteksti: Maksuperusteteksti (tekstilaji Z000) tulostuu laskun loppuun. Huom. Kirjoita teksti katkeamattomasti, ei rivivaihtoja eikä alt+enter painikkeita', value: billingFooter, width: 20 },
    { name: 'Nimike', value: invoiceValue('invoiceItemCode'), repeatable: true },
    { name: 'Määrä', value: constantValue(1), repeatable: true },
    { name: 'Määräyksikkö', value: constantValue('kpl'), repeatable: true },
    { name: 'Yksikköhinta', value: invoiceValue('euroPrice'), repeatable: true },
    { name: 'Brutto/Netto', value: constantValue('N'), repeatable: true },
    { name: 'Tulosyksikkö', value: constantValue('') },
    { name: 'Nimikkeen nimitysteksti (laskutusaihe)', value: constantValue(''), width: 20 },
    { name: 'Riviteksti: Rivimuistio (tekstilaji 0002), tulostuu laskulle rivin jälkeen', value: rowDescription, width:30, repeatable: true },
    { name: 'PRR-osa', value: constantValue('') },
    { name: 'TaKP-tili', value: constantValue('') },
    { name: 'Suorite', value: constantValue('') },
    { name: 'Toiminto', value: constantValue('') },
    { name: 'Alue /  kunta', value: constantValue('') },
    { name: 'Seurantakohde 1', value: constantValue('') },
    { name: 'Seurantakohde 2', value: constantValue('') },
    { name: 'Laskuliitteet', value: constantValue('') }
  ]

  function invoiceValue(key) {
    function valueFromInvoice(key, invoice) {
      return invoice[key]
    }
    return _.curry(valueFromInvoice)(key)
  }

  function constantValue(c) {
    function constant(c, invoice) {
      return c
    }
    return _.curry(constant)(c)
  }

  var xlsData = [ _.map(columns, function (column) { return column.name }) ]
  _.each(billingData, function (invoice) {
    xlsData.push(_.map(columns, function (column) {
      return invoice.first || column.repeatable ? column.value(invoice) : ''
    }))
  })
  var tmpXlsxFile = 'kieku_' + Math.random() + '.xlsx'
  var columnWidths = _.map(columns, function (column) { return { wch: (column.width || 10) }})
  excelWriter.write(tmpXlsxFile, xlsData, columnWidths)
  var fileData = fs.readFileSync(tmpXlsxFile)
  fs.unlinkSync(tmpXlsxFile)
  return fileData
}
<commit_msg>New fields to kieku invoicing<commit_after>var _ = require('lodash')
var moment = require('moment')
var excelWriter = require('./excel-writer')
var fs = require('fs')
var enums = require('../shared/enums')

var dateFormat = 'DD.MM.YYYY'

exports.createProviderRegistration = function createProviderRegistration(accountRows) {
  return createBilling(accountRows, _.curry(providerBillingHeader)(null), providerRowDescription, _.curry(providerBillingFooter)(accountRows))
}

exports.createYearlyProviderRegistration = function createYearlyProviderRegistration(year, accountRows) {
  return createBilling(accountRows, _.curry(providerBillingHeader)(moment().year()), providerRowDescription, _.curry(providerBillingFooter)(accountRows))
}

function providerBillingHeader(year, invoice) {
  return 'Valvontamaksu, vuosi ' + (year ? year : invoice.registrationDate.getFullYear()) + '. ' + invoice.invoiceText
}

function providerRowDescription(invoice) {
  return [moment(invoice.registrationDate).format(dateFormat), enums.providingType[invoice.providingType], invoice.name].join(', ')
}

function providerBillingFooter(accountRows, invoice) {
  var account = findAccountHavingInvoice(accountRows, invoice)
  return 'Lasku yhteensä ' + price(account.rows) + ' EUR'
}

exports.createClassificationRegistration = function createClassificationRegistration(dateRange, accountRows) {
  function billingHeader(invoice) {
    var period = dateRange.begin + ' - ' + dateRange.end
    return 'KOONTILASKUTUS ' + period + '. ' + invoice.invoiceText
  }
  function rowDescription(invoice) {
    return [
      invoice.programSequenceId,
      moment(invoice.registrationDate).format(dateFormat),
      invoice.name
    ].join(' ')
  }
  function billingFooter(invoice) {
    function summaryText(type, rows) {
      var typeString = { classification: 'luokiteltu', reclassification: 'uudelleenluokiteltu', registration: 'rekisteröity' }
      var plural = rows.length > 1 ? ' kuvaohjelmaa ' : ' kuvaohjelma '
      return rows.length + plural + typeString[type] + ', yhteensä ' + price(rows) + ' EUR.'
    }
    var account = findAccountHavingInvoice(accountRows, invoice)
    var rowsPerType = _.groupBy(account.rows, 'type')
    return _.pairs(rowsPerType).map(function (item) {
      return summaryText(item[0], item[1])
    }).join(' ')
  }
  return createBilling(accountRows, billingHeader, rowDescription, billingFooter)
}

function findAccountHavingInvoice(accountRows, invoice) {
  return _.find(accountRows, function (account) { return _.indexOf(account.rows, invoice) != -1 })
}

function price(arr) {
  return _(arr).pluck('price').reduce(function (a, b) {
    return a + b
  }, 0) / 100
}

function createBilling(accounts, billingDescription, rowDescription, billingFooter) {
  var billingData = _.flatten(_.map(accounts, function (ac) {
    var account = ac.account
    var rows = ac.rows
    var first = _.first(rows)
    var billingLanguage = account.billingPreference == 'address' ? account.billing.language : account.language
    var invoiceText = account.billing ? (account.billing.invoiceText || '').replace(/\n/g, ' ') : ''
    var accountAddress = customerNumber ? {} : account.billingPreference == 'address' ? account.billing.address : account.address
    return _.map(rows, function (row) {
      return _.extend(row, {
        first: row === first ? 1 : 0,
        accountName: account.name,
        accountContactName: account.contactName,
        accountStreetAddress: accountAddress.street,
        accountZipCode: accountAddress.zip,
        accountCity: accountAddress.city,
        accountCountry: accountAddress.country,
        invoiceItemCode: enums.invoiceItemCode(row.providingType ? row.providingType : row.type, row.duration),
        invoiceText: invoiceText,
        euroPrice: row.price / 100,
        billingLanguage: billingLanguage
      })
    })
  }))
  var columns = [
    { name: 'T', value: invoiceValue('first'), repeatable: true, width: 2 },
    { name: 'Tilauslaji', value: constantValue('Z001') },
    { name: 'Myyntiorg', value: constantValue('6008') },
    { name: 'Jakelutie', value: constantValue('02') },
    { name: 'Sektori', value: constantValue('01') },
    { name: 'Myyntitsto', value: constantValue('') },
    { name: 'Viitelasku', value: constantValue('') },
    { name: 'Asiakasnro', value: constantValue('??') },
    { name: 'Nimi', value: invoiceValue('accountName'), width: 30 },
    { name: 'Nimi2', value: constantValue('') },
    { name: 'Lähiosoite', value: invoiceValue('accountStreetAddress') },
    { name: 'PostiNo', value: invoiceValue('accountZipCode') },
    { name: 'Toimipaikka', value: invoiceValue('accountCity') },
    { name: 'Maakoodi', value: invoiceValue('accountCountry') },
    { name: 'Kielikoodi', value: invoiceValue('billingLanguage') },
    { name: 'Laskutusasiakasnro', value: constantValue('') },
    { name: 'Laskutusasiakas nimi', value: constantValue('') },
    { name: 'Maksaja-asiakasnro', value: constantValue('') },
    { name: 'Maksaja-asiakas nimi', value: constantValue('') },
    { name: 'Toimitusasiakasnro', value: constantValue('') },
    { name: 'Toimitusasiakas nimi', value: constantValue('') },
    { name: 'Palvelun luontipvm', value: constantValue('') },
    { name: 'Hinnoittelupvm', value: constantValue('') },
    { name: 'Laskuttaja', value: constantValue('??') },
    { name: 'Asiaviite', value: invoiceValue('accountContactName'), width: 15 },
    { name: 'Tilausnumero', value: constantValue('') },
    { name: 'Poikk. veron määrämaa', value: constantValue('') },
    { name: 'Otsikkoteksti: Otsikkomuistio 1 (tekstilaji 0002) tulostuu ennen rivejä. Huom. Kirjoita teksti katkeamattomasti, ei rivivaihtoja eikä alt+enter painikkeita', value: billingDescription, width: 20 },
    { name: 'Otsikkoteksti: Maksuperusteteksti (tekstilaji Z000) tulostuu laskun loppuun. Huom. Kirjoita teksti katkeamattomasti, ei rivivaihtoja eikä alt+enter painikkeita', value: billingFooter, width: 20 },
    { name: 'Nimike', value: invoiceValue('invoiceItemCode'), repeatable: true },
    { name: 'Määrä', value: constantValue(1), repeatable: true },
    { name: 'Määräyksikkö', value: constantValue('kpl'), repeatable: true },
    { name: 'Yksikköhinta', value: invoiceValue('euroPrice'), repeatable: true },
    { name: 'Brutto/Netto', value: constantValue('N'), repeatable: true },
    { name: 'Rivityyppi', value: constantValue('') },
    { name: 'Tulosyksikkö', value: constantValue('') },
    { name: 'Nimikkeen nimitysteksti (laskutusaihe)', value: constantValue(''), width: 20 },
    { name: 'Riviteksti: Rivimuistio (tekstilaji 0002), tulostuu laskulle rivin jälkeen', value: rowDescription, width:30, repeatable: true },
    { name: 'PRR-osa', value: constantValue('') },
    { name: 'TaKP-tili', value: constantValue('') },
    { name: 'Suorite', value: constantValue('') },
    { name: 'Toiminto', value: constantValue('') },
    { name: 'Alue /  kunta', value: constantValue('') },
    { name: 'Seurantakohde 1', value: constantValue('') },
    { name: 'Seurantakohde 2', value: constantValue('') },
    { name: 'Laskuliitteet', value: constantValue('') }
  ]

  function invoiceValue(key) {
    function valueFromInvoice(key, invoice) {
      return invoice[key]
    }
    return _.curry(valueFromInvoice)(key)
  }

  function constantValue(c) {
    function constant(c, invoice) {
      return c
    }
    return _.curry(constant)(c)
  }

  var xlsData = [ _.map(columns, function (column) { return column.name }) ]
  _.each(billingData, function (invoice) {
    xlsData.push(_.map(columns, function (column) {
      return invoice.first || column.repeatable ? column.value(invoice) : ''
    }))
  })
  var tmpXlsxFile = 'kieku_' + Math.random() + '.xlsx'
  var columnWidths = _.map(columns, function (column) { return { wch: (column.width || 10) }})
  excelWriter.write(tmpXlsxFile, xlsData, columnWidths)
  var fileData = fs.readFileSync(tmpXlsxFile)
  fs.unlinkSync(tmpXlsxFile)
  return fileData
}
<|endoftext|>


<commit_before>Media.allow({
      insert: function(userId) {
        return isAdminById(userId);
      },
      update: function(userId) {
        return isAdminById(userId);
      },
      remove: function(userId) {
        return isAdminById(userId);
      },
      download: function(userId) {
        return true;
      },
      fetch: []
    });

 Meteor.publish("media", function(options) {
      return Media.find({}, options, { fields: {"copies.default": 0}});
 });

 Meteor.publish("albumMedia", function(albumSlug, options) {
      var album = Albums.findOne({slug: albumSlug});

      if (!! album) {
        var visible = !! album.isVisible;

        if (visible || isAdminById(this.userId)) {
          return Media.find({'metadata.albums': { $elemMatch: { _id: album._id} }},
                              options, { fields: {'copies.default': 0}});

        } else {
          return null;
        }
      }

 });

 Meteor.publish("mediaTags", function(options) {
      return Media.find({}, { fields: {"metadata.tags": 1, 'metadata.title': 1, 'original.name': 1}});
 });

<commit_msg>added publication for media by tag<commit_after>Media.allow({
      insert: function(userId) {
        return isAdminById(userId);
      },
      update: function(userId) {
        return isAdminById(userId);
      },
      remove: function(userId) {
        return isAdminById(userId);
      },
      download: function(userId) {
        return true;
      },
      fetch: []
    });

 // publish all media, omit unnecessary fields
 Meteor.publish("media", function(options) {
      return Media.find({}, options, { fields: {"copies.default": 0}});
 });

 // publish only media in a specific album
 Meteor.publish("albumMedia", function(albumSlug, options) {
      var album = Albums.findOne({slug: albumSlug});

      if (!! album) {
        var visible = !! album.isVisible;

        if (visible || isAdminById(this.userId)) {
          return Media.find({'metadata.albums': { $elemMatch: { _id: album._id} }},
                              options, { fields: {'copies.default': 0}});

        } else {
          return null;
        }
      }

 });

 // publish all media with a specific tag
 Meteor.publish("tagMedia", function(tagSlug, options) {
    return Media.find({'metadata.tags.slug': tagSlug}, options, { fields: {'copies.default': 0}});
 });

 // condensed version of media for tags list
 Meteor.publish("mediaTags", function(options) {
    return Media.find({}, { fields: {"metadata.tags": 1, 'metadata.title': 1, 'original.name': 1}});
 });

<|endoftext|>


<commit_before>"use strict"

function md5(str) {
  var xl;

  var rotateLeft = function (lValue, iShiftBits) {
    return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
  };

  var addUnsigned = function (lX, lY) {
    var lX4, lY4, lX8, lY8, lResult;
    lX8 = (lX & 0x80000000);
    lY8 = (lY & 0x80000000);
    lX4 = (lX & 0x40000000);
    lY4 = (lY & 0x40000000);
    lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
    if (lX4 & lY4) {
      return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
    }
    if (lX4 | lY4) {
      if (lResult & 0x40000000) {
        return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
      } else {
        return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
      }
    } else {
      return (lResult ^ lX8 ^ lY8);
    }
  };

  var _F = function (x, y, z) {
    return (x & y) | ((~x) & z);
  };
  var _G = function (x, y, z) {
    return (x & z) | (y & (~z));
  };
  var _H = function (x, y, z) {
    return (x ^ y ^ z);
  };
  var _I = function (x, y, z) {
    return (y ^ (x | (~z)));
  };

  var _FF = function (a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
    return addUnsigned(rotateLeft(a, s), b);
  };

  var _GG = function (a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
    return addUnsigned(rotateLeft(a, s), b);
  };

  var _HH = function (a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
    return addUnsigned(rotateLeft(a, s), b);
  };

  var _II = function (a, b, c, d, x, s, ac) {
    a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
    return addUnsigned(rotateLeft(a, s), b);
  };

  var convertToWordArray = function (str) {
    var lWordCount;
    var lMessageLength = str.length;
    var lNumberOfWords_temp1 = lMessageLength + 8;
    var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
    var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
    var lWordArray = new Array(lNumberOfWords - 1);
    var lBytePosition = 0;
    var lByteCount = 0;
    while (lByteCount < lMessageLength) {
      lWordCount = (lByteCount - (lByteCount % 4)) / 4;
      lBytePosition = (lByteCount % 4) * 8;
      lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
      lByteCount++;
    }
    lWordCount = (lByteCount - (lByteCount % 4)) / 4;
    lBytePosition = (lByteCount % 4) * 8;
    lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
    lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
    lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
    return lWordArray;
  };

  var wordToHex = function (lValue) {
    var wordToHexValue = '',
      wordToHexValue_temp = '',
      lByte, lCount;
    for (lCount = 0; lCount <= 3; lCount++) {
      lByte = (lValue >>> (lCount * 8)) & 255;
      wordToHexValue_temp = '0' + lByte.toString(16);
      wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
    }
    return wordToHexValue;
  };

  var x = [],
    k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
    S12 = 12,
    S13 = 17,
    S14 = 22,
    S21 = 5,
    S22 = 9,
    S23 = 14,
    S24 = 20,
    S31 = 4,
    S32 = 11,
    S33 = 16,
    S34 = 23,
    S41 = 6,
    S42 = 10,
    S43 = 15,
    S44 = 21;

  str = this.utf8_encode(str);
  x = convertToWordArray(str);
  a = 0x67452301;
  b = 0xEFCDAB89;
  c = 0x98BADCFE;
  d = 0x10325476;

  xl = x.length;
  for (k = 0; k < xl; k += 16) {
    AA = a;
    BB = b;
    CC = c;
    DD = d;
    a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
    d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
    c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
    b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
    a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
    d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
    c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
    b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
    a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
    d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
    c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
    b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
    a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
    d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
    c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
    b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
    a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
    d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
    c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
    b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
    a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
    d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
    c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
    b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
    a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
    d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
    c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
    b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
    a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
    d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
    c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
    b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
    a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
    d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
    c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
    b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
    a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
    d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
    c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
    b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
    a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
    d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
    c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
    b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
    a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
    d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
    c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
    b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
    a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
    d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
    c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
    b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
    a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
    d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
    c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
    b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
    a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
    d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
    c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
    b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
    a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
    d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
    c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
    b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
    a = addUnsigned(a, AA);
    b = addUnsigned(b, BB);
    c = addUnsigned(c, CC);
    d = addUnsigned(d, DD);
  }

  var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);

  return temp.toLowerCase();
}

exports.module = function() {
	this.onCommand_md5 = function(nick, args) {
		this.channel.say(md5(args));
	}
}
<commit_msg>Update md5.js<commit_after>"use strict"

var md5 = require('MD5');

exports.module = function() {
	this.onCommand_md5 = function(nick, args) {
		this.channel.say(md5(args));
	}
}
<|endoftext|>


<commit_before>"use strict";

var fs = require("fs");

/* Sources:
    http://en.wikipedia.org/wiki/.3ds
    http://www.spacesimulator.net/wiki/index.php?title=Tutorials:3ds_Loader
    http://www.the-labs.com/Blender/3dsspec.html
*/

var chunkUtils = (function(){

    var chunkIds = {
        "Main": 0x4d4d,
        "M3D Version": 0x0002,
        "3D Editor Chunk": 0x3D3D,
        "Object Block": 0x4000,
        "Triangular Mesh": 0x4100,
        "Vertices List": 0x4110,
        "Faces Description": 0x4120,
        "Faces Material": 0x4130,
        "Smoothing Group List": 0x4150,
        "Mapping Coordinates List": 0x4140,
        "Local Coordinates System": 0x4160,
        "Light": 0x4600,
        "Spotlight": 0x4610,
        "Camera": 0x4700,
        "Material Block": 0xAFFF
    };

    var children = {
        "Main" : [
            chunkIds["M3D Version"],
            chunkIds["3D Editor Chunk"]
        ],
        "3D Editor Chunk" : [
            chunkIds["Object Block"],
            chunkIds["Material Block"]
        ],
        "Object Block" : [
            chunkIds["Triangular Mesh"],
            chunkIds["Light"],
            chunkIds["Camera"]
        ],
        "Triangular Mesh" : [
            chunkIds["Vertices List"],
            chunkIds["Faces Description"],
            chunkIds["Mapping Coordinates List"],
            chunkIds["Local Coordinates System"]
        ],
        "Faces Description": [
            chunkIds["Faces Material"],
            chunkIds["Smoothing Group List"]
        ]
    };
    /*
    0x4D4D // Main Chunk
    ├─ 0x0002 // M3D Version
    ├─ 0x3D3D // 3D Editor Chunk
    │  ├─ 0x4000 // Object Block
    │  │  ├─ 0x4100 // Triangular Mesh
    │  │  │  ├─ 0x4110 // Vertices List
    │  │  │  ├─ 0x4120 // Faces Description
    │  │  │  │  ├─ 0x4130 // Faces Material
    │  │  │  │  └─ 0x4150 // Smoothing Group List
    │  │  │  ├─ 0x4140 // Mapping Coordinates List
    │  │  │  └─ 0x4160 // Local Coordinates System
    │  │  ├─ 0x4600 // Light
    │  │  │  └─ 0x4610 // Spotlight
    │  │  └─ 0x4700 // Camera
    │  └─ 0xAFFF // Material Block
    │     ├─ 0xA000 // Material Name
    │     ├─ 0xA010 // Ambient Color
    │     ├─ 0xA020 // Diffuse Color
    │     ├─ 0xA030 // Specular Color
    │     ├─ 0xA200 // Texture Map 1
    │     ├─ 0xA230 // Bump Map
    │     └─ 0xA220 // Reflection Map
    │        │  // Sub Chunks For Each Map
    │        ├─ 0xA300 // Mapping Filename
    │        └─ 0xA351 // Mapping Parameters
    └─ 0xB000 // Keyframer Chunk
       ├─ 0xB002 // Mesh Information Block
       ├─ 0xB007 // Spot Light Information Block
       └─ 0xB008 // Frames (Start and End)
          ├─ 0xB010 // Object Name
          ├─ 0xB013 // Object Pivot Point
          ├─ 0xB020 // Position Track
          ├─ 0xB021 // Rotation Track
          ├─ 0xB022 // Scale Track
          └─ 0xB030 // Hierarchy Position
    */

    var chunkNameById = {};
    Object.keys(chunkIds).forEach(function(name){
        var value = chunkIds[name];
        chunkNameById[value] = name;
    });

    return {
        getChunkName: function(id){
            return chunkNameById[id];
        },
        getPotentialChildrenIds: function(name){
            return children[name] || [];
        },
        getChunkId: function(name){
            return chunkIds[name];
        }
    }

})();

//console.log(chunkNameById);

// buff only contains the content (length and type have been stripped out)
function Chunk(buff, type){
    //if(type === "Vertices List")
    //  console.log('Creating Vertices List chunk', buff.length)
    if(type === "Mapping Coordinates List")
      console.log('Creating Mapping Coordinates List chunk', buff.length)

    var children = [];

    var childTypeValue, childType;
    var childLength;

    var childrenIds = chunkUtils.getPotentialChildrenIds(type);

    // search for own data
    var ownDataLength = 0;
    var cursor = 0;

    if(type === "Vertices List" || type === "Faces Description" || type === "Mapping Coordinates List"){
        if(type === "Vertices List"){
            var verticesNumber = buff.readUInt16LE(cursor);
            ownDataLength = 2 + (3*4)*verticesNumber;
        }
        if(type === "Faces Description"){
            var facesNumber = buff.readUInt16LE(cursor);
            ownDataLength = 2 + (3*2+2)*facesNumber;
        }
        if(type === "Mapping Coordinates List"){
            var uvsNumber = buff.readUInt16LE(cursor);
            ownDataLength = 2 + (2*4)*uvsNumber;
        }

        cursor = ownDataLength;
    }
    else{
        while(cursor < buff.length - 2){
            childTypeValue = buff.readUInt16LE(cursor);
            if(childrenIds.indexOf(childTypeValue) !== -1)
                break;
            cursor += 1;
        }

        ownDataLength = cursor < buff.length - 2 ? cursor : buff.length;
    }

    if(ownDataLength > buff.length)
        throw new RangeError();

    // look for children
    while(cursor < buff.length -2){
        childTypeValue = buff.readUInt16LE(cursor);
        // beginning of a child
        childType = chunkUtils.getChunkName(childTypeValue);
        childLength = buff.readUInt32LE(cursor+2);

        if(childrenIds.indexOf(childTypeValue) !== -1){
            //if(type === "Triangular Mesh")
            //  console.log(type, 'creating child chunk of length from',  cursor + 6, 'to', cursor + childLength)
            children.push(Chunk(buff.slice(cursor + 6, cursor + childLength), childType));
        }
        else{
            //console.warn('skipping', childTypeValue, childLength);
        }
        cursor += childLength;
    }

    var ret = {
        get type(){
            return type;
        },
        get ownData(){
            return buff.slice(0, ownDataLength);
        },
        children : children,

        toString: function(indent){
            indent = indent || 0;

            var spaces = '';
            for(var i = 0; i < indent ; i++)
                spaces += ' ';

            return spaces + this.type + ' ' + (ownDataLength) + ' ' + (buff.length) + '\n' +
                this.children.map(function(chunk){ return chunk.toString(indent+2); }).join('');
        }
    };

    // TODO make mixins for these and move this code away
    if(type === "Object Block"){
        Object.defineProperty(ret, "meshes", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Triangular Mesh";
                })[0]; // singleton
            }
        });
        Object.defineProperty(ret, "name", {
            get: function(){
                var ownData = this.ownData
                return ownData.toString('utf-8', 0, ownData.length -1);
            }
        });
    }
    if(type === "Triangular Mesh"){
        Object.defineProperty(ret, "vertices", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Vertices List";
                })[0].vertices; // singleton
            }
        });
        Object.defineProperty(ret, "faces", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Faces Description";
                })[0].faces; // singleton
            }
        });
        Object.defineProperty(ret, "uvs", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Mapping Coordinates List";
                })[0].uvs; // singleton
            }
        });
    }
    if(type === "Vertices List"){
        Object.defineProperty(ret, "vertices", {
            get: function(){
                var data = this.ownData;

                var cursor = 0;

                var verticesNumber = data.readUInt16LE(cursor);
                cursor += 2;

                //console.log(verticesNumber);
                var vertices = [];

                while(verticesNumber > 0){
                    vertices.push({
                        x: data.readFloatLE(cursor),
                        y: data.readFloatLE(cursor+4),
                        z: data.readFloatLE(cursor+8)
                    });

                    cursor += 12;
                    verticesNumber--;
                }

                return vertices;
            }
        });
    }

    if(type === "Faces Description"){
        Object.defineProperty(ret, "faces", {
            get: function(){
                var data = this.ownData;

                var cursor = 0;

                var facesNumber = data.readUInt16LE(cursor);
                cursor += 2;

                var faces = [];
                var flags;

                while(facesNumber > 0){
                    faces.push({
                        a: data.readUInt16LE(cursor),
                        b: data.readUInt16LE(cursor+2),
                        c: data.readUInt16LE(cursor+4)
                    });

                    // pasing flags, but not using them.
                    flags = data.readUInt16LE(cursor+6);

                    cursor += 8;
                    facesNumber--;
                }

                return faces;
            }
        });
    }

    if(type === "Mapping Coordinates List"){
        Object.defineProperty(ret, "uvs", {
            get: function(){
                var data = this.ownData;

                var cursor = 0;

                var uvsNumber = data.readUInt16LE(cursor);
                cursor += 2;

                var uvs = [];

                while(uvsNumber > 0){
                    uvs.push({
                        a: data.readFloatLE(cursor),
                        b: data.readFloatLE(cursor+4)
                    });

                    cursor += 8;
                    uvsNumber--;
                }

                return uvs;
            }
        });
    }

    return ret;
}

function Parsed3DSFile(buff){

    var typeValue = buff.readUInt16LE(0);
    var type = chunkUtils.getChunkName(typeValue);
    if(type !== "Main"){
        throw new Error('First chunk should be "Main". It is '+type+' (0x'+typeValue.toString(16)+')')
    }
    var length = buff.readUInt32LE(2);

    return {
        "Main": Chunk(buff.slice(6, length), type),

        toString: function(){
            return this["Main"].toString();
        },
        getObjects: function(){
            var editorChunk = this["Main"].children[1];
            if(editorChunk.type !== "3D Editor Chunk")
                throw new Error();

            return editorChunk.children.filter(function(c){
                return c.type === "Object Block"
            })

        }
    }
}

module.exports = function(filename, cb){
    fs.readFile(filename, function(err, buff){
        if(err){
            cb(err);
            return;
        }

        cb(null, new Parsed3DSFile(buff))
    });
};
<commit_msg>removed unecessary consol log<commit_after>"use strict";

var fs = require("fs");

/* Sources:
    http://en.wikipedia.org/wiki/.3ds
    http://www.spacesimulator.net/wiki/index.php?title=Tutorials:3ds_Loader
    http://www.the-labs.com/Blender/3dsspec.html
*/

var chunkUtils = (function(){

    var chunkIds = {
        "Main": 0x4d4d,
        "M3D Version": 0x0002,
        "3D Editor Chunk": 0x3D3D,
        "Object Block": 0x4000,
        "Triangular Mesh": 0x4100,
        "Vertices List": 0x4110,
        "Faces Description": 0x4120,
        "Faces Material": 0x4130,
        "Smoothing Group List": 0x4150,
        "Mapping Coordinates List": 0x4140,
        "Local Coordinates System": 0x4160,
        "Light": 0x4600,
        "Spotlight": 0x4610,
        "Camera": 0x4700,
        "Material Block": 0xAFFF
    };

    var children = {
        "Main" : [
            chunkIds["M3D Version"],
            chunkIds["3D Editor Chunk"]
        ],
        "3D Editor Chunk" : [
            chunkIds["Object Block"],
            chunkIds["Material Block"]
        ],
        "Object Block" : [
            chunkIds["Triangular Mesh"],
            chunkIds["Light"],
            chunkIds["Camera"]
        ],
        "Triangular Mesh" : [
            chunkIds["Vertices List"],
            chunkIds["Faces Description"],
            chunkIds["Mapping Coordinates List"],
            chunkIds["Local Coordinates System"]
        ],
        "Faces Description": [
            chunkIds["Faces Material"],
            chunkIds["Smoothing Group List"]
        ]
    };
    /*
    0x4D4D // Main Chunk
    ├─ 0x0002 // M3D Version
    ├─ 0x3D3D // 3D Editor Chunk
    │  ├─ 0x4000 // Object Block
    │  │  ├─ 0x4100 // Triangular Mesh
    │  │  │  ├─ 0x4110 // Vertices List
    │  │  │  ├─ 0x4120 // Faces Description
    │  │  │  │  ├─ 0x4130 // Faces Material
    │  │  │  │  └─ 0x4150 // Smoothing Group List
    │  │  │  ├─ 0x4140 // Mapping Coordinates List
    │  │  │  └─ 0x4160 // Local Coordinates System
    │  │  ├─ 0x4600 // Light
    │  │  │  └─ 0x4610 // Spotlight
    │  │  └─ 0x4700 // Camera
    │  └─ 0xAFFF // Material Block
    │     ├─ 0xA000 // Material Name
    │     ├─ 0xA010 // Ambient Color
    │     ├─ 0xA020 // Diffuse Color
    │     ├─ 0xA030 // Specular Color
    │     ├─ 0xA200 // Texture Map 1
    │     ├─ 0xA230 // Bump Map
    │     └─ 0xA220 // Reflection Map
    │        │  // Sub Chunks For Each Map
    │        ├─ 0xA300 // Mapping Filename
    │        └─ 0xA351 // Mapping Parameters
    └─ 0xB000 // Keyframer Chunk
       ├─ 0xB002 // Mesh Information Block
       ├─ 0xB007 // Spot Light Information Block
       └─ 0xB008 // Frames (Start and End)
          ├─ 0xB010 // Object Name
          ├─ 0xB013 // Object Pivot Point
          ├─ 0xB020 // Position Track
          ├─ 0xB021 // Rotation Track
          ├─ 0xB022 // Scale Track
          └─ 0xB030 // Hierarchy Position
    */

    var chunkNameById = {};
    Object.keys(chunkIds).forEach(function(name){
        var value = chunkIds[name];
        chunkNameById[value] = name;
    });

    return {
        getChunkName: function(id){
            return chunkNameById[id];
        },
        getPotentialChildrenIds: function(name){
            return children[name] || [];
        },
        getChunkId: function(name){
            return chunkIds[name];
        }
    }

})();

//console.log(chunkNameById);

// buff only contains the content (length and type have been stripped out)
function Chunk(buff, type){
    //if(type === "Vertices List")
    //  console.log('Creating Vertices List chunk', buff.length)

    var children = [];

    var childTypeValue, childType;
    var childLength;

    var childrenIds = chunkUtils.getPotentialChildrenIds(type);

    // search for own data
    var ownDataLength = 0;
    var cursor = 0;

    if(type === "Vertices List" || type === "Faces Description" || type === "Mapping Coordinates List"){
        if(type === "Vertices List"){
            var verticesNumber = buff.readUInt16LE(cursor);
            ownDataLength = 2 + (3*4)*verticesNumber;
        }
        if(type === "Faces Description"){
            var facesNumber = buff.readUInt16LE(cursor);
            ownDataLength = 2 + (3*2+2)*facesNumber;
        }
        if(type === "Mapping Coordinates List"){
            var uvsNumber = buff.readUInt16LE(cursor);
            ownDataLength = 2 + (2*4)*uvsNumber;
        }

        cursor = ownDataLength;
    }
    else{
        while(cursor < buff.length - 2){
            childTypeValue = buff.readUInt16LE(cursor);
            if(childrenIds.indexOf(childTypeValue) !== -1)
                break;
            cursor += 1;
        }

        ownDataLength = cursor < buff.length - 2 ? cursor : buff.length;
    }

    if(ownDataLength > buff.length)
        throw new RangeError();

    // look for children
    while(cursor < buff.length -2){
        childTypeValue = buff.readUInt16LE(cursor);
        // beginning of a child
        childType = chunkUtils.getChunkName(childTypeValue);
        childLength = buff.readUInt32LE(cursor+2);

        if(childrenIds.indexOf(childTypeValue) !== -1){
            //if(type === "Triangular Mesh")
            //  console.log(type, 'creating child chunk of length from',  cursor + 6, 'to', cursor + childLength)
            children.push(Chunk(buff.slice(cursor + 6, cursor + childLength), childType));
        }
        else{
            //console.warn('skipping', childTypeValue, childLength);
        }
        cursor += childLength;
    }

    var ret = {
        get type(){
            return type;
        },
        get ownData(){
            return buff.slice(0, ownDataLength);
        },
        children : children,

        toString: function(indent){
            indent = indent || 0;

            var spaces = '';
            for(var i = 0; i < indent ; i++)
                spaces += ' ';

            return spaces + this.type + ' ' + (ownDataLength) + ' ' + (buff.length) + '\n' +
                this.children.map(function(chunk){ return chunk.toString(indent+2); }).join('');
        }
    };

    // TODO make mixins for these and move this code away
    if(type === "Object Block"){
        Object.defineProperty(ret, "meshes", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Triangular Mesh";
                })[0]; // singleton
            }
        });
        Object.defineProperty(ret, "name", {
            get: function(){
                var ownData = this.ownData
                return ownData.toString('utf-8', 0, ownData.length -1);
            }
        });
    }
    if(type === "Triangular Mesh"){
        Object.defineProperty(ret, "vertices", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Vertices List";
                })[0].vertices; // singleton
            }
        });
        Object.defineProperty(ret, "faces", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Faces Description";
                })[0].faces; // singleton
            }
        });
        Object.defineProperty(ret, "uvs", {
            get: function(){
                return this.children.filter(function(c){
                    return c.type === "Mapping Coordinates List";
                })[0].uvs; // singleton
            }
        });
    }
    if(type === "Vertices List"){
        Object.defineProperty(ret, "vertices", {
            get: function(){
                var data = this.ownData;

                var cursor = 0;

                var verticesNumber = data.readUInt16LE(cursor);
                cursor += 2;

                //console.log(verticesNumber);
                var vertices = [];

                while(verticesNumber > 0){
                    vertices.push({
                        x: data.readFloatLE(cursor),
                        y: data.readFloatLE(cursor+4),
                        z: data.readFloatLE(cursor+8)
                    });

                    cursor += 12;
                    verticesNumber--;
                }

                return vertices;
            }
        });
    }

    if(type === "Faces Description"){
        Object.defineProperty(ret, "faces", {
            get: function(){
                var data = this.ownData;

                var cursor = 0;

                var facesNumber = data.readUInt16LE(cursor);
                cursor += 2;

                var faces = [];
                var flags;

                while(facesNumber > 0){
                    faces.push({
                        a: data.readUInt16LE(cursor),
                        b: data.readUInt16LE(cursor+2),
                        c: data.readUInt16LE(cursor+4)
                    });

                    // pasing flags, but not using them.
                    flags = data.readUInt16LE(cursor+6);

                    cursor += 8;
                    facesNumber--;
                }

                return faces;
            }
        });
    }

    if(type === "Mapping Coordinates List"){
        Object.defineProperty(ret, "uvs", {
            get: function(){
                var data = this.ownData;

                var cursor = 0;

                var uvsNumber = data.readUInt16LE(cursor);
                cursor += 2;

                var uvs = [];

                while(uvsNumber > 0){
                    uvs.push({
                        a: data.readFloatLE(cursor),
                        b: data.readFloatLE(cursor+4)
                    });

                    cursor += 8;
                    uvsNumber--;
                }

                return uvs;
            }
        });
    }

    return ret;
}

function Parsed3DSFile(buff){

    var typeValue = buff.readUInt16LE(0);
    var type = chunkUtils.getChunkName(typeValue);
    if(type !== "Main"){
        throw new Error('First chunk should be "Main". It is '+type+' (0x'+typeValue.toString(16)+')')
    }
    var length = buff.readUInt32LE(2);

    return {
        "Main": Chunk(buff.slice(6, length), type),

        toString: function(){
            return this["Main"].toString();
        },
        getObjects: function(){
            var editorChunk = this["Main"].children[1];
            if(editorChunk.type !== "3D Editor Chunk")
                throw new Error();

            return editorChunk.children.filter(function(c){
                return c.type === "Object Block"
            })

        }
    }
}

module.exports = function(filename, cb){
    fs.readFile(filename, function(err, buff){
        if(err){
            cb(err);
            return;
        }

        cb(null, new Parsed3DSFile(buff))
    });
};
<|endoftext|>


<commit_before>import { Promise } from 'bluebird'
import _ from 'lodash'
import readInstalled from './lib/readInstalled'
import writeInstalled from './lib/writeInstalled'
import handleError from '../lib/handleError'
import log from '../lib/log'
import cache from '../cache'
import opts from '../opts'
import { onStart, onFinish, onError } from './lib/messages'
import { save } from './lib/npm'
import normalize from './lib/normalize'
import remakeInstallDir from './lib/remakeInstallDir'
import { uninstall } from './uninstall'
import { bundleExternals } from './externals'
import { bundleInternals } from './internals'

const LOG = 'externals'

// ensures all packages installed, uninstalled, written out to bundle
export async function install(force) {
  log('bundler', 'install')
  try {
    await remakeInstallDir(force)
    await uninstall()
    await installAll()
    await bundleExternals()

    if (force) {
      await bundleInternals()
    }
  } catch(e) {
    handleError(e)
    throw new Error(e)
  }
}

let successful = []
let failed = []
let installingFullNames = []
let installing = []
let _isInstalling = false

export async function installAll(toInstall) {
  try {
    if (!toInstall)
      toInstall = cache.getImports()

    log(LOG, 'toInstall', toInstall)

    // full names keeps paths like 'babel/runtime/etc'
    if (toInstall.length)
      installingFullNames.push(toInstall)
    else {
      opts.set('hasRunInitialInstall', true)
      return
    }

    const _toInstall = normalize(toInstall)
    const prevInstalled = await readInstalled()
    const _prevInstalled = normalize(prevInstalled)
    const fresh = _.difference(_toInstall, _prevInstalled, installing)
    log(LOG, 'installAll', 'fresh = ', fresh, ' = ')
    log(LOG, '  =', _toInstall, '(toInstall) - ', _prevInstalled, '(prevInstalled) - ', installing, '(currently installing)')

    // no new ones found
    if (!fresh.length) {
      if (!_isInstalling) opts.set('hasRunInitialInstall', true)
      return
    }

    // push installing
    installing = installing.concat(fresh)

    // check if installed running
    if (_isInstalling) return
    _isInstalling = true

    const installNext = async () => {
      const dep = installing[0]
      onStart(dep)

      try {
        await save(dep)
        successful.push(dep)
        onFinish(dep)
      }
      catch(e) {
        console.error(`Error installing ${dep}`, e.message)
        failed.push(dep)
        log(LOG, 'package install failed', dep, e.message, e.stack)
        onError(dep, e)
      }
      finally {
        installing.shift() // remove
        next()
      }
    }

    function next() {
      if (installing.length)
        installNext()
      else
        done()
    }

    async function done() {
      const installedFullPaths = _.flattenDeep(_.compact(_.uniq(installingFullNames)))
      let final = [].concat(prevInstalled, installedFullPaths)

      // remove failed
      if (failed.length)
        final = final.filter(dep => failed.indexOf(dep) >= 0)

      logInstalled(successful)
      await writeInstalled(final)
      await bundleExternals()

      // reset
      installingFullNames = []
      failed = []
      _isInstalling = false
      opts.set('hasRunInitialInstall', true)
    }

    installNext()
  }
  catch(e) {
    handleError(e)
  }
}

function logInstalled(deps) {
  if (!deps.length) return
  console.log()
  console.log(`  Installed ${deps.length} packages`.bold)
  deps.forEach(dep => {
    console.log(`  ✓ ${dep}`.green)
  })
  console.log()
}

// check for install finish
export function finishedInstalling() {
  return new Promise(finishedInstallingLoop)
}

function isInstalling() {
  return _isInstalling
}

function finishedInstallingLoop(res) {
  if (!_isInstalling) res()
  else {
    setTimeout(() => finishedInstallingLoop(res), 100)
  }
}
<commit_msg>minor<commit_after>import { Promise } from 'bluebird'
import _ from 'lodash'
import readInstalled from './lib/readInstalled'
import writeInstalled from './lib/writeInstalled'
import handleError from '../lib/handleError'
import log from '../lib/log'
import cache from '../cache'
import opts from '../opts'
import { onStart, onFinish, onError } from './lib/messages'
import { save } from './lib/npm'
import normalize from './lib/normalize'
import remakeInstallDir from './lib/remakeInstallDir'
import { uninstall } from './uninstall'
import { bundleExternals } from './externals'
import { bundleInternals } from './internals'

const LOG = 'externals'

// ensures all packages installed, uninstalled, written out to bundle
export async function install(force) {
  log('bundler', 'install')
  try {
    await remakeInstallDir(force)
    await uninstall()
    await installAll()
    await bundleExternals()

    if (force)
      await bundleInternals()

  } catch(e) {
    handleError(e)
    throw new Error(e)
  }
}

let successful = []
let failed = []
let installingFullNames = []
let installing = []
let _isInstalling = false

export async function installAll(toInstall) {
  try {
    if (!toInstall)
      toInstall = cache.getImports()

    log(LOG, 'toInstall', toInstall)

    // full names keeps paths like 'babel/runtime/etc'
    if (toInstall.length)
      installingFullNames.push(toInstall)
    else {
      opts.set('hasRunInitialInstall', true)
      return
    }

    const _toInstall = normalize(toInstall)
    const prevInstalled = await readInstalled()
    const _prevInstalled = normalize(prevInstalled)
    const fresh = _.difference(_toInstall, _prevInstalled, installing)
    log(LOG, 'installAll', 'fresh = ', fresh, ' = ')
    log(LOG, '  =', _toInstall, '(toInstall) - ', _prevInstalled, '(prevInstalled) - ', installing, '(currently installing)')

    // no new ones found
    if (!fresh.length) {
      if (!_isInstalling) opts.set('hasRunInitialInstall', true)
      return
    }

    // push installing
    installing = installing.concat(fresh)

    // check if installed running
    if (_isInstalling) return
    _isInstalling = true

    const installNext = async () => {
      const dep = installing[0]
      onStart(dep)

      try {
        await save(dep)
        successful.push(dep)
        onFinish(dep)
      }
      catch(e) {
        console.error(`Error installing ${dep}`, e.message)
        failed.push(dep)
        log(LOG, 'package install failed', dep, e.message, e.stack)
        onError(dep, e)
      }
      finally {
        installing.shift() // remove
        next()
      }
    }

    function next() {
      if (installing.length)
        installNext()
      else
        done()
    }

    async function done() {
      const installedFullPaths = _.flattenDeep(_.compact(_.uniq(installingFullNames)))
      let final = [].concat(prevInstalled, installedFullPaths)

      // remove failed
      if (failed.length)
        final = final.filter(dep => failed.indexOf(dep) >= 0)

      logInstalled(successful)
      await writeInstalled(final)
      await bundleExternals()

      // reset
      installingFullNames = []
      failed = []
      _isInstalling = false
      opts.set('hasRunInitialInstall', true)
    }

    installNext()
  }
  catch(e) {
    handleError(e)
  }
}

function logInstalled(deps) {
  if (!deps.length) return
  console.log()
  console.log(`  Installed ${deps.length} packages`.bold)
  deps.forEach(dep => {
    console.log(`  ✓ ${dep}`.green)
  })
  console.log()
}

// check for install finish
export function finishedInstalling() {
  return new Promise(finishedInstallingLoop)
}

function isInstalling() {
  return _isInstalling
}

function finishedInstallingLoop(res) {
  if (!_isInstalling) res()
  else {
    setTimeout(() => finishedInstallingLoop(res), 100)
  }
}
<|endoftext|>


<commit_before>module.exports = function () {

   // we use the events and config from the prototype, because the
   // "watchContract"-event
   // may be triggered before the init-methode is called
   var events = this.events, shhConfig = this.config.modules.shh;
   events.on("watchContract", function (contract) {

      // get the wisper-object
      var web3       = contract.web3;
      var replyWatch = web3.shh.watch({ 'topic': [ web3.fromAscii(contract.config.adr) ] });
      replyWatch.arrived(function(m) {
         events.emit("message", { to: contract.config.adr, msg: web3.toAscii(m.payload[0]), from:web3.toAscii(m.payload[1])});
      });

   });
};
<commit_msg>simplefied<commit_after>module.exports = function () {

   // we use the events and config from the prototype, because the
   // "watchContract"-event
   // may be triggered before the init-methode is called
   var events = this.events;
   events.on("watchContract", function (contract) {

      // get the wisper-object
      var web3       = contract.web3;

      // watch for incoming messages
      web3.shh.watch({
         'topic': [ web3.fromAscii(contract.config.adr) ]
      }).arrived(function(m) {
         events.emit("message", { to: contract.config.adr, msg: web3.toAscii(m.payload[0]), from:web3.toAscii(m.payload[1])});
      });

   });
};
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const {resolve} = require('path')
const passport = require('passport')
const PrettyError = require('pretty-error')
const finalHandler = require('finalhandler')
// PrettyError docs: https://www.npmjs.com/package/pretty-error

// Bones has a symlink from node_modules/APP to the root of the app.
// That means that we can require paths relative to the app root by
// saying require('APP/whatever').
//
// This next line requires our root index.js:
const pkg = require('APP')

const app = express()

if (!pkg.isProduction && !pkg.isTesting) {
  // Logging middleware (dev only)
  app.use(require('volleyball'))
}

// Pretty error prints errors all pretty.
const prettyError = new PrettyError

// Skip events.js and http.js and similar core node files.
prettyError.skipNodeFiles()

// Skip all the trace lines about express' core and sub-modules.
prettyError.skipPackage('express')

module.exports = app
  // Session middleware - compared to express-session (which is what's used in the Auther workshop), cookie-session stores sessions in a cookie, rather than some other type of session store.
  // Cookie-session docs: https://www.npmjs.com/package/cookie-session
  .use(require('cookie-session')({
    name: 'session',
    keys: [process.env.SESSION_SECRET || 'an insecure secret key'],
  }))

  // Body parsing middleware
  .use(bodyParser.urlencoded({ extended: true }))
  .use(bodyParser.json())

  // Authentication middleware
  .use(passport.initialize())
  .use(passport.session())

  // Serve static files from ../public
  .use(express.static(resolve(__dirname, '..', 'public')))
  .use(express.static(resolve(__dirname, '..', 'bower_components')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/chai')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/mocha')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/bootstrap')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/ace-code-editor')))

  // Serve our api - ./api also requires in ../db, which syncs with our database
  .use('/api', require('./api'))

  // any requests with an extension (.js, .css, etc.) turn into 404
  .use((req, res, next) => {
    if (path.extname(req.path).length) {
      const err = new Error('Not found')
      err.status = 404
      next(err)
    } else {
      next()
    }
  })

  // Send index.html for anything else.
  .get('/*', (_, res) => res.sendFile(resolve(__dirname, '..', 'public', 'index.html')))

  // Error middleware interceptor, delegates to same handler Express uses.
  // https://github.com/expressjs/express/blob/master/lib/application.js#L162
  // https://github.com/pillarjs/finalhandler/blob/master/index.js#L172
  .use((err, req, res, next) => {
    console.error(prettyError.render(err))
    finalHandler(req, res)(err)
  })

if (module === require.main) {
  // Start listening only if we're the main module.
  //
  // https://nodejs.org/api/modules.html#modules_accessing_the_main_module
  const server = app.listen(
    pkg.port,
    () => {
      console.log(`--- Started HTTP Server for ${pkg.name} ---`)
      const { address, port } = server.address()
      const host = address === '::' ? 'localhost' : address
      const urlSafeHost = host.includes(':') ? `[${host}]` : host
      console.log(`Listening on http://${urlSafeHost}:${port}`)
    }
  )
}

// This check on line 64 is only starting the server if this file is being run directly by Node, and not required by another file.
// Bones does this for testing reasons. If we're running our app in development or production, we've run it directly from Node using 'npm start'.
// If we're testing, then we don't actually want to start the server; 'module === require.main' will luckily be false in that case, because we would be requiring in this file in our tests rather than running it directly.
<commit_msg>Update start.js<commit_after>'use strict'

const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const {resolve} = require('path')
const passport = require('passport')
const PrettyError = require('pretty-error')
const finalHandler = require('finalhandler')
// PrettyError docs: https://www.npmjs.com/package/pretty-error

// Bones has a symlink from node_modules/APP to the root of the app.
// That means that we can require paths relative to the app root by
// saying require('APP/whatever').
//
// This next line requires our root index.js:
const pkg = require('APP')

const app = express()

if (!pkg.isProduction && !pkg.isTesting) {
  // Logging middleware (dev only)
  app.use(require('volleyball'))
}

// Pretty error prints errors all pretty.
const prettyError = new PrettyError

// Skip events.js and http.js and similar core node files.
prettyError.skipNodeFiles()

// Skip all the trace lines about express' core and sub-modules.
prettyError.skipPackage('express')

module.exports = app
  // Session middleware - compared to express-session (which is what's used in the Auther workshop), cookie-session stores sessions in a cookie, rather than some other type of session store.
  // Cookie-session docs: https://www.npmjs.com/package/cookie-session
  .use(require('cookie-session')({
    name: 'session',
    keys: [process.env.SESSION_SECRET || 'an insecure secret key'],
  }))

  // Body parsing middleware
  .use(bodyParser.urlencoded({ extended: true }))
  .use(bodyParser.json())

  // Authentication middleware
  .use(passport.initialize())
  .use(passport.session())

  // Serve static files from ../public
  .use(express.static(resolve(__dirname, '..', 'public')))
  .use(express.static(resolve(__dirname, '..', 'bower_components')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/chai')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/mocha')))
  .use(express.static(resolve(__dirname, '..', 'node_modules/bootstrap')))

  // Serve our api - ./api also requires in ../db, which syncs with our database
  .use('/api', require('./api'))

  // any requests with an extension (.js, .css, etc.) turn into 404
  .use((req, res, next) => {
    if (path.extname(req.path).length) {
      const err = new Error('Not found')
      err.status = 404
      next(err)
    } else {
      next()
    }
  })

  // Send index.html for anything else.
  .get('/*', (_, res) => res.sendFile(resolve(__dirname, '..', 'public', 'index.html')))

  // Error middleware interceptor, delegates to same handler Express uses.
  // https://github.com/expressjs/express/blob/master/lib/application.js#L162
  // https://github.com/pillarjs/finalhandler/blob/master/index.js#L172
  .use((err, req, res, next) => {
    console.error(prettyError.render(err))
    finalHandler(req, res)(err)
  })

if (module === require.main) {
  // Start listening only if we're the main module.
  //
  // https://nodejs.org/api/modules.html#modules_accessing_the_main_module
  const server = app.listen(
    pkg.port,
    () => {
      console.log(`--- Started HTTP Server for ${pkg.name} ---`)
      const { address, port } = server.address()
      const host = address === '::' ? 'localhost' : address
      const urlSafeHost = host.includes(':') ? `[${host}]` : host
      console.log(`Listening on http://${urlSafeHost}:${port}`)
    }
  )
}

// This check on line 64 is only starting the server if this file is being run directly by Node, and not required by another file.
// Bones does this for testing reasons. If we're running our app in development or production, we've run it directly from Node using 'npm start'.
// If we're testing, then we don't actually want to start the server; 'module === require.main' will luckily be false in that case, because we would be requiring in this file in our tests rather than running it directly.
<|endoftext|>