<commit_before>const choo = require('choo');
const html = require('choo/html');
const util = require('./util');
const app = choo();

var localStorage = window.localStorage;
var socket;
var unread = 0;
var isBlurred = false;

app.model({
    state: {
        now: new Date(),
        users: [],
        messages: [],
        nick: localStorage.nick ? localStorage.nick : '',
        loggedIn: false,
        connected: false,
        showOptions: false,
        notify: localStorage.notify === 'true',
        dark: localStorage.dark === 'true',
        boss: localStorage.boss === 'true'
    },
    reducers: {
        setNick: (state, nick) => {
            localStorage.nick = nick;
            return {nick: nick};
        },
        setUsers: (state, users) => ({users: users}),
        addUser: (state, user) => ({users: [...state.users, user]}),
        deleteUser: (state, user) => ({users: state.users.filter(u => u.id !== user.id)}),
        setLoggedIn: (state, loggedIn) => ({loggedIn: loggedIn}),
        setConnected: (state, connected) => ({connected: connected}),
        setShowOptions: (state, showOptions) => ({showOptions: showOptions}),
        setNotify: (state, notify) => {
            if (notify) { Notification.requestPermission(); }
            localStorage.notify = notify;
            return {notify: notify};
        },
        setDark: (state, dark) => {
            localStorage.dark = dark;
            return {dark: dark};
        },
        setBoss: (state, boss) => {
            localStorage.boss = boss;
            return {boss: boss};
        },
        receiveMessage: (state, message) => {
            if (state.messages.some(m => m.time.getTime() === message.time.getTime()))
                return state;
            if (isBlurred) {
                unread++;
                document.title = `(${unread}) nekocafe`;
                if (state.notify) {
                    var n = new Notification('nekocafe', {tag: 'nekocafe', body: `<${message.nick}> ${message.message}`});
                }
            }
            return {messages: [...state.messages, message]};
        },
        setTime: (state, time) => ({now: time})
    },
    effects: {
        sendMessage: (state, data, send, done) => {
            socket.emit('message', data);
        },
        login: (state, data, send, done) => {
            send('setLoggedIn', true, done);
            socket = io();
            socket.on('connect', () => {
                socket.emit('nick', {nick: state.nick});
                send('setConnected', true, done);
            });
            socket.on('disconnect', () => {
                send('setConnected', false, done);
            });
            socket.on('message', (msg) => send(
                'receiveMessage',
                {
                    time: new Date(msg.time),
                    nick: msg.nick,
                    message: msg.message,
                    embeds: msg.embeds
                },
                done));
            socket.on('users', (users) => send('setUsers', users, done));
            socket.on('join', (user) => send('addUser', user, done));
            socket.on('part', (user) => send('deleteUser', user, done));
            socket.on('time', (time) => send('setTime', new Date(time), done));
        }
    },
    subscriptions: {
        blur: (send, done) => {
            window.addEventListener('blur', () => {
                unread = 0;
                isBlurred = true;
            }, false);
            window.addEventListener('focus', () => {
                document.title = 'nekocafe';
                isBlurred = false;
            }, false);
        }
    }
});

function scrollDown() {
    var body = document.body;
    var html = document.getElementsByTagName('html')[0];
    // other browsers
    body.scrollTop = body.scrollHeight;
    // firefox
    html.scrollTop = html.scrollHeight;
}

const messageTime = (now, time) => html`
    ${util.relTime(now, time)}
`;

const messageText = (message) => {
    const msgSpan = html`<span></span>`;
    msgSpan.innerHTML = util.hotLink(util.escapeHtml(message.message));
    return html`
        ${'<' + message.nick + '>'} ${msgSpan}
    `;
};

const embedRow = (embed) => {
    const inner = html`<div></div>`;
    switch (embed.type) {
        case 'html':
            inner.innerHTML = embed.html;
            break;
        case 'tweet':
            twttr.widgets.createTweet(embed.id, inner);
            break;
        default:
            inner.innerHTML = '[error loading embed]';
            break;
    }
    const elt = html`

                ${inner}

    `;
    elt.isSameNode = () => true;
    return elt;
};

const messageItem = (state, message, installOnload) => {
    const embeds = state.boss ? [] : message.embeds;
    if (installOnload)
        return html`

                    ${messageTime(state.now, message.time)}
                    ${messageText(message)}

                ${embeds.map(embedRow)}

        `;
    else
        return html`

                    ${messageTime(state.now, message.time)}
                    ${messageText(message)}

                ${embeds.map(embedRow)}

        `;
}

const messageList  = (state) => {
    const messages = state.messages;
    return html`

            ${messages.map((message, i) => messageItem(state, message, i+1 === messages.length))}

    `;
};

const spinner = (state) => {
    return html`<p class="navbar-text">Connecting...</div>`;
};

const loginWidget = (nick, oninput, login) => {
    return html`
        <form class="navbar-form login" onsubmit=${login}>

                <input class="form-control" type="text" name="nick" placeholder="Name"
                    oninput=${oninput} value=${nick} autofocus required />

            <button class="btn btn-primary" type="submit">Connect</button>
        </form>
    `;
}

const statusBar = (state, send) => {
    function login(e) {
        e.preventDefault();
        send('login');
    }

    function oninput(e) {
        send('setNick', e.target.value);
    }

    var status = html`<p class="navbar-text" href="">${state.users.map(u => u.nick).join(', ')}</a>`;

    return html`

                        ${!state.loggedIn ? loginWidget(state.nick, oninput, login) :
                            (state.connected ? status : spinner(state))}

                        <button class="btn btn-default navbar-btn navbar-right" type="button"
                            tabindex="-1" onclick=${() => send('setShowOptions', !state.showOptions)}>${state.showOptions? '😺' : '🐱'}</button>

    `;
};

const optionsWidget = (state, send) => {
    return html`
        <form class="options" onload=${scrollDown}>
            Online

${state.users.map(u => u.nick).join(', ')}

            Options

                    <input type="checkbox" ${state.notify ? 'checked': ''}
                        onchange=${e => send('setNotify', e.target.checked)} />
                    Notifications

                    <input type="checkbox" ${state.dark ? 'checked' : ''}
                        onchange=${e => send('setDark', e.target.checked)} />
                    Dark mode

                    <input type="checkbox" ${state.boss ? 'checked' : ''}
                        onchange=${e => send('setBoss', e.target.checked)} />
                    Boss mode

        </form>
    `;
};

function disableIf(exp) {
    return exp ? 'disabled' : '';
}

const messageBar = (state, send) => {
    function onSubmit(e) {
        e.preventDefault();
        send('sendMessage', e.target.children[0].children[0].value);
        e.target.reset();
    }
    return html`

                <form class="navbar-form messageWidget" onsubmit=${onSubmit}>

                        <input ${disableIf(!state.connected)} id="message" name="message"
                            class="form-control" placeholder="Enter message" autocomplete="off" />

                            <button ${disableIf(!state.connected)} class="btn btn-default" type="submit">Send</button>

                </form>

    `;
}

const mainView = (state, prev, send) => html`

        ${statusBar(state, send)}

            ${messageList(state)}
            ${state.showOptions ? optionsWidget(state, send) : ''}

        ${messageBar(state, send)}

`;

app.router(['/', mainView]);

//const tree = app.start('#root');
const tree = app.start();
document.body.appendChild(tree);<commit_msg>move createTweet to onload<commit_after>const choo = require('choo');
const html = require('choo/html');
const util = require('./util');
const app = choo();

var localStorage = window.localStorage;
var socket;
var unread = 0;
var isBlurred = false;

app.model({
    state: {
        now: new Date(),
        users: [],
        messages: [],
        nick: localStorage.nick ? localStorage.nick : '',
        loggedIn: false,
        connected: false,
        showOptions: false,
        notify: localStorage.notify === 'true',
        dark: localStorage.dark === 'true',
        boss: localStorage.boss === 'true'
    },
    reducers: {
        setNick: (state, nick) => {
            localStorage.nick = nick;
            return {nick: nick};
        },
        setUsers: (state, users) => ({users: users}),
        addUser: (state, user) => ({users: [...state.users, user]}),
        deleteUser: (state, user) => ({users: state.users.filter(u => u.id !== user.id)}),
        setLoggedIn: (state, loggedIn) => ({loggedIn: loggedIn}),
        setConnected: (state, connected) => ({connected: connected}),
        setShowOptions: (state, showOptions) => ({showOptions: showOptions}),
        setNotify: (state, notify) => {
            if (notify) { Notification.requestPermission(); }
            localStorage.notify = notify;
            return {notify: notify};
        },
        setDark: (state, dark) => {
            localStorage.dark = dark;
            return {dark: dark};
        },
        setBoss: (state, boss) => {
            localStorage.boss = boss;
            return {boss: boss};
        },
        receiveMessage: (state, message) => {
            if (state.messages.some(m => m.time.getTime() === message.time.getTime()))
                return state;
            if (isBlurred) {
                unread++;
                document.title = `(${unread}) nekocafe`;
                if (state.notify) {
                    var n = new Notification('nekocafe', {tag: 'nekocafe', body: `<${message.nick}> ${message.message}`});
                }
            }
            return {messages: [...state.messages, message]};
        },
        setTime: (state, time) => ({now: time})
    },
    effects: {
        sendMessage: (state, data, send, done) => {
            socket.emit('message', data);
        },
        login: (state, data, send, done) => {
            send('setLoggedIn', true, done);
            socket = io();
            socket.on('connect', () => {
                socket.emit('nick', {nick: state.nick});
                send('setConnected', true, done);
            });
            socket.on('disconnect', () => {
                send('setConnected', false, done);
            });
            socket.on('message', (msg) => send(
                'receiveMessage',
                {
                    time: new Date(msg.time),
                    nick: msg.nick,
                    message: msg.message,
                    embeds: msg.embeds
                },
                done));
            socket.on('users', (users) => send('setUsers', users, done));
            socket.on('join', (user) => send('addUser', user, done));
            socket.on('part', (user) => send('deleteUser', user, done));
            socket.on('time', (time) => send('setTime', new Date(time), done));
        }
    },
    subscriptions: {
        blur: (send, done) => {
            window.addEventListener('blur', () => {
                unread = 0;
                isBlurred = true;
            }, false);
            window.addEventListener('focus', () => {
                document.title = 'nekocafe';
                isBlurred = false;
            }, false);
        }
    }
});

function scrollDown() {
    var body = document.body;
    var html = document.getElementsByTagName('html')[0];
    // other browsers
    body.scrollTop = body.scrollHeight;
    // firefox
    html.scrollTop = html.scrollHeight;
}

const messageTime = (now, time) => html`
    ${util.relTime(now, time)}
`;

const messageText = (message) => {
    const msgSpan = html`<span></span>`;
    msgSpan.innerHTML = util.hotLink(util.escapeHtml(message.message));
    return html`
        ${'<' + message.nick + '>'} ${msgSpan}
    `;
};

const embedRow = (embed) => {
    const onload = () => {
        if (embed.type === 'tweet') {
            twttr.widgets.createTweet(embed.id, inner);
        }
    }
    const inner = html`<div onload=${onload}></div>`;
    switch (embed.type) {
        case 'html':
            inner.innerHTML = embed.html;
            break;
        case 'tweet':
            break;
        default:
            inner.innerHTML = '[error loading embed]';
            break;
    }
    const elt = html`

                ${inner}

    `;
    elt.isSameNode = () => true;
    return elt;
};

const messageItem = (state, message, installOnload) => {
    const embeds = state.boss ? [] : message.embeds;
    if (installOnload)
        return html`

                    ${messageTime(state.now, message.time)}
                    ${messageText(message)}

                ${embeds.map(embedRow)}

        `;
    else
        return html`

                    ${messageTime(state.now, message.time)}
                    ${messageText(message)}

                ${embeds.map(embedRow)}

        `;
}

const messageList  = (state) => {
    const messages = state.messages;
    return html`

            ${messages.map((message, i) => messageItem(state, message, i+1 === messages.length))}

    `;
};

const spinner = (state) => {
    return html`<p class="navbar-text">Connecting...</div>`;
};

const loginWidget = (nick, oninput, login) => {
    return html`
        <form class="navbar-form login" onsubmit=${login}>

                <input class="form-control" type="text" name="nick" placeholder="Name"
                    oninput=${oninput} value=${nick} autofocus required />

            <button class="btn btn-primary" type="submit">Connect</button>
        </form>
    `;
}

const statusBar = (state, send) => {
    function login(e) {
        e.preventDefault();
        send('login');
    }

    function oninput(e) {
        send('setNick', e.target.value);
    }

    var status = html`<p class="navbar-text" href="">${state.users.map(u => u.nick).join(', ')}</a>`;

    return html`

                        ${!state.loggedIn ? loginWidget(state.nick, oninput, login) :
                            (state.connected ? status : spinner(state))}

                        <button class="btn btn-default navbar-btn navbar-right" type="button"
                            tabindex="-1" onclick=${() => send('setShowOptions', !state.showOptions)}>${state.showOptions? '😺' : '🐱'}</button>

    `;
};

const optionsWidget = (state, send) => {
    return html`
        <form class="options" onload=${scrollDown}>
            Online

${state.users.map(u => u.nick).join(', ')}

            Options

                    <input type="checkbox" ${state.notify ? 'checked': ''}
                        onchange=${e => send('setNotify', e.target.checked)} />
                    Notifications

                    <input type="checkbox" ${state.dark ? 'checked' : ''}
                        onchange=${e => send('setDark', e.target.checked)} />
                    Dark mode

                    <input type="checkbox" ${state.boss ? 'checked' : ''}
                        onchange=${e => send('setBoss', e.target.checked)} />
                    Boss mode

        </form>
    `;
};

function disableIf(exp) {
    return exp ? 'disabled' : '';
}

const messageBar = (state, send) => {
    function onSubmit(e) {
        e.preventDefault();
        send('sendMessage', e.target.children[0].children[0].value);
        e.target.reset();
    }
    return html`

                <form class="navbar-form messageWidget" onsubmit=${onSubmit}>

                        <input ${disableIf(!state.connected)} id="message" name="message"
                            class="form-control" placeholder="Enter message" autocomplete="off" />

                            <button ${disableIf(!state.connected)} class="btn btn-default" type="submit">Send</button>

                </form>

    `;
}

const mainView = (state, prev, send) => html`

        ${statusBar(state, send)}

            ${messageList(state)}
            ${state.showOptions ? optionsWidget(state, send) : ''}

        ${messageBar(state, send)}

`;

app.router(['/', mainView]);

//const tree = app.start('#root');
const tree = app.start();
document.body.appendChild(tree);<|endoftext|>


<commit_before>'use strict'

const async = require('async')
const fs = require('fs')
const os = require('os')
const path = require('path')
const spawn = require('child_process').spawn
const downloader = require('./downloader')
let tunnelLocation
let activeTunnel
let started = false

function logger (msg) {
    console.log.apply(console, arguments)
}

function download (options, callback) {
    tunnelLocation = path.normalize(path.join(__dirname, '../testingbot-tunnel.jar'))

    let url = 'https://testingbot.com/tunnel/testingbot-tunnel.jar'

    if (options.tunnelVersion) {
        tunnelLocation = path.normalize(path.join(__dirname, `../testingbot-tunnel-${options.tunnelVersion}.jar`))
        url = `https://testingbot.com/tunnel/testingbot-tunnel-${options.tunnelVersion}.jar`
    }

    if (fs.existsSync(tunnelLocation)) {
        return callback(null)
    }

    downloader.get(url, { fileName: 'testingbot-tunnel', destination: tunnelLocation }, (err, destination) => {
        if (err) {
            return callback(new Error(`Could not download the tunnel from TestingBot - please check your connection. ${err.message}`))
        }

        return callback(null)
    })
}

function run (options, callback) {
    if (!fs.existsSync(tunnelLocation)) {
        return callback(new Error(`Tunnel jar file is not present in ${tunnelLocation}`))
    }

    const onReady = function () {
        started = true
        logger('Tunnel is ready')
        callback(null, activeTunnel)
    }

    const args = []

    args.push('-jar')
    args.push(tunnelLocation)

    if (options.apiKey) {
        args.push(options.apiKey)
    }

    if (options.apiSecret) {
        args.push(options.apiSecret)
    }

    for (const option in options) {
        if ((option === 'apiKey') || (option === 'apiSecret') || (option === 'verbose') || (option === 'tunnelVersion')) {
            continue
        }

        if (options[option]) {
            args.push(`--${option}`)
            args.push(options[option])
        } else {
            args.push(`--${option}`)
        }
    }

    const readyFile = path.join(os.tmpdir(), 'testingbot.ready')
    try {
        if (fs.statSync(readyFile).isFile()) {
            logger('Tunnel Readyfile already exists, removing')
            fs.unlinkSync(readyFile)
        }
    } catch (ignore) {}

    args.push(`-f ${readyFile}`)

    const readyFileChecker = setInterval(() => {
        fs.stat(readyFile, (error, stat) => {
            if (!error) {
                clearInterval(readyFileChecker)
                onReady()
            }
        })
    }, 800)

    if (options.verbose) {
        logger('Starting tunnel with options', args)
    }
    activeTunnel = spawn('java', args, {
        detached: true
    })

    activeTunnel.unref()

    activeTunnel.stderr.on('data', data => {
        data = data.toString().trim()
        if (options.verbose && data !== '') {
            logger(data)
        }
        if (data.indexOf('is available for download') > -1 || data.indexOf('An error ocurred') > -1) {
            logger(data)
        } else if (data.indexOf('error code : 401') > -1) {
            logger('Invalid credentials, please specify the correct KEY and SECRET retrieved from https://testingbot.com')
        }
    })

    activeTunnel.stdout.on('data', data => {
        data = data.toString().trim()
        if (options.verbose && data !== '') {
            logger(data)
        }
    })

    activeTunnel.close = closeCallback => {
        if (closeCallback) {
            activeTunnel.on('close', () => {
                closeCallback()
            })
        }
        activeTunnel.kill('SIGINT')
    }

    activeTunnel.on('exit', (code, signal) => {
        logger('Closing TestingBot Tunnel')
        if (!started) {
            callback(new Error(`Could not start TestingBot Tunnel. Exit code ${code} signal: ${signal}`))
        }

        started = false
        activeTunnel = null
    })
}

function killTunnel (callback) {
    if (!callback) {
        callback = function () {}
    }

    if (!activeTunnel) {
        return callback(new Error('no active tunnel'))
    }

    activeTunnel.kill('SIGINT')
}

function downloadAndRun (options, callback) {
    if (!options) {
        options = {}
    }

    if (!callback) {
        callback = function () {}
    }

    async.waterfall([
        async.apply(download, options),
        async.apply(run, options)
    ], callback)
}

function exitHandler (options, err) {
    if (!activeTunnel) {
        return
    }

    if (err) {
        logger(err.stack)
    }

    if (options.cleanup) {
        logger('Shutting down tunnel')
        killTunnel()
    }

    if (options.exit) {
        process.exit()
    }
}

process.on('exit', exitHandler.bind(null, {cleanup: true}))
process.on('SIGINT', exitHandler.bind(null, {exit: true}))
process.on('uncaughtException', exitHandler.bind(null, {exit: true}))

module.exports = downloadAndRun
module.exports.kill = killTunnel
<commit_msg>detect and handle corrupt downloaded tunnel jar file<commit_after>'use strict'

const async = require('async')
const fs = require('fs')
const os = require('os')
const path = require('path')
const spawn = require('child_process').spawn
const downloader = require('./downloader')
let tunnelLocation
let activeTunnel
let started = false

function logger (msg) {
    console.log.apply(console, arguments)
}

function download (options, callback) {
    tunnelLocation = path.normalize(path.join(__dirname, '../testingbot-tunnel.jar'))

    let url = 'https://testingbot.com/tunnel/testingbot-tunnel.jar'

    if (options.tunnelVersion) {
        tunnelLocation = path.normalize(path.join(__dirname, `../testingbot-tunnel-${options.tunnelVersion}.jar`))
        url = `https://testingbot.com/tunnel/testingbot-tunnel-${options.tunnelVersion}.jar`
    }

    try {
        const tunnelFile = fs.statSync(tunnelLocation);
        if (tunnelFile['size'] > 1024) {
            return callback(null);
        }
    } catch (ignore) {}

    downloader.get(url, { fileName: 'testingbot-tunnel', destination: tunnelLocation }, (err, destination) => {
        if (err) {
            return callback(new Error(`Could not download the tunnel from TestingBot - please check your connection. ${err.message}`))
        }

        return callback(null)
    })
}

function run (options, callback) {
    if (!fs.existsSync(tunnelLocation)) {
        return callback(new Error(`Tunnel jar file is not present in ${tunnelLocation}`))
    }

    const onReady = function () {
        started = true
        logger('Tunnel is ready')
        callback(null, activeTunnel)
    }

    const args = []

    args.push('-jar')
    args.push(tunnelLocation)

    if (options.apiKey) {
        args.push(options.apiKey)
    }

    if (options.apiSecret) {
        args.push(options.apiSecret)
    }

    for (const option in options) {
        if ((option === 'apiKey') || (option === 'apiSecret') || (option === 'verbose') || (option === 'tunnelVersion')) {
            continue
        }

        if (options[option]) {
            args.push(`--${option}`)
            args.push(options[option])
        } else {
            args.push(`--${option}`)
        }
    }

    const readyFile = path.join(os.tmpdir(), 'testingbot.ready')
    try {
        if (fs.statSync(readyFile).isFile()) {
            logger('Tunnel Readyfile already exists, removing')
            fs.unlinkSync(readyFile)
        }
    } catch (ignore) {}

    args.push(`-f`)
    args.push(`${readyFile}`)

    const readyFileChecker = setInterval(() => {
        fs.stat(readyFile, (error, stat) => {
            if (!error) {
                clearInterval(readyFileChecker)
                onReady()
            }
        })
    }, 800)

    if (options.verbose) {
        logger('Starting tunnel with options', args)
    }
    activeTunnel = spawn('java', args, {
        detached: true
    })

    activeTunnel.unref()

    activeTunnel.stderr.on('data', data => {
        data = data.toString().trim()
        if (options.verbose && data !== '') {
            logger(data)
        }
        if (data.indexOf('is available for download') > -1 || data.indexOf('An error ocurred') > -1) {
            logger(data)
        } else if (data.toLowerCase().indexOf('error') > -1) {
            logger('Invalid credentials, please specify the correct KEY and SECRET retrieved from https://testingbot.com')
            logger(data)
        }
    })

    activeTunnel.stdout.on('data', data => {
        data = data.toString().trim()
        if (options.verbose && data !== '') {
            logger(data)
        }
    })

    activeTunnel.close = closeCallback => {
        if (closeCallback) {
            activeTunnel.on('close', () => {
                closeCallback()
            })
        }
        activeTunnel.kill('SIGINT')
    }

    activeTunnel.on('exit', (code, signal) => {
        logger('Closing TestingBot Tunnel')
        if (!started) {
            callback(new Error(`Could not start TestingBot Tunnel. Exit code ${code} signal: ${signal}`))
        }

        started = false
        activeTunnel = null
    })
}

function killTunnel (callback) {
    if (!callback) {
        callback = function () {}
    }

    if (!activeTunnel) {
        return callback(new Error('no active tunnel'))
    }

    activeTunnel.kill('SIGINT')
}

function downloadAndRun (options, callback) {
    if (!options) {
        options = {}
    }

    if (!callback) {
        callback = function () {}
    }

    async.waterfall([
        async.apply(download, options),
        async.apply(run, options)
    ], callback)
}

function exitHandler (options, err) {
    if (!activeTunnel) {
        return
    }

    if (err) {
        logger(err.stack)
    }

    if (options.cleanup) {
        logger('Shutting down tunnel')
        killTunnel()
    }

    if (options.exit) {
        process.exit()
    }
}

process.on('exit', exitHandler.bind(null, {cleanup: true}))
process.on('SIGINT', exitHandler.bind(null, {exit: true}))
process.on('uncaughtException', exitHandler.bind(null, {exit: true}))

module.exports = downloadAndRun
module.exports.kill = killTunnel
<|endoftext|>


<commit_before>var http          = require('http')
  , https         = require('https')
  , xmlrpcBuilder = require('./xmlrpc-builder.js')
  , xmlrpcParser  = require('./xmlrpc-parser.js')

/**
 * Creates a Client object for making XML-RPC method calls.
 *
 * @constructor
 * @param {Object} options - server options to make the HTTP request to
 *   - {String} host
 *   - {Number} port
 * @param {Boolean} isSecure - true if using https for making calls, otherwise
 *   false
 * @return {Client}
 */
function Client(options, isSecure) {

  // Invokes with new if called without
  if (false === (this instanceof Client)) {
    return new Client(options, isSecure)
  }

  // Set the HTTP request headers
  var headers = {
    'User-Agent'     : 'NodeJS XML-RPC Client'
  , 'Content-Type'   : 'text/xml'
  , 'Accept'         : 'text/xml'
  , 'Accept-Charset' : 'UTF8'
  }
  options.headers = options.headers || {}

  if (options.headers.Authorization == null &&
      options.basic_auth != null &&
      options.basic_auth.user != null &&
      options.basic_auth.pass != null) {
    options.headers['Authorization'] = 'Basic ' + new Buffer(options.basic_auth.user + ":" + options.basic_auth.pass).toString('base64')
  }

  for (attribute in headers) {
    if (options.headers[attribute] === undefined) {
      options.headers[attribute] = headers[attribute]
    }
  }

  options.method = 'POST'
  this.options = options

  this.isSecure = (isSecure === true) ? true : false
}

/**
 * Makes an XML-RPC call to the server specified by the constructor's options.
 *
 * @param {String} method - the method name
 * @param {Array} params - params to send in the call
 * @param {Function} callback - function(error, value)
 *   - {Object|null} error - any errors when making the call, otherwise null
 *   - {mixed} value - the value returned in the method response
 */
Client.prototype.methodCall = function(method, params, callback) {
  var that = this

  // Creates the XML to send
  xmlrpcBuilder.buildMethodCall(method, params, function(error, xml) {

    that.options.headers['Content-Length'] = xml.length

    // Uses HTTPS to send request if specified
    var httpRequester = (that.isSecure) ? https : http

    // POSTs the XML to the server
    var request = httpRequester.request(that.options, function(result) {
      // Parses the method response and returns the value
      result.setEncoding('utf8')

      // Must keep track of existing response parser to properly handle multiple
      // data events. If null is passed in, it will create a new parser.
      var saxParser = null
      result.on('data', function(chunk) {
        saxParser = xmlrpcParser.parseMethodResponse(saxParser, chunk, callback)
      })
      result.on('error', function(error) {
        callback(error, null)
      })
    })

    request.on('error', function(error) {
      callback(error, null)
    })

    request.write(xml, 'utf8')
    request.end()
  })

}

/**
 * @deprecated - Use methodCall() instead as call() already belongs to the
 * Function prototype and has a different purpose.
 */
Client.prototype.call = function(method, params, callback) {
  console.error('Client.call() has been deprecated. Please use Client.methodCall()')
}

module.exports = Client

<commit_msg>Removes the deprecated call method on client.<commit_after>var http          = require('http')
  , https         = require('https')
  , xmlrpcBuilder = require('./xmlrpc-builder.js')
  , xmlrpcParser  = require('./xmlrpc-parser.js')

/**
 * Creates a Client object for making XML-RPC method calls.
 *
 * @constructor
 * @param {Object} options - server options to make the HTTP request to
 *   - {String} host
 *   - {Number} port
 * @param {Boolean} isSecure - true if using https for making calls, otherwise
 *   false
 * @return {Client}
 */
function Client(options, isSecure) {

  // Invokes with new if called without
  if (false === (this instanceof Client)) {
    return new Client(options, isSecure)
  }

  // Set the HTTP request headers
  var headers = {
    'User-Agent'     : 'NodeJS XML-RPC Client'
  , 'Content-Type'   : 'text/xml'
  , 'Accept'         : 'text/xml'
  , 'Accept-Charset' : 'UTF8'
  }
  options.headers = options.headers || {}

  if (options.headers.Authorization == null &&
      options.basic_auth != null &&
      options.basic_auth.user != null &&
      options.basic_auth.pass != null) {
    options.headers['Authorization'] = 'Basic ' + new Buffer(options.basic_auth.user + ":" + options.basic_auth.pass).toString('base64')
  }

  for (attribute in headers) {
    if (options.headers[attribute] === undefined) {
      options.headers[attribute] = headers[attribute]
    }
  }

  options.method = 'POST'
  this.options = options

  this.isSecure = (isSecure === true) ? true : false
}

/**
 * Makes an XML-RPC call to the server specified by the constructor's options.
 *
 * @param {String} method - the method name
 * @param {Array} params - params to send in the call
 * @param {Function} callback - function(error, value)
 *   - {Object|null} error - any errors when making the call, otherwise null
 *   - {mixed} value - the value returned in the method response
 */
Client.prototype.methodCall = function(method, params, callback) {
  var that = this

  // Creates the XML to send
  xmlrpcBuilder.buildMethodCall(method, params, function(error, xml) {

    that.options.headers['Content-Length'] = xml.length

    // Uses HTTPS to send request if specified
    var httpRequester = (that.isSecure) ? https : http

    // POSTs the XML to the server
    var request = httpRequester.request(that.options, function(result) {
      // Parses the method response and returns the value
      result.setEncoding('utf8')

      // Must keep track of existing response parser to properly handle multiple
      // data events. If null is passed in, it will create a new parser.
      var saxParser = null
      result.on('data', function(chunk) {
        saxParser = xmlrpcParser.parseMethodResponse(saxParser, chunk, callback)
      })
      result.on('error', function(error) {
        callback(error, null)
      })
    })

    request.on('error', function(error) {
      callback(error, null)
    })

    request.write(xml, 'utf8')
    request.end()
  })

}

module.exports = Client

<|endoftext|>


<commit_before>(function () {
    'use strict';

    var Level2State = function() {
    };

    Level2State.prototype.preload = function() {
        // Para carregar um sprite, basta informar uma chave e dizer qual é o arquivo
        this.game.load.image('mapTiles', 'Assets/spritesheets/tiles.png');

        // Para carregar um spritesheet, é necessário saber a altura e largura de cada sprite, e o número de sprites no arquivo
        // No caso do player.png, os sprites são de 32x32 pixels, e há 8 sprites no arquivo
        this.game.load.spritesheet('player', 'Assets/spritesheets/player.png', 32, 32, 8);
        this.game.load.spritesheet('items', 'Assets/spritesheets/items.png', 32, 32, 16);
        this.game.load.spritesheet('enemies', 'Assets/spritesheets/enemies.png', 32, 32, 12);

        // Para carregar um arquivo do Tiled, o mesmo precisa estar no formato JSON
        this.game.load.tilemap('level2', 'assets/maps/level2.json', null, Phaser.Tilemap.TILED_JSON);

        // Para carregar os sons, basta informar a chave e dizer qual é o arquivo
        this.game.load.audio('jumpSound', 'Assets/sounds/jump.wav');
        this.game.load.audio('pickupSound', 'Assets/sounds/pickup.wav');
        this.game.load.audio('playerDeath', 'Assets/sounds/hurt3.ogg');
        this.game.load.audio('enemyDeath', 'Assets/sounds/hit2.ogg');
        this.game.load.audio('music', 'Assets/sounds/mystery.wav');
    }

    Level2State.prototype.create = function() {

        // Inicializando sistema de física
        // o sistema Arcade é o mais simples de todos, mas também é o mais eficiente em termos de processamento.
        // https://photonstorm.github.io/phaser-ce/Phaser.Physics.Arcade.html
        this.game.physics.startSystem(Phaser.Physics.ARCADE);

        // Para carregar o mapa do Tiled para o Phaser, 3 estágios são necessários:
        // 1 - Criar um objeto com o arquivo do Tiled carregado no preload()
        this.level2 = this.game.add.tilemap('level2');
        // 2 - Adicionar as imagens correspondentes aos tilesets do Tiled dentro do Phaser
        // "tiles" é o nome do tileset dentro do Tiled
        // "mapTiles" é o nome da imagem com os tiles, carregada no preload()
        this.level2.addTilesetImage('tiles', 'mapTiles');

        // 3 - Criar os layers do mapa
        // A ordem nesse caso é importante, então os layers que ficarão no "fundo" deverão ser
        // criados primeiro, e os que ficarão na "frente" por último;
        this.bgLayer = this.level2.createLayer('Floor');
        //this.lavaLayer = this.level1.createLayer('Lava');
        this.wallsLayer = this.level2.createLayer('BG');
        // Mais informações sobre tilemaps:
        // https://photonstorm.github.io/phaser-ce/#toc14

        // Redimensionando o tamanho do "mundo" do jogo
        this.wallsLayer.resizeWorld();

        // Para que possamos detectar colisões dos objetos com os layers do mapa, primeiro precisamos
        // informar quais tiles deverão efetivamente ter um colisor, para cada layer.
        // Esta contagem é feita olhando o tileset no Tiled, sendo que o tile mais à esquerda da
        // primeira linha do tileset terá valor 1, o próximo na linha valor 2, e assim por diante,
        // continuando a contagem na próxima linha, até o último tile da última linha.

        // Neste caso, ao invés de dizermos quais tiles devem colidir, estamos dizendo quais tiles não
        // devem colidir, pois há mais tiles que colidem do que tiles sem colisão.
        // Os parâmetros são a lista dos tiles, "true" indicando que a colisão deve ser ativada,
        // e o nome do layer.
        this.level2.setCollisionByExclusion([9, 10, 11, 12, 17, 18, 19, 20], true, this.wallsLayer);

        // Para o layer de lava é o caso oposto: poucos tiles colidem, então é mais fácil
        // informar diretamente quais são.
        //this.level1.setCollision([5, 6, 13], true, this.lavaLayer);

        // Inicializando jogador
        // Adicionando o sprite do jogador na posição (160, 64) usando o asset 'player'
        // Como estamos usando um spritesheet, é necessário informar qual sprite vamos usar
        // A contagem é da mesma forma do que nos tiles do mapa, mas o primeiro sprite recebe
        // o número 0 ao invés de 1.
        this.player = this.game.add.sprite(160, 64, 'player', 5);
        // Ajustando âncora do jogador (ponto de referência para posicionamento)
        this.player.anchor.setTo(0.5, 0.5);
        // Ativando física para o jogador
        this.game.physics.enable(this.player);
        // Ativando gravidade para o jogador
        // Como é positiva no eixo Y, o jogador terá uma gravidade "normal",
        // ou seja, irá acelerar para baixo
        this.player.body.gravity.y = 750;
        // Como o "mundo" é maior do que a área visível, é necessário que a câmera siga o jogador.
        // https://photonstorm.github.io/phaser-ce/Phaser.Camera.html#follow
        this.game.camera.follow(this.player);

        // Animações do jogador
        // Animações, no contexto do Phaser, nada mais são do que sequências de frames do spritesheet
        // Para criar uma animação, utilizamos animations.add()
        // Parâmetros: nome da animação, lista de quadros, quadros por segundo da animação
        // https://photonstorm.github.io/phaser-ce/Phaser.AnimationManager.html
        this.player.animations.add('walk', [0, 1, 2, 1], 6);
        this.player.animations.add('idle', [5, 5, 5, 5, 5, 5, 6, 5, 6, 5], 6);
        this.player.animations.add('jump', [4], 6);

        // Adicionando entradas
        // createCursorKeys() cria automaticamente mapeamentos para as 4 teclas de direção
        // https://photonstorm.github.io/phaser-ce/Phaser.Keyboard.html#createCursorKeys
        // Lista de teclas disponíveis: https://photonstorm.github.io/phaser-ce/Phaser.KeyCode.html
        this.keys = this.game.input.keyboard.createCursorKeys();
        this.jumpButton = this.game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

        // Adicionando objetos do Tiled, utilizando grupos
        // Um grupo é como se fosse um array de sprites, mas com várias facilidades adicionais,
        // como por exemplo alterar atributos e facilitar detectar colisões com objetos do grupo
        // Especificamente, estamos criando physicsGroups, que já armazenam objetos com física ativada
        // https://photonstorm.github.io/phaser-ce/Phaser.GameObjectFactory.html#physicsGroup

        // Criando objetos que foram criados em um layer de objetos do Tiled
        // Parâmetros do createFromObjects():
        // nome do layer do Tiled de onde vamos criar os objetos
        // nome dos objetos do Tiled que serão criados
        // nome do spritesheet carregado no preload() com os objetos
        // frame do spritesheet, basta setar para um dos frames do objeto em questão
        // true, false - estes dois parâmetros podem ficar com estes valores
        // grupo - qual grupo do Phaser devemos adicionar esses objetos

        // Grupo de diamantes
        this.diamonds = this.game.add.physicsGroup();
        this.level2.createFromObjects('Items', 'diamond', 'items', 5, true, false, this.diamonds);
        // Para cada objeto do grupo, vamos executar uma função
        this.diamonds.forEach(function(diamond){
            // body.immovable = true indica que o objeto não é afetado por forças externas
            diamond.body.immovable = true;
            // Adicionando animações; o parâmetro true indica que a animação é em loop
            diamond.animations.add('spin', [4, 5, 6, 7, 6, 5], 6, true);
            diamond.animations.play('spin');
        });

        this.bats = this.game.add.physicsGroup();
        this.level2.createFromObjects('Enemies', 'bat', 'enemies', 8, true, false, this.bats);
        this.bats.forEach(function(bat){
            bat.anchor.setTo(0.5, 0.5);
            bat.body.immovable = true;
            bat.animations.add('fly', [8, 9, 10], 6, true);
            bat.animations.play('fly');
            // Velocidade inicial do inimigo
            bat.body.velocity.x = 100;
            // bounce.x=1 indica que, se o objeto tocar num objeto no eixo x, a força deverá
            // ficar no sentido contrário; em outras palavras, o objeto é perfeitamente elástico
            bat.body.bounce.x = 1;
        });

        // Criando assets de som com this.game.add.audio()
        // O parâmetro é o nome do asset definido no preload()
        this.jumpSound = this.game.add.audio('jumpSound');
        this.pickupSound = this.game.add.audio('pickupSound');
        this.playerDeathSound = this.game.add.audio('playerDeath');
        this.enemyDeathSound = this.game.add.audio('enemyDeath');

        // Música de fundo - criada da mesma forma, mas com o parâmetro loop = true
        this.music = this.game.add.audio('music');
        this.music.loop = true;
        // Já iniciamos a música aqui mesmo pra ficar tocando ao fundo
        this.music.play();

        // HUD de score
        // A linha abaixo adiciona um texto na tela, e a próxima faz com o que o texto fique
        // fixo na câmera, dessa forma não vai se deslocar quando a câmera mudar
        this.scoreText = this.game.add.text(500, 50, "Score: 0",
                                {font: "25px Arial", fill: "#ffffff"});
        this.scoreText.fixedToCamera = true;

        // Estado do jogo - Variáveis para guardar quaisquer informações pertinentes para as condições de
        // vitória/derrota, ações do jogador, etc
        this.totalDiamonds = this.diamonds.length;
        this.collectedDiamonds = 0;
        this.score = 0;

    }

    Level2State.prototype.update = function() {
        // Detecção de colisões
        // Todas as colisões entre os objetos do jogo são avaliadas com arcade.collide() ou
        // arcade.overlap(). O Phaser irá automaticamente calcular a colisão dos objetos
        // Inicialmente, adicionando colisões do player com as paredes da fase, que é um layer:
        this.game.physics.arcade.collide(this.player, this.wallsLayer);

        // Colisão com os morcegos - depende de como foi a colisão, veremos abaixo
        this.game.physics.arcade.overlap(this.player, this.bats, this.batCollision, null, this);

        // Adicionando colisão entre os morcegos e as paredes
        this.game.physics.arcade.collide(this.bats, this.wallsLayer);

        // Movimentação do player
        // Para detectar se uma das teclas referenciadas foi pressionada,
        // basta verificar a variável .isDown da mesma
        // Caso seja a tecla para a esquerda, ajustar uma velocidade negativa
        // ao eixo X, que fará a posição X diminuir e consequentemente o jogador
        // ir para a esquerda;
        if(this.keys.left.isDown){
            this.player.body.velocity.x = -150; // Ajustar velocidade
            // Se o jogador estiver virado para a direita, inverter a escala para que ele vire para o outro lado
            if(this.player.scale.x == 1) this.player.scale.x = -1;
            // Iniciando a animação 'walk'
            this.player.animations.play('walk');
        }
        // Se a tecla direita estiver pressionada (this.keys.right.isDown == true),
        // mover o sprite para a direita
        else if(this.keys.right.isDown){
            // se a tecla direita estiver pressionada
            this.player.body.velocity.x = 150;  // Ajustar velocidade
            // Se o jogador estiver virado para a direita, inverter a escala para que ele vire para o outro lado
            if(this.player.scale.x == -1) this.player.scale.x = 1;
            this.player.animations.play('walk');
        }
        else {
            // Ajustar velocidade para zero
            this.player.body.velocity.x = 0;
            this.player.animations.play('idle');
        }

        // Se o a barra de espaço ou a tecla cima estiverem pressionadas, e o jogador estiver com a parte de baixo tocando em alguma coisa
        if((this.jumpButton.isDown || this.keys.up.isDown) && (this.player.body.touching.down || this.player.body.onFloor())){
            // Adicione uma velocidade no eixo Y, fazendo o jogador pular
            this.player.body.velocity.y = -400;
            // Tocando o som de pulo
            this.jumpSound.play();
        }

        // Se o jogador não estiver no chão, inicie a animação 'jump'
        if(!this.player.body.touching.down && !this.player.body.onFloor()){
            this.player.animations.play('jump');
        }

        // Para cada morcego, verificar em que sentido ele está indo
        // Se a velocidade for positiva, a escala no eixo X será 1, caso
        // contrário -1
        this.bats.forEach(function(bat){
           if(bat.body.velocity.x != 0) {
               // Math.sign apenas retorna o sinal do parâmetro: positivo retorna 1, negativo -1
               bat.scale.x = 1 * Math.sign(bat.body.velocity.x);
           }
        });

    }

    // Tratamento da colisão entre o jogador e os diamantes
    Level2State.prototype.batCollision = function(player, bat){
        // Se o jogador colidir por baixo e o morcego por cima, isso indica que o jogador pulou
        // em cima do morcego, nesse caso vamos "matar" o morcego
        if(player.body.touching.down && bat.body.touching.up){
            this.enemyDeathSound.play(); // tocando som de morte do morcego
            this.player.body.velocity.y = -200; // adicionando um pequeno impulso vertical ao jogador
            this.score += 100; // atualizando score
            this.scoreText.text = "Score: " + this.score;
            bat.kill();
        }
        else this.lose(); // caso contrário, ir para condição de derrota
    }

    // Condição de derrota: guarde o score e siga para o próximo estado
    Level2State.prototype.gameover = function(){
        alert("game over");
    }

    gameManager.addState('level2', Level2State);

})();<commit_msg>Adicionado o player na fase 2<commit_after>(function () {
    'use strict';

    var Level2State = function() {
         this.player = gameManager.getSprite('player');
    };

    Level2State.prototype.preload = function() {
        // Para carregar um sprite, basta informar uma chave e dizer qual é o arquivo
        this.game.load.image('mapTiles', 'Assets/spritesheets/tiles.png');

        // Para carregar um spritesheet, é necessário saber a altura e largura de cada sprite, e o número de sprites no arquivo
        // No caso do player.png, os sprites são de 32x32 pixels, e há 8 sprites no arquivo
        // this.game.load.spritesheet('player', 'Assets/spritesheets/player.png', 32, 32, 8);
        this.game.load.spritesheet('items', 'Assets/spritesheets/items.png', 32, 32, 16);
        this.game.load.spritesheet('enemies', 'Assets/spritesheets/enemies.png', 32, 32, 12);

        // Para carregar um arquivo do Tiled, o mesmo precisa estar no formato JSON
        this.game.load.tilemap('level2', 'assets/maps/level2.json', null, Phaser.Tilemap.TILED_JSON);

        // Para carregar os sons, basta informar a chave e dizer qual é o arquivo
        this.game.load.audio('jumpSound', 'Assets/sounds/jump.wav');
        this.game.load.audio('pickupSound', 'Assets/sounds/pickup.wav');
        this.game.load.audio('playerDeath', 'Assets/sounds/hurt3.ogg');
        this.game.load.audio('enemyDeath', 'Assets/sounds/hit2.ogg');
        this.game.load.audio('music', 'Assets/sounds/mystery.wav');

        // player
        this.player.preload();
    }

    Level2State.prototype.create = function() {

        // Inicializando sistema de física
        // o sistema Arcade é o mais simples de todos, mas também é o mais eficiente em termos de processamento.
        // https://photonstorm.github.io/phaser-ce/Phaser.Physics.Arcade.html
        this.game.physics.startSystem(Phaser.Physics.ARCADE);

        // Para carregar o mapa do Tiled para o Phaser, 3 estágios são necessários:
        // 1 - Criar um objeto com o arquivo do Tiled carregado no preload()
        this.level2 = this.game.add.tilemap('level2');
        // 2 - Adicionar as imagens correspondentes aos tilesets do Tiled dentro do Phaser
        // "tiles" é o nome do tileset dentro do Tiled
        // "mapTiles" é o nome da imagem com os tiles, carregada no preload()
        this.level2.addTilesetImage('tiles', 'mapTiles');

        // 3 - Criar os layers do mapa
        // A ordem nesse caso é importante, então os layers que ficarão no "fundo" deverão ser
        // criados primeiro, e os que ficarão na "frente" por último;
        this.bgLayer = this.level2.createLayer('Floor');
        //this.lavaLayer = this.level1.createLayer('Lava');
        this.wallsLayer = this.level2.createLayer('BG');
        // Mais informações sobre tilemaps:
        // https://photonstorm.github.io/phaser-ce/#toc14

        // Redimensionando o tamanho do "mundo" do jogo
        this.wallsLayer.resizeWorld();

        // Para que possamos detectar colisões dos objetos com os layers do mapa, primeiro precisamos
        // informar quais tiles deverão efetivamente ter um colisor, para cada layer.
        // Esta contagem é feita olhando o tileset no Tiled, sendo que o tile mais à esquerda da
        // primeira linha do tileset terá valor 1, o próximo na linha valor 2, e assim por diante,
        // continuando a contagem na próxima linha, até o último tile da última linha.

        // Neste caso, ao invés de dizermos quais tiles devem colidir, estamos dizendo quais tiles não
        // devem colidir, pois há mais tiles que colidem do que tiles sem colisão.
        // Os parâmetros são a lista dos tiles, "true" indicando que a colisão deve ser ativada,
        // e o nome do layer.
        this.level2.setCollisionByExclusion([9, 10, 11, 12, 17, 18, 19, 20], true, this.wallsLayer);

        // Para o layer de lava é o caso oposto: poucos tiles colidem, então é mais fácil
        // informar diretamente quais são.
        //this.level1.setCollision([5, 6, 13], true, this.lavaLayer);

        // Inicializando jogador
        this.player.setup(this);
        this.game.camera.follow(this.player.sprite);

        // Adicionando objetos do Tiled, utilizando grupos
        // Um grupo é como se fosse um array de sprites, mas com várias facilidades adicionais,
        // como por exemplo alterar atributos e facilitar detectar colisões com objetos do grupo
        // Especificamente, estamos criando physicsGroups, que já armazenam objetos com física ativada
        // https://photonstorm.github.io/phaser-ce/Phaser.GameObjectFactory.html#physicsGroup

        // Criando objetos que foram criados em um layer de objetos do Tiled
        // Parâmetros do createFromObjects():
        // nome do layer do Tiled de onde vamos criar os objetos
        // nome dos objetos do Tiled que serão criados
        // nome do spritesheet carregado no preload() com os objetos
        // frame do spritesheet, basta setar para um dos frames do objeto em questão
        // true, false - estes dois parâmetros podem ficar com estes valores
        // grupo - qual grupo do Phaser devemos adicionar esses objetos

        // Grupo de diamantes
        this.diamonds = this.game.add.physicsGroup();
        this.level2.createFromObjects('Items', 'diamond', 'items', 5, true, false, this.diamonds);
        // Para cada objeto do grupo, vamos executar uma função
        this.diamonds.forEach(function(diamond){
            // body.immovable = true indica que o objeto não é afetado por forças externas
            diamond.body.immovable = true;
            // Adicionando animações; o parâmetro true indica que a animação é em loop
            diamond.animations.add('spin', [4, 5, 6, 7, 6, 5], 6, true);
            diamond.animations.play('spin');
        });

        this.bats = this.game.add.physicsGroup();
        this.level2.createFromObjects('Enemies', 'bat', 'enemies', 8, true, false, this.bats);
        this.bats.forEach(function(bat){
            bat.anchor.setTo(0.5, 0.5);
            bat.body.immovable = true;
            bat.animations.add('fly', [8, 9, 10], 6, true);
            bat.animations.play('fly');
            // Velocidade inicial do inimigo
            bat.body.velocity.x = 100;
            // bounce.x=1 indica que, se o objeto tocar num objeto no eixo x, a força deverá
            // ficar no sentido contrário; em outras palavras, o objeto é perfeitamente elástico
            bat.body.bounce.x = 1;
        });

        // Criando assets de som com this.game.add.audio()
        // O parâmetro é o nome do asset definido no preload()
        this.jumpSound = this.game.add.audio('jumpSound');
        this.pickupSound = this.game.add.audio('pickupSound');
        this.playerDeathSound = this.game.add.audio('playerDeath');
        this.enemyDeathSound = this.game.add.audio('enemyDeath');

        // Música de fundo - criada da mesma forma, mas com o parâmetro loop = true
        this.music = this.game.add.audio('music');
        this.music.loop = true;
        // Já iniciamos a música aqui mesmo pra ficar tocando ao fundo
        this.music.play();

        // HUD de score
        // A linha abaixo adiciona um texto na tela, e a próxima faz com o que o texto fique
        // fixo na câmera, dessa forma não vai se deslocar quando a câmera mudar
        this.scoreText = this.game.add.text(500, 50, "Score: 0",
                                {font: "25px Arial", fill: "#ffffff"});
        this.scoreText.fixedToCamera = true;

        // Estado do jogo - Variáveis para guardar quaisquer informações pertinentes para as condições de
        // vitória/derrota, ações do jogador, etc
        this.totalDiamonds = this.diamonds.length;
        this.collectedDiamonds = 0;
        this.score = 0;

    }

    Level2State.prototype.update = function() {
        // Detecção de colisões
        // Todas as colisões entre os objetos do jogo são avaliadas com arcade.collide() ou
        // arcade.overlap(). O Phaser irá automaticamente calcular a colisão dos objetos
        // Inicialmente, adicionando colisões do player com as paredes da fase, que é um layer:
        this.game.physics.arcade.collide(this.player.sprite, this.wallsLayer, this.player.groundCollision, null, this.player);

        // Colisão com os morcegos - depende de como foi a colisão, veremos abaixo
        this.game.physics.arcade.overlap(this.player.sprite, this.bats, this.batCollision, null, this);

        // Adicionando colisão entre os morcegos e as paredes
        this.game.physics.arcade.collide(this.bats, this.wallsLayer);

        // Movimentação do player
         this.player.handleInputs();

        // Para cada morcego, verificar em que sentido ele está indo
        // Se a velocidade for positiva, a escala no eixo X será 1, caso
        // contrário -1
        this.bats.forEach(function(bat){
           if(bat.body.velocity.x != 0) {
               // Math.sign apenas retorna o sinal do parâmetro: positivo retorna 1, negativo -1
               bat.scale.x = 1 * Math.sign(bat.body.velocity.x);
           }
        });

    }

    // Tratamento da colisão entre o jogador e os diamantes
    Level2State.prototype.batCollision = function(player, bat){
        // Se o jogador colidir por baixo e o morcego por cima, isso indica que o jogador pulou
        // em cima do morcego, nesse caso vamos "matar" o morcego
        if(player.body.touching.down && bat.body.touching.up){
            this.enemyDeathSound.play(); // tocando som de morte do morcego
            this.player.body.velocity.y = -200; // adicionando um pequeno impulso vertical ao jogador
            this.score += 100; // atualizando score
            this.scoreText.text = "Score: " + this.score;
            bat.kill();
        }
        else this.lose(); // caso contrário, ir para condição de derrota
    }

    // Condição de derrota: guarde o score e siga para o próximo estado
    Level2State.prototype.gameover = function(){
        alert("game over");
    }

    gameManager.addState('level2', Level2State);

})();<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jshint eqeqeq: false*/

/**
Provides a set of features
to control a YUI instance on the client side. This module will be
serialized and sent to the client side thru `res.expose()` and available
in the client side thru `window.app.yui`.

@module express-yui/lib/client
**/

var utils = require('./utils');

/**
Provides a set of methods to be serialized and sent to the client side to boot
the application in the browser.

@class client
@static
@uses utils
@extensionfor express-yui/lib/yui
*/
function bootstrap() {

    var self = this,
        d = document,
        head = d.getElementsByTagName('head')[0],
        // Some basic browser sniffing...
        ie = /MSIE/.test(navigator.userAgent),
        // number of seed parts that are still pending
        pending = 0,
        // it is just a queue of pending "use" statements until YUI gets ready
        callback = [],
        args = arguments,
        config = typeof YUI_config != "undefined" ? YUI_config : {};

    function flush() {
        var l = callback.length,
            i;
        if (!self.YUI && typeof YUI == "undefined") {
            throw new Error("YUI was not injected correctly!");
        }
        self.YUI = self.YUI || YUI;
        // callback on every pending use statement
        for (i = 0; i < l; i++) {
            callback.shift()();
        }
    }

    function decrementRequestPending() {
        pending--;
        if (pending <= 0) {
            setTimeout(flush, 0);
        } else {
            // in case there is any remaining script to be loaded
            load();
        }
    }

    function createScriptNode(src) {
        var node = d.createElement('script');
        // use async=false for ordered async?
        // parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
        if (node.async) {
            node.async = false;
        }
        if (ie) {
            node.onreadystatechange = function () {
                if (/loaded|complete/.test(this.readyState)) {
                    this.onreadystatechange = null;
                    decrementRequestPending();
                }
            };
        } else {
            node.onload = node.onerror = decrementRequestPending;
        }
        node.setAttribute('src', src);
        return node;
    }

    function load() {
        if (!config.seed) {
            throw new Error('YUI_config.seed array is required.');
        }
        var seed = config.seed,
            l = seed.length,
            i, node;

        pending = pending || seed.length;
        // flagging the injection process to avoid duplicated entries
        self._injected = true;

        // appending every file from seed collection into the header
        for (i = 0; i < l; i++) {
            node = createScriptNode(seed.shift());
            head.appendChild(node);
            // TODO: if original node.async is undefined, it means the order has
            // to be preserved manually, in which case we should insert
            // them one by one to guarantee serial execute
            if (node.async !== false) {
                break;
            }
        }

    }

    callback.push(function () {
        var i;

        if (!self._Y) {
            // extend core (YUI_config.extendedCore)
            self.YUI.Env.core.push.apply(self.YUI.Env.core, config.extendedCore || []);
            // create unique instance which is accesible thru app.yui.use()
            self._Y = self.YUI();
            self.use = self._Y.use;

            if (config.patch) {
                for (i = 0; i < config.patch.length; i += 1) {
                    config.patch[i].apply(self);
                }
            }
        }
        // call use for arguments
        self._Y.use.apply(self._Y, args);
    });

    // just in case YUI was injected manually in the page
    self.YUI = self.YUI || (typeof YUI != "undefined" ? YUI : null);

    if (!self.YUI && !self._injected) {
        // attach seed and wait for it to finish to flush the callback
        load();
    } else if (pending <= 0) {
        // everything is ready, just flush
        flush();
    } // else do nothing, the current pending job will take care of flushing callback

    return this; // chaining
}

module.exports = {

    /**
    Attaches the seed into the head, then creates a YUI Instance and attaches
    `modules` into it. This is equivalent to `YUI().use()` after getting the seed
    ready. This method is a bootstrap implementation for the library, and the way
    you use this in your templates, is by doing this:

        <script>{{{state}}}</script>
        <script>
        app.yui.use('foo', 'bar', function (Y) {
            // do something!
        });
        </script>

    Where `state` defines the state of the express app, and `app.yui` defines
    the helpers that `express-yui` brings into the client side.

    @method use
    @public
    **/
    use: utils.minifyFunction(bootstrap), // optimizing before exposing it to the client side

    /**
    Boots the application, rehydrate the app state and calls back to notify the
    `ready` state of the app.

        <script>{{{state}}}</script>
        <script>
        app.yui.ready(function (err) {
            if (err) {
                throw err;
            }
            app.yui.use('foo', 'bar', function (Y) {
                // do something!
            });
        });
        </script>

    @method ready
    @param {Function} callback when the app is ready. If an error occurr, the error object
                        will be passed as the first argument of the callback function.
    @public
    **/
    ready: utils.minifyFunction(function (callback) {
        this.use(function () {
            callback();
        });
    })

};
<commit_msg>update name of patches property<commit_after>/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jshint eqeqeq: false*/

/**
Provides a set of features
to control a YUI instance on the client side. This module will be
serialized and sent to the client side thru `res.expose()` and available
in the client side thru `window.app.yui`.

@module express-yui/lib/client
**/

var utils = require('./utils');

/**
Provides a set of methods to be serialized and sent to the client side to boot
the application in the browser.

@class client
@static
@uses utils
@extensionfor express-yui/lib/yui
*/
function bootstrap() {

    var self = this,
        d = document,
        head = d.getElementsByTagName('head')[0],
        // Some basic browser sniffing...
        ie = /MSIE/.test(navigator.userAgent),
        // number of seed parts that are still pending
        pending = 0,
        // it is just a queue of pending "use" statements until YUI gets ready
        callback = [],
        args = arguments,
        config = typeof YUI_config != "undefined" ? YUI_config : {};

    function flush() {
        var l = callback.length,
            i;
        if (!self.YUI && typeof YUI == "undefined") {
            throw new Error("YUI was not injected correctly!");
        }
        self.YUI = self.YUI || YUI;
        // callback on every pending use statement
        for (i = 0; i < l; i++) {
            callback.shift()();
        }
    }

    function decrementRequestPending() {
        pending--;
        if (pending <= 0) {
            setTimeout(flush, 0);
        } else {
            // in case there is any remaining script to be loaded
            load();
        }
    }

    function createScriptNode(src) {
        var node = d.createElement('script');
        // use async=false for ordered async?
        // parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
        if (node.async) {
            node.async = false;
        }
        if (ie) {
            node.onreadystatechange = function () {
                if (/loaded|complete/.test(this.readyState)) {
                    this.onreadystatechange = null;
                    decrementRequestPending();
                }
            };
        } else {
            node.onload = node.onerror = decrementRequestPending;
        }
        node.setAttribute('src', src);
        return node;
    }

    function load() {
        if (!config.seed) {
            throw new Error('YUI_config.seed array is required.');
        }
        var seed = config.seed,
            l = seed.length,
            i, node;

        pending = pending || seed.length;
        // flagging the injection process to avoid duplicated entries
        self._injected = true;

        // appending every file from seed collection into the header
        for (i = 0; i < l; i++) {
            node = createScriptNode(seed.shift());
            head.appendChild(node);
            // TODO: if original node.async is undefined, it means the order has
            // to be preserved manually, in which case we should insert
            // them one by one to guarantee serial execute
            if (node.async !== false) {
                break;
            }
        }

    }

    callback.push(function () {
        var i;

        if (!self._Y) {
            // extend core (YUI_config.extendedCore)
            self.YUI.Env.core.push.apply(self.YUI.Env.core, config.extendedCore || []);
            // create unique instance which is accesible thru app.yui.use()
            self._Y = self.YUI();
            self.use = self._Y.use;

            if (config.patches) {
                for (i = 0; i < config.patches.length; i += 1) {
                    config.patches[i].apply(self);
                }
            }
        }
        // call use for arguments
        self._Y.use.apply(self._Y, args);
    });

    // just in case YUI was injected manually in the page
    self.YUI = self.YUI || (typeof YUI != "undefined" ? YUI : null);

    if (!self.YUI && !self._injected) {
        // attach seed and wait for it to finish to flush the callback
        load();
    } else if (pending <= 0) {
        // everything is ready, just flush
        flush();
    } // else do nothing, the current pending job will take care of flushing callback

    return this; // chaining
}

module.exports = {

    /**
    Attaches the seed into the head, then creates a YUI Instance and attaches
    `modules` into it. This is equivalent to `YUI().use()` after getting the seed
    ready. This method is a bootstrap implementation for the library, and the way
    you use this in your templates, is by doing this:

        <script>{{{state}}}</script>
        <script>
        app.yui.use('foo', 'bar', function (Y) {
            // do something!
        });
        </script>

    Where `state` defines the state of the express app, and `app.yui` defines
    the helpers that `express-yui` brings into the client side.

    @method use
    @public
    **/
    use: utils.minifyFunction(bootstrap), // optimizing before exposing it to the client side

    /**
    Boots the application, rehydrate the app state and calls back to notify the
    `ready` state of the app.

        <script>{{{state}}}</script>
        <script>
        app.yui.ready(function (err) {
            if (err) {
                throw err;
            }
            app.yui.use('foo', 'bar', function (Y) {
                // do something!
            });
        });
        </script>

    @method ready
    @param {Function} callback when the app is ready. If an error occurr, the error object
                        will be passed as the first argument of the callback function.
    @public
    **/
    ready: utils.minifyFunction(function (callback) {
        this.use(function () {
            callback();
        });
    })

};
<|endoftext|>


<commit_before>// TODO:
//  * support 1 nested multipart level
//    (see second multipart example here:
//     http://www.w3.org/TR/html401/interact/forms.html#didx-multipartform-data)
//  * support limits.fieldNameSize
//     -- this will require modifications to utils.parseParams

var ReadableStream = require('stream').Readable || require('readable-stream'),
    inherits = require('util').inherits;

var Dicer = require('dicer');

var parseParams = require('../utils').parseParams,
    decodeText = require('../utils').decodeText;

var RE_BOUNDARY = /^boundary$/i,
    RE_FIELD = /^form-data$/i,
    RE_CHARSET = /^charset$/i,
    RE_FILENAME = /^filename$/i,
    RE_NAME = /^name$/i;

Multipart.detect = /^multipart\/form-data/i;
function Multipart(boy, cfg) {
  if (!(this instanceof Multipart))
    return new Multipart(boy, cfg);
  var boundary,
      i,
      len,
      self = this,
      limits = cfg.limits,
      headers = cfg.headers,
      parsedConType = cfg.parsedConType,
      defCharset = cfg.defCharset || 'utf8',
      fileopts = (typeof cfg.fileHwm === 'number'
                  ? { highWaterMark: cfg.fileHwm }
                  : {});

  for (i = 0, len = parsedConType.length; i < len; ++i) {
    if (Array.isArray(parsedConType[i])
        && RE_BOUNDARY.test(parsedConType[i][0])) {
      boundary = parsedConType[i][1];
      break;
    }
  }

  function checkFinished() {
    if (nends === 0 && finished && !boy._done) {
      finished = false;
      process.nextTick(function() {
        boy._done = true;
        boy.emit('finish');
      });
    }
  }

  if (typeof boundary !== 'string')
    throw new Error('Multipart: Boundary not found');

  var fieldSizeLimit = (limits && limits.fieldSize) || (1 * 1024 * 1024),
      fileSizeLimit = (limits && limits.fileSize) || Infinity,
      filesLimit = (limits && limits.files) || Infinity,
      fieldsLimit = (limits && limits.fields) || Infinity,
      partsLimit = (limits && limits.parts) || Infinity;

  var nfiles = 0, nfields = 0, nends = 0, curFile, finished = false;

  this._needDrain = false;
  this._pause = false;
  this._cb = undefined;
  this._nparts = 0;
  this._boy = boy;

  var parserCfg = {
    boundary: boundary,
    maxHeaderPairs: (limits && limits.headerPairs)
  };
  if (fileopts.highWaterMark)
    parserCfg.partHwm = fileopts.highWaterMark;
  if (cfg.highWaterMark)
    parserCfg.highWaterMark = cfg.highWaterMark;
  this.parser = new Dicer(parserCfg);
  this.parser.on('drain', function() {
    self._needDrain = false;
    if (self._cb && !self._pause) {
      var cb = self._cb;
      self._cb = undefined;
      cb();
    }
  }).on('part', function onPart(part) {
    if (++self._nparts > partsLimit) {
      self.parser.removeListener('part', onPart);
      self.parser.on('part', skipPart);
      boy.hitPartsLimit = true;
      boy.emit('partsLimit');
      return skipPart(part);
    }
    part.on('header', function(header) {
      var contype, fieldname, parsed, charset, encoding, filename, nsize = 0;

      if (header['content-type']) {
        parsed = parseParams(header['content-type'][0]);
        contype = parsed[0].toLowerCase();
        for (i = 0, len = parsed.length; i < len; ++i) {
          if (RE_CHARSET.test(parsed[i][0])) {
            charset = parsed[i][1].toLowerCase();
            break;
          }
        }
      } else
        contype = 'text/plain';

      if (charset === undefined)
        charset = defCharset;

      if (header['content-disposition']) {
        parsed = parseParams(header['content-disposition'][0]);
        if (!RE_FIELD.test(parsed[0]))
          return skipPart(part);
        for (i = 0, len = parsed.length; i < len; ++i) {
          if (RE_NAME.test(parsed[i][0]))
            fieldname = decodeText(parsed[i][1], 'binary', 'utf8');
          else if (RE_FILENAME.test(parsed[i][0]))
            filename = decodeText(parsed[i][1], 'binary', 'utf8');
        }
      } else
        return skipPart(part);

      if (header['content-transfer-encoding'])
        encoding = header['content-transfer-encoding'][0].toLowerCase();
      else
        encoding = '7bit';

      var onData, onEnd;
      if (contype === 'application/octet-stream' || filename !== undefined) {
        // file/binary field
        if (nfiles === filesLimit) {
          if (!boy.hitFilesLimit) {
            boy.hitFilesLimit = true;
            boy.emit('filesLimit');
          }
          return skipPart(part);
        }

        ++nfiles;

        if (!boy._events.file) {
          self.parser._ignore();
          return;
        }

        ++nends;
        var file = new FileStream(fileopts);
        curFile = file;
        file.on('end', function() {
          --nends;
          checkFinished();
        });
        file._read = function(n) {
          if (!self._pause)
            return;
          self._pause = false;
          if (self._cb && !self._needDrain) {
            var cb = self._cb;
            self._cb = undefined;
            cb();
          }
        };
        boy.emit('file', fieldname, file, filename, encoding, contype);

        onData = function(data) {
          if ((nsize += data.length) > fileSizeLimit) {
            var extralen = (fileSizeLimit - (nsize - data.length));
            if (extralen > 0)
              file.push(data.slice(0, extralen));
            file.truncated = true;
            part.removeAllListeners('data');
          } else if (!file.push(data))
            self._pause = true;
        };

        onEnd = function() {
          curFile = undefined;
          file.push(null);
        };
      } else {
        // non-file field
        if (nfields === fieldsLimit) {
          if (!boy.hitFieldsLimit) {
            boy.hitFieldsLimit = true;
            boy.emit('fieldsLimit');
          }
          return skipPart(part);
        }

        ++nfields;
        ++nends;
        var buffer = '', truncated = false;

        onData = function(data) {
          if ((nsize += data.length) > fieldSizeLimit) {
            var extralen = (fieldSizeLimit - (nsize - data.length));
            buffer += data.toString('binary', 0, extralen);
            truncated = true;
            part.removeAllListeners('data');
          } else
            buffer += data.toString('binary');
        };

        onEnd = function() {
          if (buffer.length)
            buffer = decodeText(buffer, 'binary', charset);
          boy.emit('field', fieldname, buffer, false, truncated);
          --nends;
          checkFinished();
        };
      }
      part.on('data', onData);
      part.on('end', onEnd);
    }).on('error', function(err) {
      if (curFile)
        curFile.emit('error', err);
    });
  }).on('error', function(err) {
    boy.emit('error', err);
  }).on('finish', function() {
    finished = true;
    checkFinished();
  });
}

Multipart.prototype.write = function(chunk, cb) {
  var r;
  if ((r = this.parser.write(chunk)) && !this._pause)
    cb();
  else {
    this._needDrain = !r;
    this._cb = cb;
  }
};

Multipart.prototype.end = function() {
  var self = this;
  if (this._nparts === 0 && !self._boy._done) {
    process.nextTick(function() {
      self._boy._done = true;
      self._boy.emit('finish');
    });
  }
};

function skipPart(part) {
  part.resume();
}

function FileStream(opts) {
  if (!(this instanceof FileStream))
    return new FileStream(opts);
  ReadableStream.call(this, opts);

  this.truncated = false;
}
inherits(FileStream, ReadableStream);

FileStream.prototype._read = function(n) {};

module.exports = Multipart;
<commit_msg>multipart: style change<commit_after>// TODO:
//  * support 1 nested multipart level
//    (see second multipart example here:
//     http://www.w3.org/TR/html401/interact/forms.html#didx-multipartform-data)
//  * support limits.fieldNameSize
//     -- this will require modifications to utils.parseParams

var ReadableStream = require('stream').Readable || require('readable-stream'),
    inherits = require('util').inherits;

var Dicer = require('dicer');

var parseParams = require('../utils').parseParams,
    decodeText = require('../utils').decodeText;

var RE_BOUNDARY = /^boundary$/i,
    RE_FIELD = /^form-data$/i,
    RE_CHARSET = /^charset$/i,
    RE_FILENAME = /^filename$/i,
    RE_NAME = /^name$/i;

Multipart.detect = /^multipart\/form-data/i;
function Multipart(boy, cfg) {
  if (!(this instanceof Multipart))
    return new Multipart(boy, cfg);
  var i,
      len,
      self = this,
      boundary,
      limits = cfg.limits,
      headers = cfg.headers,
      parsedConType = cfg.parsedConType,
      defCharset = cfg.defCharset || 'utf8',
      fileopts = (typeof cfg.fileHwm === 'number'
                  ? { highWaterMark: cfg.fileHwm }
                  : {});

  for (i = 0, len = parsedConType.length; i < len; ++i) {
    if (Array.isArray(parsedConType[i])
        && RE_BOUNDARY.test(parsedConType[i][0])) {
      boundary = parsedConType[i][1];
      break;
    }
  }

  function checkFinished() {
    if (nends === 0 && finished && !boy._done) {
      finished = false;
      process.nextTick(function() {
        boy._done = true;
        boy.emit('finish');
      });
    }
  }

  if (typeof boundary !== 'string')
    throw new Error('Multipart: Boundary not found');

  var fieldSizeLimit = (limits && limits.fieldSize) || (1 * 1024 * 1024),
      fileSizeLimit = (limits && limits.fileSize) || Infinity,
      filesLimit = (limits && limits.files) || Infinity,
      fieldsLimit = (limits && limits.fields) || Infinity,
      partsLimit = (limits && limits.parts) || Infinity;

  var nfiles = 0, nfields = 0, nends = 0, curFile, finished = false;

  this._needDrain = false;
  this._pause = false;
  this._cb = undefined;
  this._nparts = 0;
  this._boy = boy;

  var parserCfg = {
    boundary: boundary,
    maxHeaderPairs: (limits && limits.headerPairs)
  };
  if (fileopts.highWaterMark)
    parserCfg.partHwm = fileopts.highWaterMark;
  if (cfg.highWaterMark)
    parserCfg.highWaterMark = cfg.highWaterMark;
  this.parser = new Dicer(parserCfg);
  this.parser.on('drain', function() {
    self._needDrain = false;
    if (self._cb && !self._pause) {
      var cb = self._cb;
      self._cb = undefined;
      cb();
    }
  }).on('part', function onPart(part) {
    if (++self._nparts > partsLimit) {
      self.parser.removeListener('part', onPart);
      self.parser.on('part', skipPart);
      boy.hitPartsLimit = true;
      boy.emit('partsLimit');
      return skipPart(part);
    }
    part.on('header', function(header) {
      var contype, fieldname, parsed, charset, encoding, filename, nsize = 0;

      if (header['content-type']) {
        parsed = parseParams(header['content-type'][0]);
        contype = parsed[0].toLowerCase();
        for (i = 0, len = parsed.length; i < len; ++i) {
          if (RE_CHARSET.test(parsed[i][0])) {
            charset = parsed[i][1].toLowerCase();
            break;
          }
        }
      } else
        contype = 'text/plain';

      if (charset === undefined)
        charset = defCharset;

      if (header['content-disposition']) {
        parsed = parseParams(header['content-disposition'][0]);
        if (!RE_FIELD.test(parsed[0]))
          return skipPart(part);
        for (i = 0, len = parsed.length; i < len; ++i) {
          if (RE_NAME.test(parsed[i][0]))
            fieldname = decodeText(parsed[i][1], 'binary', 'utf8');
          else if (RE_FILENAME.test(parsed[i][0]))
            filename = decodeText(parsed[i][1], 'binary', 'utf8');
        }
      } else
        return skipPart(part);

      if (header['content-transfer-encoding'])
        encoding = header['content-transfer-encoding'][0].toLowerCase();
      else
        encoding = '7bit';

      var onData, onEnd;
      if (contype === 'application/octet-stream' || filename !== undefined) {
        // file/binary field
        if (nfiles === filesLimit) {
          if (!boy.hitFilesLimit) {
            boy.hitFilesLimit = true;
            boy.emit('filesLimit');
          }
          return skipPart(part);
        }

        ++nfiles;

        if (!boy._events.file) {
          self.parser._ignore();
          return;
        }

        ++nends;
        var file = new FileStream(fileopts);
        curFile = file;
        file.on('end', function() {
          --nends;
          checkFinished();
        });
        file._read = function(n) {
          if (!self._pause)
            return;
          self._pause = false;
          if (self._cb && !self._needDrain) {
            var cb = self._cb;
            self._cb = undefined;
            cb();
          }
        };
        boy.emit('file', fieldname, file, filename, encoding, contype);

        onData = function(data) {
          if ((nsize += data.length) > fileSizeLimit) {
            var extralen = (fileSizeLimit - (nsize - data.length));
            if (extralen > 0)
              file.push(data.slice(0, extralen));
            file.truncated = true;
            part.removeAllListeners('data');
          } else if (!file.push(data))
            self._pause = true;
        };

        onEnd = function() {
          curFile = undefined;
          file.push(null);
        };
      } else {
        // non-file field
        if (nfields === fieldsLimit) {
          if (!boy.hitFieldsLimit) {
            boy.hitFieldsLimit = true;
            boy.emit('fieldsLimit');
          }
          return skipPart(part);
        }

        ++nfields;
        ++nends;
        var buffer = '', truncated = false;

        onData = function(data) {
          if ((nsize += data.length) > fieldSizeLimit) {
            var extralen = (fieldSizeLimit - (nsize - data.length));
            buffer += data.toString('binary', 0, extralen);
            truncated = true;
            part.removeAllListeners('data');
          } else
            buffer += data.toString('binary');
        };

        onEnd = function() {
          if (buffer.length)
            buffer = decodeText(buffer, 'binary', charset);
          boy.emit('field', fieldname, buffer, false, truncated);
          --nends;
          checkFinished();
        };
      }
      part.on('data', onData);
      part.on('end', onEnd);
    }).on('error', function(err) {
      if (curFile)
        curFile.emit('error', err);
    });
  }).on('error', function(err) {
    boy.emit('error', err);
  }).on('finish', function() {
    finished = true;
    checkFinished();
  });
}

Multipart.prototype.write = function(chunk, cb) {
  var r;
  if ((r = this.parser.write(chunk)) && !this._pause)
    cb();
  else {
    this._needDrain = !r;
    this._cb = cb;
  }
};

Multipart.prototype.end = function() {
  var self = this;
  if (this._nparts === 0 && !self._boy._done) {
    process.nextTick(function() {
      self._boy._done = true;
      self._boy.emit('finish');
    });
  }
};

function skipPart(part) {
  part.resume();
}

function FileStream(opts) {
  if (!(this instanceof FileStream))
    return new FileStream(opts);
  ReadableStream.call(this, opts);

  this.truncated = false;
}
inherits(FileStream, ReadableStream);

FileStream.prototype._read = function(n) {};

module.exports = Multipart;
<|endoftext|>


<commit_before>angular.module('tutorialWebApp').controller('TestCtrl', ['$scope', 'ProjectCouch', function

		($scope, ProjectCouch) {

			console.log("test Controller reporting for duty.");

			var promise = ProjectCouch.get({
					q : '_design',
					r : 'actions',
					s : '_view',
					t : 'getAll',
					include_docs : 'true',
					limit : 10
				});
			promise.$promise.then(function (data) {
				$scope.actions = data;
			}, function (reason) {
				alert(reason);
			});

		}
	])

.controller('TestEditCtrl',['$scope','ProjectCouch','$location','$routeParams',
function($scope,ProjectCouch,$location,$routeParams){
  console.log("test edit Controller reporting for duty.");
  var self = this;

  ProjectCouch.get({q: $routeParams.actionid}, function(action) {
    self.original =action;
    $scope.action = new ProjectCouch(self.original);
  });

  $scope.isClean = function() {
    return angular.equals(self.original, $scope.action);
  }

  $scope.destroy = function() {
    self.original.destroy(function() {
      $location.path('/test');
    });
  };

  $scope.save = function() {
    $scope.action.update(function() {
      $location.path('/');
    });
  };
}])
.controller('TestNewCtrl',['$scope','ProjectCouch','$location','$routeParams',
function($scope,ProjectCouch,$location,$routeParams){
  console.log("test newController reporting for duty.");
 $scope.save = function() {
    ProjectCouch.save($scope.action, function(action) {
      $location.path('/test/');
    });
  }
}]);

<commit_msg>beautify<commit_after>angular.module('tutorialWebApp').controller('TestCtrl', ['$scope', 'ProjectCouch', function

		($scope, ProjectCouch) {

			console.log("test Controller reporting for duty.");

			var promise = ProjectCouch.get({
					q : '_design',
					r : 'jobs',
					s : '_view',
					t : 'getAll',
					include_docs : 'true',
					limit : 10
				});
			promise.$promise.then(function (data) {
				$scope.actions = data;
			}, function (reason) {
				alert(reason);
			});

		}
	])

.controller('TestEditCtrl',['$scope','ProjectCouch','$location','$routeParams',
function($scope,ProjectCouch,$location,$routeParams){
  console.log("test edit Controller reporting for duty.");
  var self = this;

  ProjectCouch.get({q: $routeParams.actionid}, function(action) {
    self.original =action;
    $scope.action = new ProjectCouch(self.original);
  });

  $scope.isClean = function() {
    return angular.equals(self.original, $scope.action);
  }

  $scope.destroy = function() {
    self.original.destroy(function() {
      $location.path('/test');
    });
  };

  $scope.save = function() {
    $scope.action.update(function() {
      $location.path('/');
    });
  };
}])
.controller('TestNewCtrl',['$scope','ProjectCouch','$location','$routeParams',
function($scope,ProjectCouch,$location,$routeParams){
  console.log("test newController reporting for duty.");
 $scope.save = function() {
    ProjectCouch.save($scope.action, function(action) {
      $location.path('/test/');
    });
  }
}]);

<|endoftext|>


<commit_before>const fetch = require('node-fetch');
const qs = require('qs');
const debug = require('debug')('feathers-solr-client');
const debugError = require('debug')('feathers-solr-client-error');
const { FeathersError } = require('@feathersjs/errors');

class Client {
  constructor(conn) {
    if (!conn) {
      throw new Error('Connection string must be defined! http://localhost:8983/solr/core/');
    }
    this.conn = conn;
  }

  _response(res) {
    try {
      if (res.status >= 200 && res.status < 300) {
        debug('Response:', res.status);
        return res.json();
      } else {
        throw new FeathersError(res.status, res.statusText);
      }
    } catch (err) {
      debugError('Error:', err);
      throw new FeathersError(res.status, res.statusText);
    }
  }

  get(api, params = {}) {
    const url = `${this.conn}/${api}?${qs.stringify(params, { encode: false })}`;
    const options = {
      method: 'get',
      headers: { 'Content-Type': 'application/json' }
    };
    debug('GET', url);

    return fetch(url, options).then(res => this._response(res));
  }

  post(api, data, params = {}) {
    const url = `${this.conn}/${api}?${qs.stringify(params)}`;
    const options = {
      method: 'post',
      body: JSON.stringify(data),
      headers: { 'Content-Type': 'application/json' }
    };
    debug('Post:', url, '\n', data);

    return fetch(url, options).then(res => this._response(res));
  }
}

module.exports = Client;
<commit_msg>Refactor<commit_after>const fetch = require('node-fetch');
const qs = require('qs');
const debug = require('debug')('feathers-solr-client');
const debugError = require('debug')('feathers-solr-client-error');
const { FeathersError } = require('@feathersjs/errors');

class Client {
  constructor(conn) {
    if (!conn) {
      throw new Error('Connection string must be defined! http://localhost:8983/solr/core/');
    }
    this.conn = conn;
  }

  _response(res) {
    try {
      if (res.status >= 200 && res.status < 300) {
        debug('Response:', res.status);
        return res.json();
      } else {
        throw new FeathersError(res.status, res.statusText);
      }
    } catch (err) {
      debugError('Error:', err);
      throw new FeathersError(res.status, res.statusText);
    }
  }

  get(api, params = {}) {
    const url = `${this.conn}/${api}?${qs.stringify(params, { encode: false })}`;
    const options = {
      method: 'get',
      headers: { 'Content-Type': 'application/json' }
    };
    debug('GET', url);

    return fetch(url, options).then(res => this._response(res));
  }

  post(api, data, params = {}) {
    const url = `${this.conn}/${api}?${qs.stringify(params)}`;
    const options = {
      method: 'post',
      body: JSON.stringify(data),
      headers: { 'Content-Type': 'application/json' }
    };
    debug('Post:', url, data);

    return fetch(url, options).then(res => this._response(res));
  }
}

module.exports = Client;
<|endoftext|>


<commit_before>'use babel'

const Interact = require('interact.js')
import {CompositeDisposable} from 'atom'
import {Message} from './message-element'

export default class BottomPanel {
  constructor() {
    this.subscriptions = new CompositeDisposable

    this.visibility = false
    this.alwaysTakeMinimumSpace = atom.config.get('linter.alwaysTakeMinimumSpace')
    this.errorPanelHeight = atom.config.get('linter.errorPanelHeight')

    const element = document.createElement('linter-panel') // TODO(steelbrain): Make this a `div`
    Interact(element).resizable({edges: {top: true}})
      .on('resizemove', event => {
        event.target.style.height = `${event.rect.height}px`
      })
      .on('resizeend', event => {
        atom.config.set('linter.errorPanelHeight', event.target.clientHeight)
      })

    this.subscriptions.add(atom.config.onDidChange('linter.alwaysTakeMinimumSpace', ({newValue}) => {
      this.alwaysTakeMinimumSpace = newValue
      this.updateHeight()
    }))

    this.subscriptions.add(atom.config.onDidChange('linter.errorPanelHeight', ({newValue}) => {
      this.errorPanelHeight = newValue
      this.updateHeight()
    }))

  }
  setMessages() {
    this.updateVisibility()
  }
  refresh(scope) {}
  updateHeight() {
    let height = this.errorPanelHeight

    if (this.alwaysTakeMinimumSpace) {
      // Add `1px` for the top border.
      height = Math.min(this.messagesElement.clientHeight + 1, height)
    }

    this.messagesElement.parentNode.style.height = `${height}px`
  }
  getVisibility() {}
  updateVisibility() {}
  dispose() {
    this.subscriptions.dispose()
  }
}
<commit_msg>:fire: Remove the ui directory completely<commit_after><|endoftext|>