<commit_before>#!/usr/bin/env node
'use strict';

// Enable source map support
require('source-map-support').install();

// Polyfill Promise if necessary
if (global.Promise === undefined) {
  require('es6-promise').polyfill();
}

const pkg = require('../package.json');
const hibp = require('hibp');
const program = require('commander');
const prettyjson = require('prettyjson');
const Spinner = require('cli-spinner').Spinner;

// Configure the progress spinner
const fetchSpinner = new Spinner('Fetching data... %s');
fetchSpinner.setSpinnerString('|/-\\');

// Begin command-line argument configuration
program
    .usage(`${pkg.name} [option | command]`)
    .description('Each command has its own -h (--help) option.')
    .version(pkg.version, '-v, --version');

// Fetch and display breach data for an account
program
    .command('ba <account>')
    .description('get all breaches for an account (username or email address)')
    .option('-d, --domain-filter <domain>', 'filter breach data by domain')
    .option('-r, --raw', 'output the raw JSON data')
    .option('-t, --truncate', 'truncate data to just the name of each breach')
    .action((account, options) => {
      account = account.trim();
      if (account.length) {
        getBreachedAccount(account,
            options.domainFilter,
            options.truncate,
            options.raw);
      } else {
        program.help();
      }
    });

// Fetch and display all breach data in the system
program
    .command('breaches')
    .description('get all breaches in the system')
    .option('-d, --domain-filter <domain>', 'filter breach data by domain')
    .option('-r, --raw', 'output the raw JSON data')
    .action((options) => {
      getBreaches(options.domainFilter, options.raw);
    });

// Fetch and display a single breached site by name
program
    .command('breach <name>')
    .description('get a single breached site by breach name')
    .option('-r, --raw', 'output the raw JSON data')
    .action((name, options) => {
      name = name.trim();
      if (name.length) {
        getBreach(name, options.raw);
      } else {
        program.help();
      }
    });

// Fetch and display all data classes in the system
program
    .command('dc')
    .description('get all data classes in the system')
    .option('-r, --raw', 'output the raw JSON data')
    .action((options) => {
      getDataClasses(options.raw);
    });

// Fetch and display all pastes for an account
program
    .command('pa <email>')
    .description('get all pastes for an account (email address)')
    .option('-r, --raw', 'output the raw JSON data')
    .action((email, options) => {
      email = email.trim();
      if (email.length) {
        getPastes(email, options.raw);
      } else {
        program.help();
      }
    });

// Display help and exit if unknown arguments are provided
program.on('*', () => {
  program.help();
});

// Display help and exit if no arguments are provided
if (!process.argv.slice(2).length) {
  program.help();
}

// Initiate the parser
program.parse(process.argv);

/**
 * Fetches and outputs breach data for the specified account.
 *
 * @param {string} account a username or email address
 * @param {string} [domain] a domain by which to filter the results
 * @param {boolean} [truncateResults] truncate the results to only include the
 * name of each breach (default: false)
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getBreachedAccount (account, domain, truncateResults, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.breachedAccount(account, domain, truncateResults)
      .then((breachData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (!breachData) {
          console.log('Good news — no pwnage found!');
        } else if (raw) {
          console.log(JSON.stringify(breachData));
        } else {
          console.log(prettyjson.render(breachData));
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs all breached sites in the system.
 *
 * @param {string} [domain] a domain by which to filter the results
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getBreaches (domain, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.breaches(domain)
      .then((breachData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(breachData));
        } else if (breachData.length) {
          console.log(prettyjson.render(breachData));
        } else {
          console.log('No breaches found.');
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs breach data for a single site by breach name.
 *
 * @param {string} name the name of a breach in the system
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getBreach (name, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.breach(name)
      .then((breachData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(breachData));
        } else if (breachData) {
          console.log(prettyjson.render(breachData));
        } else {
          console.log('No breach found by that name.');
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs all data classes in the system.
 *
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getDataClasses (raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.dataClasses()
      .then((dataClasses) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(dataClasses));
        } else {
          console.log(prettyjson.render(dataClasses));
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs all pastes for an account (email address).
 *
 * @param {string} email the email address to query
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getPastes (email, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.pasteAccount(email)
      .then((pasteData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(pasteData));
        } else if (pasteData) {
          console.log(prettyjson.render(pasteData));
        } else {
          console.log('Good news — no pwnage found!');
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}
<commit_msg>Switch to ES2015 module import syntax<commit_after>#!/usr/bin/env node

// Enable source map support
import 'source-map-support/register';

// Polyfill Promise if necessary
import {polyfill} from 'es6-promise';
if (global.Promise === undefined) {
  polyfill();
}

import hibp from 'hibp';
import program from 'commander';
import prettyjson from 'prettyjson';
import {Spinner} from 'cli-spinner';
import * as pkg from '../package.json';

// Configure the progress spinner
const fetchSpinner = new Spinner('Fetching data... %s');
fetchSpinner.setSpinnerString('|/-\\');

// Begin command-line argument configuration
program
    .usage(`${pkg.name} [option | command]`)
    .description('Each command has its own -h (--help) option.')
    .version(pkg.version, '-v, --version');

// Fetch and display breach data for an account
program
    .command('ba <account>')
    .description('get all breaches for an account (username or email address)')
    .option('-d, --domain-filter <domain>', 'filter breach data by domain')
    .option('-r, --raw', 'output the raw JSON data')
    .option('-t, --truncate', 'truncate data to just the name of each breach')
    .action((account, options) => {
      account = account.trim();
      if (account.length) {
        getBreachedAccount(account,
            options.domainFilter,
            options.truncate,
            options.raw);
      } else {
        program.help();
      }
    });

// Fetch and display all breach data in the system
program
    .command('breaches')
    .description('get all breaches in the system')
    .option('-d, --domain-filter <domain>', 'filter breach data by domain')
    .option('-r, --raw', 'output the raw JSON data')
    .action((options) => {
      getBreaches(options.domainFilter, options.raw);
    });

// Fetch and display a single breached site by name
program
    .command('breach <name>')
    .description('get a single breached site by breach name')
    .option('-r, --raw', 'output the raw JSON data')
    .action((name, options) => {
      name = name.trim();
      if (name.length) {
        getBreach(name, options.raw);
      } else {
        program.help();
      }
    });

// Fetch and display all data classes in the system
program
    .command('dc')
    .description('get all data classes in the system')
    .option('-r, --raw', 'output the raw JSON data')
    .action((options) => {
      getDataClasses(options.raw);
    });

// Fetch and display all pastes for an account
program
    .command('pa <email>')
    .description('get all pastes for an account (email address)')
    .option('-r, --raw', 'output the raw JSON data')
    .action((email, options) => {
      email = email.trim();
      if (email.length) {
        getPastes(email, options.raw);
      } else {
        program.help();
      }
    });

// Display help and exit if unknown arguments are provided
program.on('*', () => {
  program.help();
});

// Display help and exit if no arguments are provided
if (!process.argv.slice(2).length) {
  program.help();
}

// Initiate the parser
program.parse(process.argv);

/**
 * Fetches and outputs breach data for the specified account.
 *
 * @param {string} account a username or email address
 * @param {string} [domain] a domain by which to filter the results
 * @param {boolean} [truncateResults] truncate the results to only include the
 * name of each breach (default: false)
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getBreachedAccount (account, domain, truncateResults, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.breachedAccount(account, domain, truncateResults)
      .then((breachData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (!breachData) {
          console.log('Good news — no pwnage found!');
        } else if (raw) {
          console.log(JSON.stringify(breachData));
        } else {
          console.log(prettyjson.render(breachData));
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs all breached sites in the system.
 *
 * @param {string} [domain] a domain by which to filter the results
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getBreaches (domain, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.breaches(domain)
      .then((breachData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(breachData));
        } else if (breachData.length) {
          console.log(prettyjson.render(breachData));
        } else {
          console.log('No breaches found.');
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs breach data for a single site by breach name.
 *
 * @param {string} name the name of a breach in the system
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getBreach (name, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.breach(name)
      .then((breachData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(breachData));
        } else if (breachData) {
          console.log(prettyjson.render(breachData));
        } else {
          console.log('No breach found by that name.');
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs all data classes in the system.
 *
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getDataClasses (raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.dataClasses()
      .then((dataClasses) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(dataClasses));
        } else {
          console.log(prettyjson.render(dataClasses));
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}

/**
 * Fetches and outputs all pastes for an account (email address).
 *
 * @param {string} email the email address to query
 * @param {boolean} [raw] output the raw JSON data (default: false)
 * @returns {undefined}
 */
function getPastes (email, raw) {
  if (!raw && process.stdout.isTTY) {
    fetchSpinner.start();
  }
  hibp.pasteAccount(email)
      .then((pasteData) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        if (raw) {
          console.log(JSON.stringify(pasteData));
        } else if (pasteData) {
          console.log(prettyjson.render(pasteData));
        } else {
          console.log('Good news — no pwnage found!');
        }
      })
      .catch((err) => {
        if (!raw && process.stdout.isTTY) {
          fetchSpinner.stop();
          console.log();
        }
        console.error(err.message);
      });
}
<|endoftext|>


<commit_before>return {
  "eval": function(T, a) {
    if (a == Tyrone.CALL) {
      T.stack.push(
        String(eval(T.stack.pop()))
      );
    }
  },

  "exec": function(T, a) {
    if (a == Tyrone.CALL) {
      eval(T.stack.pop());
    }
  }
};
<commit_msg>Added timer methods to js.js<commit_after>return {
  "eval": function(T, a) {
    if (a == Tyrone.CALL) {
      T.stack.push(
        String(eval(T.stack.pop()))
      );
    }
  },

  "exec": function(T, a) {
    if (a == Tyrone.CALL) {
      eval(T.stack.pop());
    }
  },

  "settimeout": function(T, a) {
    if (a == Tyrone.CALL) {
      var t = Number(T.stack.pop());
      var p = T.stack.pop();
      var id = setTimeout(function() {
        T.exec(p);
      }, t);
      T.stack.push(String(id));
    }
  },

  "cleartimeout": function(T, a) {
    if (a == Tyrone.CALL) {
      var id = Number(T.stack.pop());
      clearTimeout(id);
    }
  },

  "setinterval": function(T, a) {
    if (a == Tyrone.CALL) {
      var t = Number(T.stack.pop());
      var p = T.stack.pop();
      var id = setInterval(function() {
        T.exec(p);
      }, t);
      T.stack.push(String(id));
    }
  },

  "clearinterval": function(T, a) {
    if (a == Tyrone.CALL) {
      var id = Number(T.stack.pop());
      clearInterval(id);
    }
  }
};
<|endoftext|>


<commit_before>'use strict'

var Promise = require('q');
var _ = require('./lodash')

module.exports = function(service) {
  var reductiofy = require('./reductiofy')(service)
  var filters = require('./filters')(service)
  var postAggregation = require('./postAggregation')(service)
  var postAggregationMethods = _.keys(postAggregation)

  return function doQuery(queryObj) {
    var queryHash = JSON.stringify(queryObj)

    // Attempt to reuse an exact copy of this query that is present elsewhere
    for (var i = 0; i < service.columns.length; i++) {
      for (var j = 0; j < service.columns[i].queries.length; j++) {
        if (service.columns[i].queries[j].hash === queryHash) {
          return Promise.try(function() {
            return service.columns[i].queries[j]
          })
        }
      }
    }

    var query = {
      // Original query passed in to query method
      original: queryObj,
      hash: queryHash
    }

    // Default queryObj
    if (_.isUndefined(query.original)) {
      query.original = {}
    }
    // Default select
    if (_.isUndefined(query.original.select)) {
      query.original.select = {
        $count: true
      }
    }
    // Default to groupAll
    query.original.groupBy = query.original.groupBy || true

    // Attach the query api to the query object
    query = newQueryObj(query)

    return createColumn(query)
      .then(makeCrossfilterGroup)
      .then(buildRequiredColumns)
      .then(applyQuery)

    function createColumn(query) {
      // Ensure column is created
      return service.column({
          key: query.original.groupBy,
          type: !_.isUndefined(query.type) ? query.type : null,
          array: !!query.array
        })
        .then(function() {
          // Attach the column to the query
          var column = service.column.find(query.original.groupBy)
          query.column = column
          column.queries.push(query)
          column.removeListeners.push(function() {
            return query.clear()
          })
          return query
        })
    }

    function makeCrossfilterGroup(query) {
      // Create the grouping on the columns dimension
      // Using Promise Resolve allows support for crossfilter async
      // TODO check if query already exists, and use the same base query // if possible
      return Promise.resolve(query.column.dimension.group())
        .then(function(g) {
          query.group = g
          return query
        })
    }

    function buildRequiredColumns(query) {
      var requiredColumns = filters.scanForDynamicFilters(query.original)
        // We need to scan the group for any filters that would require
        // the group to be rebuilt when data is added or removed in any way.
      if (requiredColumns.length) {
        return Promise.all(_.map(requiredColumns, function(columnKey) {
            return service.column({
              key: columnKey,
              dynamicReference: query.group
            })
          }))
          .then(function() {
            // Here, we create a listener to recreate and apply the reducer
            // (with updated reference data) to
            // the group anytime data changes
            var stopDataListen = service.onDataChange(function() {
              return applyQuery(query)
            })
            query.removeListeners.push(stopDataListen)
            return query
          })
      }
      return query
    }

    function applyQuery(query) {

      // apply a one time listener for filtering. This is what allows
      // us to post aggregate and change the data on each filter
      var stopFilterListen = service.onFilter(function() {
        return postAggregate(query)
      })
      query.removeListeners.push(stopFilterListen)

      return buildReducer(query)
        .then(applyReducer)
        .then(attachData)
        .then(postAggregate)
    }

    function buildReducer(query) {
      return reductiofy(query.original)
        .then(function(reducer) {
          query.reducer = reducer
          return query
        })
    }

    function applyReducer(query) {
      return Promise.resolve(query.reducer(query.group))
        .then(function() {
          return query
        })
    }

    function attachData(query) {
      return Promise.resolve(query.group.all())
        .then(function(data) {
          query.data = data
          return query
        })
    }

    function postAggregate(query) {
      return Promise.all(_.map(query.postAggregations, function(post) {
          return post()
        }))
        .then(function() {
          return query
        })
    }

    function newQueryObj(q, parent) {
      var locked = false
      if (!parent) {
        parent = q
        q = {}
        locked = true
      }

      // Assign the regular query properties
      _.assign(q, {
        // The Universe for continuous promise chaining
        universe: service,
        // Crossfilter instance
        crossfilter: service.cf,

        // parent Information
        parent: parent,
        column: parent.column,
        dimension: parent.dimension,
        group: parent.group,
        reducer: parent.reducer,
        original: parent.original,
        hash: parent.hash,

        // It's own removeListeners
        removeListeners: [],

        // It's own postAggregations
        postAggregations: [],

        // Data method
        locked: locked,
        lock: lock,
        unlock: unlock,
        // Disposal method
        clear: clearQuery,
      })

      _.forEach(postAggregationMethods, function(method) {
        q[method] = postAggregateMethodWrap(postAggregation[method])
      })

      return q

      function lock(set){
        if(!_.isUndefined(set)){
          q.locked = !!set
          return
        }
        q.locked = true
      }

      function unlock(){
        q.locked = false
      }

      function clearQuery() {
        _.forEach(q.removeListners, function(l) {
          l()
        })
        return Promise.try(function() {
            return q.group.dispose()
          })
          .then(function() {
            q.column.queries.splice(q.column.queries.indexOf(q), 1)
            if (!q.column.queries.length) {
              return service.clear(q.column.key)
            }
          })
          .then(function() {
            return service
          })
      }

      function postAggregateMethodWrap(postMethod) {
        return function() {
          var args = Array.prototype.slice.call(arguments);
          var sub = {}
          newQueryObj(sub, q)
          args.unshift(sub, q)

          q.postAggregations.push(function() {
            Promise.resolve(postMethod.apply(null, args))
              .then(postAggregateChildren)
          })

          return Promise.resolve(postMethod.apply(null, args))
            .then(postAggregateChildren)

          function postAggregateChildren() {
            return postAggregate(sub)
              .then(function(){
                return sub
              })
          }
        }
      }

    }
  }
}
<commit_msg>Auto-lock a query if used by more than one post aggregation<commit_after>'use strict'

var Promise = require('q');
var _ = require('./lodash')

module.exports = function(service) {
  var reductiofy = require('./reductiofy')(service)
  var filters = require('./filters')(service)
  var postAggregation = require('./postAggregation')(service)
  var postAggregationMethods = _.keys(postAggregation)

  return function doQuery(queryObj) {
    var queryHash = JSON.stringify(queryObj)

    // Attempt to reuse an exact copy of this query that is present elsewhere
    for (var i = 0; i < service.columns.length; i++) {
      for (var j = 0; j < service.columns[i].queries.length; j++) {
        if (service.columns[i].queries[j].hash === queryHash) {
          return Promise.try(function() {
            return service.columns[i].queries[j]
          })
        }
      }
    }

    var query = {
      // Original query passed in to query method
      original: queryObj,
      hash: queryHash
    }

    // Default queryObj
    if (_.isUndefined(query.original)) {
      query.original = {}
    }
    // Default select
    if (_.isUndefined(query.original.select)) {
      query.original.select = {
        $count: true
      }
    }
    // Default to groupAll
    query.original.groupBy = query.original.groupBy || true

    // Attach the query api to the query object
    query = newQueryObj(query)

    return createColumn(query)
      .then(makeCrossfilterGroup)
      .then(buildRequiredColumns)
      .then(applyQuery)

    function createColumn(query) {
      // Ensure column is created
      return service.column({
          key: query.original.groupBy,
          type: !_.isUndefined(query.type) ? query.type : null,
          array: !!query.array
        })
        .then(function() {
          // Attach the column to the query
          var column = service.column.find(query.original.groupBy)
          query.column = column
          column.queries.push(query)
          column.removeListeners.push(function() {
            return query.clear()
          })
          return query
        })
    }

    function makeCrossfilterGroup(query) {
      // Create the grouping on the columns dimension
      // Using Promise Resolve allows support for crossfilter async
      // TODO check if query already exists, and use the same base query // if possible
      return Promise.resolve(query.column.dimension.group())
        .then(function(g) {
          query.group = g
          return query
        })
    }

    function buildRequiredColumns(query) {
      var requiredColumns = filters.scanForDynamicFilters(query.original)
        // We need to scan the group for any filters that would require
        // the group to be rebuilt when data is added or removed in any way.
      if (requiredColumns.length) {
        return Promise.all(_.map(requiredColumns, function(columnKey) {
            return service.column({
              key: columnKey,
              dynamicReference: query.group
            })
          }))
          .then(function() {
            // Here, we create a listener to recreate and apply the reducer
            // (with updated reference data) to
            // the group anytime data changes
            var stopDataListen = service.onDataChange(function() {
              return applyQuery(query)
            })
            query.removeListeners.push(stopDataListen)
            return query
          })
      }
      return query
    }

    function applyQuery(query) {

      // apply a one time listener for filtering. This is what allows
      // us to post aggregate and change the data on each filter
      var stopFilterListen = service.onFilter(function() {
        return postAggregate(query)
      })
      query.removeListeners.push(stopFilterListen)

      return buildReducer(query)
        .then(applyReducer)
        .then(attachData)
        .then(postAggregate)
    }

    function buildReducer(query) {
      return reductiofy(query.original)
        .then(function(reducer) {
          query.reducer = reducer
          return query
        })
    }

    function applyReducer(query) {
      return Promise.resolve(query.reducer(query.group))
        .then(function() {
          return query
        })
    }

    function attachData(query) {
      return Promise.resolve(query.group.all())
        .then(function(data) {
          query.data = data
          return query
        })
    }

    function postAggregate(query) {
      if(query.postAggregations.length > 1){
        // If the query is used by 2+ post aggregations, we need to lock
        // it against getting mutated by the post-aggregations
        query.locked = true
      }
      return Promise.all(_.map(query.postAggregations, function(post) {
          return post()
        }))
        .then(function() {
          return query
        })
    }

    function newQueryObj(q, parent) {
      var locked = false
      if (!parent) {
        parent = q
        q = {}
        locked = true
      }

      // Assign the regular query properties
      _.assign(q, {
        // The Universe for continuous promise chaining
        universe: service,
        // Crossfilter instance
        crossfilter: service.cf,

        // parent Information
        parent: parent,
        column: parent.column,
        dimension: parent.dimension,
        group: parent.group,
        reducer: parent.reducer,
        original: parent.original,
        hash: parent.hash,

        // It's own removeListeners
        removeListeners: [],

        // It's own postAggregations
        postAggregations: [],

        // Data method
        locked: locked,
        lock: lock,
        unlock: unlock,
        // Disposal method
        clear: clearQuery,
      })

      _.forEach(postAggregationMethods, function(method) {
        q[method] = postAggregateMethodWrap(postAggregation[method])
      })

      return q

      function lock(set){
        if(!_.isUndefined(set)){
          q.locked = !!set
          return
        }
        q.locked = true
      }

      function unlock(){
        q.locked = false
      }

      function clearQuery() {
        _.forEach(q.removeListners, function(l) {
          l()
        })
        return Promise.try(function() {
            return q.group.dispose()
          })
          .then(function() {
            q.column.queries.splice(q.column.queries.indexOf(q), 1)
            if (!q.column.queries.length) {
              return service.clear(q.column.key)
            }
          })
          .then(function() {
            return service
          })
      }

      function postAggregateMethodWrap(postMethod) {
        return function() {
          var args = Array.prototype.slice.call(arguments);
          var sub = {}
          newQueryObj(sub, q)
          args.unshift(sub, q)

          q.postAggregations.push(function() {
            Promise.resolve(postMethod.apply(null, args))
              .then(postAggregateChildren)
          })

          return Promise.resolve(postMethod.apply(null, args))
            .then(postAggregateChildren)

          function postAggregateChildren() {
            return postAggregate(sub)
              .then(function(){
                return sub
              })
          }
        }
      }

    }
  }
}
<|endoftext|>


<commit_before>jQuery(function ($) {
    var csrf_token = $('meta[name=csrf-token]').attr('content'),
        csrf_param = $('meta[name=csrf-param]').attr('content');

    $.fn.extend({
        /**
         * Triggers a custom event on an element and returns the event result
         * this is used to get around not being able to ensure callbacks are placed
         * at the end of the chain.
         *
         * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
         *       own events and placing ourselves at the end of the chain.
         */
        triggerAndReturn: function (name, data) {
            var event = new jQuery.Event(name);
            this.trigger(event, data);

            return event.result !== false;
        },

        /**
         * Handles execution of remote calls firing overridable events along the way
         *
         */
        callRemote: function () {
            var el      = $(this),
                data    = [],
                method  = el.attr('method') || el.attr('data-method') || 'GET',
                url     = el.attr('action') || el.attr('href');

            if (el.context.tagName.toUpperCase() === 'FORM') {
                data = el.serializeArray();
            }

            // TODO: should let the developer know no url was found
            if (url !== undefined) {
                if (el.triggerAndReturn('ajax:before')) {
                    $.ajax({
                        url: url,
                        data: data,
                        type: method.toUpperCase(),
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("Accept", "text/javascript");
                            el.trigger('ajax:loading', xhr);
                        },
                        success: function (data, status, xhr) {
                            el.trigger('ajax:success', [data, status, xhr]);
                        },
                        complete: function (xhr) {
                            el.trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            el.trigger('ajax:failure', [xhr, status, error]);
                        }
                    });
                }

                el.trigger('ajax:after');
            }
        }
    });

    /**
     *  confirmation handler
     */
    $('a[data-confirm],input[data-confirm]').live('click', function () {
        var el = $(this);
        if (el.triggerAndReturn('confirm')) {
            if (!confirm(el.attr('data-confirm'))) {
                return false;
            }
        }
    });

    /**
     * remote handlers
     */
    $('form[data-remote="true"]').live('submit', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-remote="true"],input[data-remote="true"]').live('click', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-method][data-remote!=true]').live('click',function(e){
        var link = $(this),
            href = link.attr('href'),
            method = link.attr('data-method'),
            form = $('<form method="post" action="'+href+'">'),
            input = $('<input name="_method" value="'+method+'" type="hidden" />'),
            csrf_input = $('<input name="'+csrf-param+'" value="'+csrf-token+'" type="hidden" />');

        form.hide();
        form.append(input);
        form.append(csrf_input);

        $('body').append(form); // redundant?

        e.preventDefault();
        form.submit();
    });

    /**
     * disable_with handlers
     */
    $('form[data-remote="true"]').live('ajax:before', function () {
        $(this).children('input[data-disable-with]').each(function (i, el) {
            var input = $(el);
            input.data('enable_with', input.val())
                 .attr('value', input.attr('data-disable-with'))
                 .attr('disabled', 'disabled');
        });
    });

    $('form[data-remote="true"]').live('ajax:after', function () {
        $(this).children('input[data-disable-with]').each(function (i, el) {
            var input = $(el);
            input.removeAttr('disabled')
                 .val(input.data('enable_with'));
        });
    });
});

<commit_msg>minor change to make the code more jQuery-like.<commit_after>jQuery(function ($) {
    var csrf_token = $('meta[name=csrf-token]').attr('content'),
        csrf_param = $('meta[name=csrf-param]').attr('content');

    $.fn.extend({
        /**
         * Triggers a custom event on an element and returns the event result
         * this is used to get around not being able to ensure callbacks are placed
         * at the end of the chain.
         *
         * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
         *       own events and placing ourselves at the end of the chain.
         */
        triggerAndReturn: function (name, data) {
            var event = new jQuery.Event(name);
            this.trigger(event, data);

            return event.result !== false;
        },

        /**
         * Handles execution of remote calls firing overridable events along the way
         *
         */
        callRemote: function () {
            var el      = $(this),
                data    = [],
                method  = el.attr('method') || el.attr('data-method') || 'GET',
                url     = el.attr('action') || el.attr('href');

            if (el.is('form')) {
                data = el.serializeArray();
            }

            // TODO: should let the developer know no url was found
            if (url !== undefined) {
                if (el.triggerAndReturn('ajax:before')) {
                    $.ajax({
                        url: url,
                        data: data,
                        type: method.toUpperCase(),
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("Accept", "text/javascript");
                            el.trigger('ajax:loading', xhr);
                        },
                        success: function (data, status, xhr) {
                            el.trigger('ajax:success', [data, status, xhr]);
                        },
                        complete: function (xhr) {
                            el.trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            el.trigger('ajax:failure', [xhr, status, error]);
                        }
                    });
                }

                el.trigger('ajax:after');
            }
        }
    });

    /**
     *  confirmation handler
     */
    $('a[data-confirm],input[data-confirm]').live('click', function () {
        var el = $(this);
        if (el.triggerAndReturn('confirm')) {
            if (!confirm(el.attr('data-confirm'))) {
                return false;
            }
        }
    });

    /**
     * remote handlers
     */
    $('form[data-remote="true"]').live('submit', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-remote="true"],input[data-remote="true"]').live('click', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-method][data-remote!=true]').live('click',function(e){
        var link = $(this),
            href = link.attr('href'),
            method = link.attr('data-method'),
            form = $('<form method="post" action="'+href+'">'),
            input = $('<input name="_method" value="'+method+'" type="hidden" />'),
            csrf_input = $('<input name="'+csrf-param+'" value="'+csrf-token+'" type="hidden" />');

        form.hide();
        form.append(input);
        form.append(csrf_input);

        $('body').append(form); // redundant?

        e.preventDefault();
        form.submit();
    });

    /**
     * disable_with handlers
     */
    $('form[data-remote="true"]').live('ajax:before', function () {
        $(this).children('input[data-disable-with]').each(function (i, el) {
            var input = $(el);
            input.data('enable_with', input.val())
                 .attr('value', input.attr('data-disable-with'))
                 .attr('disabled', 'disabled');
        });
    });

    $('form[data-remote="true"]').live('ajax:after', function () {
        $(this).children('input[data-disable-with]').each(function (i, el) {
            var input = $(el);
            input.removeAttr('disabled')
                 .val(input.data('enable_with'));
        });
    });
});

<|endoftext|>


<commit_before>// Raven.js
//
// Originally based on the Arecibo JavaScript client.
//
// Requires:
//     * TraceKit (included in the full and minified distribution files)

'use strict';

// First, check for JSON support
// If there is no JSON, we no-op the core features of Raven
// since JSON is required to encode the payload
var _Raven = window.Raven,
    hasJSON = !isUndefined(window.JSON),
    globalServer,
    globalUser,
    globalKey,
    globalProject,
    globalOptions = {
        logger: 'javascript',
        ignoreErrors: [],
        ignoreUrls: []
    };

/*
 * The core Raven object
 */
var Raven = {
    VERSION: '@VERSION',

    /*
     * Raven.noConflict()
     *
     * Allow multiple versions of Raven to be installed.
     */
    noConflict: function() {
        window.Raven = _Raven;
        return Raven;
    },

    /*
     * Raven.config()
     *
     * Configure raven with a DSN and extra options
     */
    config: function(dsn, options) {
        var uri = parseUri(dsn),
            lastSlash = uri.path.lastIndexOf('/'),
            path = uri.path.substr(1, lastSlash);

        // merge in options
        if (options) {
            each(options, function(key, value){
                globalOptions[key] = value;
            });
        }

        // "Script error." is hard coded into browsers for errors that it can't read.
        // this is the result of a script being pulled in from an external domain and CORS.
        globalOptions.ignoreErrors.push('Script error.');

        globalKey = uri.user;
        globalProject = ~~uri.path.substr(lastSlash + 1);

        // assemble the endpoint from the uri pieces
        globalServer = uri.protocol + '://' + uri.host +
                      (uri.port ? ':' + uri.port : '') +
                      '/' + path + 'api/' + globalProject + '/store/';

        // return for chaining
        return Raven;
    },

    /*
     * Raven.install()
     *
     * Installs a global window.onerror error handler
     * to capture and report uncaught exceptions.
     */
    install: function() {
        if (!isSetup()) return;

        TraceKit.report.subscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.context()
     *
     * Wrap code within a context so Raven can capture errors
     * reliably across domains that is executed immediately.
     */
    context: function(options, func, args) {
        if (isFunction(options)) {
            args = func;
            func = options;
            options = undefined;
        }

        Raven.wrap(options, func).apply(this, args);
    },

    /* Raven.wrap()
     *
     * Wrap code within a context and returns back a new function to be executed
     */
    wrap: function(options, func) {
        // options is optional
        if (isFunction(options)) {
            func = options;
            options = undefined;
        }

        return function() {
            try {
                func.apply(this, arguments);
            } catch(e) {
                Raven.captureException(e, options);
            }
        };
    },

    /*
     * Raven.uninstall()
     *
     * Uninstalls the global error handler.
     */
    uninstall: function() {
        TraceKit.report.unsubscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.captureException()
     *
     * Manually capture an exception and send it over to Sentry
     */
    captureException: function(ex, options) {
        // TraceKit.report will re-raise any exception passed to it,
        // which means you have to wrap it in try/catch. Instead, we
        // can wrap it here and only re-raise if TraceKit.report
        // raises an exception different from the one we asked to
        // report on.
        try {
            TraceKit.report(ex, options);
        } catch(ex1) {
            if(ex !== ex1) {
                throw ex1;
            }
        }

        return Raven;
    },

    /*
     * Raven.captureMessage()
     *
     * Manually send a message to Sentry
     */
    captureMessage: function(msg, options) {
        // Fire away!
        send(
            arrayMerge({
                message: msg
            }, options)
        );

        return Raven;
    },

    /*
     * Raven.setUser()
     *
     * Set/clear a user to be sent along with the payload.
     */
    setUser: function(user) {
       globalUser = user;

       return Raven;
    }
};

/**** Private functions ****/
function parseUri(str) {
    var keys = 'source protocol authority userInfo user password host port relative path directory file query anchor'.split(' '),
        m = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str),
        uri = {},
        i = 14;

    while (i--) uri[keys[i]] = m[i] || '';

    return uri;
}

function isUndefined(what) {
    return typeof what === 'undefined';
}

function isFunction(what) {
    return typeof what === 'function';
}

function each(obj, callback) {
    var i, j;

    if (obj.length === undefined) {
        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                callback.call(null, i, obj[i]);
            }
        }
    } else {
        for (i = 0, j = obj.length; i < j; i++) {
            callback.call(null, i, obj[i]);
        }
    }
}

var cachedAuth;

function getAuthQueryString() {
    if (cachedAuth) return cachedAuth;

    var qs = [
        'sentry_version=2.0',
        'sentry_client=raven-js/' + Raven.VERSION
    ];
    if (globalKey) {
        qs.push('sentry_key=' + globalKey);
    }

    cachedAuth = '?' + qs.join('&');
    return cachedAuth;
}

function handleStackInfo(stackInfo, options) {
    var frames = [], i = stackInfo.stack.length;

    while (i--) frames[i] = normalizeFrame(stackInfo.stack[i]);

    processException(
        stackInfo.name,
        stackInfo.message,
        stackInfo.url,
        stackInfo.lineno,
        frames,
        options
    );
}

function normalizeFrame(frame) {
    // normalize the frames data
    var normalized = {
        abs_path:   frame.url,
        lineno:     frame.line,
        colno:      frame.column,
        'function': frame.func || '?'
    }, context = extractContextFromFrame(frame);

    if (context) {
        var i = 3, keys = ['pre_context', 'context_line', 'post_context'];
        while (i--) normalized[keys[i]] = context[i];
    }

    normalized.in_app = !/(Raven|TraceKit)\./.test(normalized['function']);

    return normalized;
}

function extractContextFromFrame(frame) {
    if (!frame.context) return;

    var context = frame.context,
        pivot = ~~(context.length / 2),
        i = context.length, isMinified = false, line;

    while (i--) {
        line = context[i];
        // We're making a guess to see if the source is minified or not.
        // To do that, we make the assumption if *any* of the lines passed
        // in are greater than 300 characters long, we bail.
        // Sentry will see that there isn't a context
        if (line.length > 300) {
            isMinified = true;
            break;
        }
    }

    if (isMinified) {
        // The source is minified and we don't know which column. Fuck it.
        if (isUndefined(frame.column)) return;

        // Source maps are enabled and has a column number, let Sentry try and grab it
        if (globalOptions.sourceMaps) return;

        // If the source is minified with sourcemaps disabled and has a frame column
        // we take a chunk of the offending line to hopefully shed some light
        return [
            [],  // no pre_context
            context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
            []   // no post_context
        ];
    }

    return [
        context.slice(0, pivot),    // pre_context
        context[pivot],             // context_line
        context.slice(pivot + 1)    // post_context
    ];
}

function processException(type, message, fileurl, lineno, frames, options) {
    var stacktrace, label, i;

    // IE8 really doesn't have Array.prototype.indexOf
    // Filter out a message that matches our ignore list
    i = globalOptions.ignoreErrors.length;
    while (i--) {
        if (message === globalOptions.ignoreErrors[i]) {
            return;
        }
    }

    if (frames && frames.length) {
        stacktrace = {frames: frames};
        fileurl = fileurl || frames[0].filename;
    } else if (fileurl) {
        stacktrace = {
            frames: [{
                filename: fileurl,
                lineno: lineno
            }]
        };
    }

    i = globalOptions.ignoreUrls.length;
    while (i--) {
        if (globalOptions.ignoreUrls[i].test(fileurl)) {
            return;
        }
    }

    label = lineno ? message + ' at ' + lineno : message;

    // Fire away!
    send(
        arrayMerge({
            'sentry.interfaces.Exception': {
                type: type,
                value: message
            },
            'sentry.interfaces.Stacktrace': stacktrace,
            culprit: fileurl,
            message: label
        }, options)
    );
}

function arrayMerge(arr1, arr2) {
    if (!arr2) {
        return arr1;
    }
    each(arr2, function(key, value){
        arr1[key] = value;
    });
    return arr1;
}

function getHttpData() {
    var url = window.location.protocol + '//' + window.location.host + window.location.pathname,
        querystring = window.location.search.slice(1),  // Remove the ?
        http;

    http = {
        url: url,
        querystring: querystring,
        headers: {
            'User-Agent': navigator.userAgent
        }
    };

    if (window.document.referrer) {
        http.headers.Referer = window.document.referrer;
    }

    return http;
}

function send(data) {
    if (!isSetup()) return;

    data = arrayMerge({
        project: globalProject,
        logger: globalOptions.logger,
        site: globalOptions.site,
        platform: 'javascript',
        'sentry.interfaces.Http': getHttpData()
    }, data);

    if (globalUser) data['sentry.interfaces.User'] = globalUser;

    if (isFunction(globalOptions.dataCallback)) {
        data = globalOptions.dataCallback(data);
    }

    makeRequest(data);
}

function makeRequest(data) {
    new Image().src = globalServer + getAuthQueryString() + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
}

function isSetup() {
    if (!hasJSON) return false;  // needs JSON support
    if (!globalServer) {
        console.error("Error: Raven has not been configured.");
        return false;
    }
    return true;
}
<commit_msg>Expose a `fetchContext` config option and have it disabled by default<commit_after>// Raven.js
//
// Originally based on the Arecibo JavaScript client.
//
// Requires:
//     * TraceKit (included in the full and minified distribution files)

'use strict';

// First, check for JSON support
// If there is no JSON, we no-op the core features of Raven
// since JSON is required to encode the payload
var _Raven = window.Raven,
    hasJSON = !isUndefined(window.JSON),
    globalServer,
    globalUser,
    globalKey,
    globalProject,
    globalOptions = {
        logger: 'javascript',
        ignoreErrors: [],
        ignoreUrls: []
    };

// Disable Tracekit's remote fetching by default
TraceKit.remoteFetching = false;

/*
 * The core Raven object
 */
var Raven = {
    VERSION: '@VERSION',

    /*
     * Raven.noConflict()
     *
     * Allow multiple versions of Raven to be installed.
     */
    noConflict: function() {
        window.Raven = _Raven;
        return Raven;
    },

    /*
     * Raven.config()
     *
     * Configure raven with a DSN and extra options
     */
    config: function(dsn, options) {
        var uri = parseUri(dsn),
            lastSlash = uri.path.lastIndexOf('/'),
            path = uri.path.substr(1, lastSlash);

        // merge in options
        if (options) {
            each(options, function(key, value){
                globalOptions[key] = value;
            });
        }

        // "Script error." is hard coded into browsers for errors that it can't read.
        // this is the result of a script being pulled in from an external domain and CORS.
        globalOptions.ignoreErrors.push('Script error.');

        globalKey = uri.user;
        globalProject = ~~uri.path.substr(lastSlash + 1);

        // assemble the endpoint from the uri pieces
        globalServer = uri.protocol + '://' + uri.host +
                      (uri.port ? ':' + uri.port : '') +
                      '/' + path + 'api/' + globalProject + '/store/';

        if (options.fetchContext) {
            TraceKit.remoteFetching = true;
        }

        // return for chaining
        return Raven;
    },

    /*
     * Raven.install()
     *
     * Installs a global window.onerror error handler
     * to capture and report uncaught exceptions.
     */
    install: function() {
        if (!isSetup()) return;

        TraceKit.report.subscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.context()
     *
     * Wrap code within a context so Raven can capture errors
     * reliably across domains that is executed immediately.
     */
    context: function(options, func, args) {
        if (isFunction(options)) {
            args = func;
            func = options;
            options = undefined;
        }

        Raven.wrap(options, func).apply(this, args);
    },

    /* Raven.wrap()
     *
     * Wrap code within a context and returns back a new function to be executed
     */
    wrap: function(options, func) {
        // options is optional
        if (isFunction(options)) {
            func = options;
            options = undefined;
        }

        return function() {
            try {
                func.apply(this, arguments);
            } catch(e) {
                Raven.captureException(e, options);
            }
        };
    },

    /*
     * Raven.uninstall()
     *
     * Uninstalls the global error handler.
     */
    uninstall: function() {
        TraceKit.report.unsubscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.captureException()
     *
     * Manually capture an exception and send it over to Sentry
     */
    captureException: function(ex, options) {
        // TraceKit.report will re-raise any exception passed to it,
        // which means you have to wrap it in try/catch. Instead, we
        // can wrap it here and only re-raise if TraceKit.report
        // raises an exception different from the one we asked to
        // report on.
        try {
            TraceKit.report(ex, options);
        } catch(ex1) {
            if(ex !== ex1) {
                throw ex1;
            }
        }

        return Raven;
    },

    /*
     * Raven.captureMessage()
     *
     * Manually send a message to Sentry
     */
    captureMessage: function(msg, options) {
        // Fire away!
        send(
            arrayMerge({
                message: msg
            }, options)
        );

        return Raven;
    },

    /*
     * Raven.setUser()
     *
     * Set/clear a user to be sent along with the payload.
     */
    setUser: function(user) {
       globalUser = user;

       return Raven;
    }
};

/**** Private functions ****/
function parseUri(str) {
    var keys = 'source protocol authority userInfo user password host port relative path directory file query anchor'.split(' '),
        m = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str),
        uri = {},
        i = 14;

    while (i--) uri[keys[i]] = m[i] || '';

    return uri;
}

function isUndefined(what) {
    return typeof what === 'undefined';
}

function isFunction(what) {
    return typeof what === 'function';
}

function each(obj, callback) {
    var i, j;

    if (obj.length === undefined) {
        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                callback.call(null, i, obj[i]);
            }
        }
    } else {
        for (i = 0, j = obj.length; i < j; i++) {
            callback.call(null, i, obj[i]);
        }
    }
}

var cachedAuth;

function getAuthQueryString() {
    if (cachedAuth) return cachedAuth;

    var qs = [
        'sentry_version=2.0',
        'sentry_client=raven-js/' + Raven.VERSION
    ];
    if (globalKey) {
        qs.push('sentry_key=' + globalKey);
    }

    cachedAuth = '?' + qs.join('&');
    return cachedAuth;
}

function handleStackInfo(stackInfo, options) {
    var frames = [], i = stackInfo.stack.length;

    while (i--) frames[i] = normalizeFrame(stackInfo.stack[i]);

    processException(
        stackInfo.name,
        stackInfo.message,
        stackInfo.url,
        stackInfo.lineno,
        frames,
        options
    );
}

function normalizeFrame(frame) {
    // normalize the frames data
    var normalized = {
        abs_path:   frame.url,
        lineno:     frame.line,
        colno:      frame.column,
        'function': frame.func || '?'
    }, context = extractContextFromFrame(frame);

    if (context) {
        var i = 3, keys = ['pre_context', 'context_line', 'post_context'];
        while (i--) normalized[keys[i]] = context[i];
    }

    normalized.in_app = !/(Raven|TraceKit)\./.test(normalized['function']);

    return normalized;
}

function extractContextFromFrame(frame) {
    // immediately check if we should even attempt to parse a context
    if (!frame.context || !globalOptions.fetchContext) return;

    var context = frame.context,
        pivot = ~~(context.length / 2),
        i = context.length, isMinified = false, line;

    while (i--) {
        line = context[i];
        // We're making a guess to see if the source is minified or not.
        // To do that, we make the assumption if *any* of the lines passed
        // in are greater than 300 characters long, we bail.
        // Sentry will see that there isn't a context
        if (line.length > 300) {
            isMinified = true;
            break;
        }
    }

    if (isMinified) {
        // The source is minified and we don't know which column. Fuck it.
        if (isUndefined(frame.column)) return;

        // If the source is minified and has a frame column
        // we take a chunk of the offending line to hopefully shed some light
        return [
            [],  // no pre_context
            context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
            []   // no post_context
        ];
    }

    return [
        context.slice(0, pivot),    // pre_context
        context[pivot],             // context_line
        context.slice(pivot + 1)    // post_context
    ];
}

function processException(type, message, fileurl, lineno, frames, options) {
    var stacktrace, label, i;

    // IE8 really doesn't have Array.prototype.indexOf
    // Filter out a message that matches our ignore list
    i = globalOptions.ignoreErrors.length;
    while (i--) {
        if (message === globalOptions.ignoreErrors[i]) {
            return;
        }
    }

    if (frames && frames.length) {
        stacktrace = {frames: frames};
        fileurl = fileurl || frames[0].filename;
    } else if (fileurl) {
        stacktrace = {
            frames: [{
                filename: fileurl,
                lineno: lineno
            }]
        };
    }

    i = globalOptions.ignoreUrls.length;
    while (i--) {
        if (globalOptions.ignoreUrls[i].test(fileurl)) {
            return;
        }
    }

    label = lineno ? message + ' at ' + lineno : message;

    // Fire away!
    send(
        arrayMerge({
            'sentry.interfaces.Exception': {
                type: type,
                value: message
            },
            'sentry.interfaces.Stacktrace': stacktrace,
            culprit: fileurl,
            message: label
        }, options)
    );
}

function arrayMerge(arr1, arr2) {
    if (!arr2) {
        return arr1;
    }
    each(arr2, function(key, value){
        arr1[key] = value;
    });
    return arr1;
}

function getHttpData() {
    var url = window.location.protocol + '//' + window.location.host + window.location.pathname,
        querystring = window.location.search.slice(1),  // Remove the ?
        http;

    http = {
        url: url,
        querystring: querystring,
        headers: {
            'User-Agent': navigator.userAgent
        }
    };

    if (window.document.referrer) {
        http.headers.Referer = window.document.referrer;
    }

    return http;
}

function send(data) {
    if (!isSetup()) return;

    data = arrayMerge({
        project: globalProject,
        logger: globalOptions.logger,
        site: globalOptions.site,
        platform: 'javascript',
        'sentry.interfaces.Http': getHttpData()
    }, data);

    if (globalUser) data['sentry.interfaces.User'] = globalUser;

    if (isFunction(globalOptions.dataCallback)) {
        data = globalOptions.dataCallback(data);
    }

    makeRequest(data);
}

function makeRequest(data) {
    new Image().src = globalServer + getAuthQueryString() + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
}

function isSetup() {
    if (!hasJSON) return false;  // needs JSON support
    if (!globalServer) {
        console.error("Error: Raven has not been configured.");
        return false;
    }
    return true;
}
<|endoftext|>


<commit_before>// Raven.js
//
// Originally based on the Arecibo JavaScript client.
//
// Requires:
//     * Either jQuery (>1.5) or Zepto.js (>0.8).
//     * parseUri (included in the full and minified distribution files)

(function(){
    // Save a reference to the global object (`window` in the browser, `global`
    // on the server).
    var root = this;

    var Raven;
    root.Raven = Raven = {};

    var self = Raven;

    Raven.VERSION = '@VERSION';

    // jQuery, Zepto, or Ender owns the `$` variable.
    var $ = root.jQuery || root.Zepto || root.ender;

    Raven.options = {
        secretKey: undefined,  // The global key if not using project auth
        publicKey: undefined,  // Leave as undefined if not using project auth
        servers: [],
        projectId: 1,
        logger: 'javascript',
        site: undefined,
        signatureUrl: undefined,
        fetchHeaders: false,  // Generates a synchronous request to your server
        testMode: false,  // Disables some things that randomize the signature
        ignoreErrors: [],
        ignoreUrls: []
    };

    Raven.funcNameRE = /function\s*([\w\-$]+)?\s*\(/i;

    Raven.config = function(config) {
        var servers = [];

        if (typeof(config) === "string") {
            if (config.indexOf('http') === 0) {
                // new-style DSN configuration
                config = Raven.parseDSN(config);
            } else {
                throw "Base64 encoded config is no longer supported - use DSN";
            }
        }

        // XXX: is there a better place to put this?
        if (typeof($) === 'undefined') {
            throw "Unable to find required library (jQuery, Zepto, ender)";
        }
        if (root.jQuery === $ && $().jquery < '1.5.0') {
            throw "A newer version of jQuery is required";
        }

        $.each(config, function(key, option) {
            self.options[key] = option;
        });

        // Expand server base URLs into API URLs
        $.each(self.options['servers'], function(i, server) {
            // Add a trailing slash if one isn't provided
            if (server.slice(-1) !== '/') {
                server += '/';
            }
            servers.push(server + 'api/' + self.options['projectId'] + '/store/');
        });
        self.options['servers'] = servers;

    };

    Raven.parseDSN = function(dsn) {
        var uri = parseUri(dsn);
        var path_idx = uri.path.lastIndexOf('/');
        var project_id;
        var path;

        if (path_idx === -1) {
            project_id = uri.path.substr(1);
            path = '';
        } else {
            path = uri.path.substr(1, path_idx);
            project_id = uri.path.substr(path_idx + 1);
        }

        return {
            servers: [uri.protocol + '://' + uri.host + ':' + uri.port + '/' + path],
            publicKey: uri.user,
            secretKey: uri.password,
            projectId: project_id
        };
    };

    Raven.getHeaders = function() {
        var headers = {};

        if (self.options.fetchHeaders && !self.options.testMode) {
            headers = $.ajax({type: 'HEAD', url: root.location, async: false})
                       .getAllResponseHeaders();
        }

        headers["Referer"] = document.referrer;
        headers["User-Agent"] = navigator.userAgent;
        return headers;
    };

    Raven.parseHeaders = function(headers_string) {
        /*
         * Parse the header string returned from getAllResponseHeaders
         */
        var headers = {};
        $.each(headers_string.split('\n'), function(i, header) {
            var name = header.slice(0, header.indexOf(':')),
                value = header.slice(header.indexOf(':') + 2);
            headers[name] = value;
        });
        return headers;
    };

    Raven.getSignature = function(message, timestamp, callback) {
        if (self.options.signatureUrl) {
            $.post(self.options.signatureUrl, {
                message: message, timestamp: timestamp
            }, function(data) {
                callback(data.signature);
            });
        } else {
            callback();
        }
    };

    Raven.getAuthHeader = function(signature, timestamp) {
        var header = "Sentry sentry_version=2.0, ";
        header += "sentry_timestamp=" + timestamp + ", ";
        header += "sentry_client=raven-js/" + self.VERSION;
        if (self.options.publicKey) {
            header += ", sentry_key=" + self.options.publicKey;
        }
        if (signature) {
            header += ", sentry_signature=" + signature;
        }
        return header;
    };

    Raven.captureException = function(e) {
        var lineno, traceback, fileurl;

        if (e.line) {  // WebKit
            lineno = e.line;
        } else if (e.lineNumber) {  // Mozilla
            lineno = e.lineNumber;
        }

        if (e.sourceURL) {  // Webkit
            fileurl = e.sourceURL;
        } else if (e.fileName) {  // Mozilla
            fileurl = e.fileName;
        }

        if (e.arguments && e.stack) {
            traceback = this.chromeTraceback(e);
        } else if (e.stack) {
            // Detect edge cases where Chrome doesn't have 'arguments'
            if (e.stack.indexOf('@') == -1) {
                traceback = this.chromeTraceback(e);
            } else {
                traceback = this.firefoxOrSafariTraceback(e);
            }
        } else {
            traceback = [{"filename": fileurl, "lineno": lineno}];
            traceback = traceback.concat(this.otherTraceback(arguments.callee));
        }

        self.process(e, fileurl, lineno, traceback);
    };

    Raven.captureMessage = function(msg) {
        self.process(msg);
    };

    Raven.trimString = function(str) {
        return str.replace(/^\s+|\s+$/g, "");
    };

    Raven.chromeTraceback = function(e) {
        /*
         * First line is simply the repeated message:
         *   ReferenceError: aldfjalksdjf is not defined
         *
         * Following lines contain error context:
         *   at http://localhost:9000/1/group/306:41:5
         */
        var chunks, fn, filename, lineno, fileBits,
            traceback = [],
            lines = e.stack.split('\n');
        $.each(lines.slice(1), function(i, line) {
            // Trim the 'at ' from the beginning, and split by spaces
            chunks = Raven.trimString(line).slice(3);
            if (chunks == "unknown source") {
                return;  // Skip this one
            } else {
                chunks = chunks.split(' ');
            }

            if (chunks.length > 2) {
                // If there are more than 2 chunks, there are spaces in the
                // filename
                fn = chunks[0];
                filename = chunks.slice(1).join(' ');
                lineno = '(unknown)';
            } else if (chunks.length == 2) {
                // If there are two chunks, the first one is the function name
                fn = chunks[0];
                filename = chunks[1];
            } else {
                fn = '(unknown)';
                filename = chunks[0];
            }

            if (filename && filename !== '(unknown source)') {
                if (filename[0] === '(') {
                    // Remove parentheses
                    filename = filename.slice(1, -1);
                }
                // filename should be: <scheme>://<uri>:<line>:<column>
                // where :<column> is optional
                fileBits = filename.split(':');
                lineno = fileBits[2];
                filename = fileBits.slice(0, 2).join(':');
            }

            traceback.push({
                'function': fn,
                'filename': filename,
                'lineno': lineno
            });
        });
        return traceback;
    };

    Raven.firefoxOrSafariTraceback = function(e) {
        /*
         * Each line is a function with args and a filename, separated by an ampersand.
         *   unsubstantiatedClaim("I am Batman")@http://raven-js.com/test/exception.js:7
         *
         * Anonymous functions are presented without a name, but including args.
         *   (66)@http://raven-js.com/test/vendor/qunit.js:418
         *
         */
        var chunks, fn, args, filename, lineno,
            traceback = [],
            lines = e.stack.split('\n');
        $.each(lines, function(i, line) {
            if (line) {
                chunks = line.split('@');
                if (chunks[0]) {
                    fn = chunks[0].split('(');

                    if (fn.length > 1 && fn[1] != ')') {
                        args = fn[1].slice(0, -1).split(',');
                    } else {
                        args = undefined;
                    }

                    if (fn[0]) {
                        fn = fn[0];
                    } else {
                        fn = '(unknown)';
                    }
                } else {
                    fn = '(unknown)';
                }

                if (chunks.length > 1) {
                    filename = chunks[1].split(':');
                    lineno = filename.slice(-1)[0];
                    filename = filename.slice(0, -1).join(':');
                } else if (chunks[0] == '[native code]') {
                    fn = '(unknown)';
                    filename = '[native code]';
                    lineno = 0;
                    args = undefined;
                }

                traceback.push({
                    'function': fn,
                    'filename': filename,
                    'lineno': lineno,
                    'vars': {'arguments': args}
                });
            }
        });
        return traceback;
    };

    Raven.otherTraceback = function(callee) {
        /*
         * Generates best-efforts tracebacks for other browsers, such as Safari
         * or IE.
         */
        var fn, args,
            ANON = '<anonymous>',
            traceback = [],
            max = 9;
        while (callee && traceback.length < max) {
            fn = callee.name || (this.funcNameRE.test(callee.toString()) ? RegExp.$1 || ANON : ANON);
            if (callee.arguments) {
                args = this.stringifyArguments(callee.arguments);
            } else {
                args = undefined;
            }
            traceback.push({
                'filename': '(unknown source)',
                'lineno': '(unknown)',
                'function': fn,
                'post_context': callee.toString().split('\n'),
                'vars': {'arguments': args}
            });
            callee = callee.caller;
        }
        return traceback;
    };

    Raven.stringifyArguments = function(args) {
        /*
         * Converts a callee's arguments to strings
         */
        var fn,
            self = this,
            UNKNOWN = '<unknown>',
            results = [];

        $.each(args, function(i, arg) {
            if (arg === undefined) {
                results.push('undefined');
            } else if (arg === null) {
                results.push('null');
            } else if (arg instanceof Array) {
                results.push(self.stringifyArguments(arg));
            } else if (arg.constructor) {
                fn = arg.constructor.name || (self.funcNameRE.test(arg.constructor.toString()) ? RegExp.$1 || UNKNOWN : UNKNOWN);
                if (fn == 'String') {
                    results.push('"' + arg + '"');
                } else if (fn == 'Number' || fn == 'Date') {
                    results.push(arg);
                } else if (fn == 'Boolean') {
                    results.push(arg ? 'true' : 'false');
                } else {
                    results.push(fn);
                }
            } else {
                results.push(UNKNOWN);
            }
        });

        return results;
    };

    Raven.process = function(message, fileurl, lineno, traceback, timestamp) {
        var label, stacktrace, data, encoded_msg, type,
            url = root.location.protocol + '//' + root.location.host + root.location.pathname,
            querystring = root.location.search.slice(1);  // Remove the ?

        if (typeof(message) === 'object') {
            type = message.name;
            message = message.message;
        }
        if ($.inArray(message, self.options.ignoreErrors) >= 0) {
            return;
        }

        for (var i = 0; i < self.options.ignoreUrls.length; i++) {
            if (self.options.ignoreUrls[i].test(fileurl)) {
                return;
            }
        }

        label = lineno ? message + " at " + lineno : message;

        if (traceback) {
            stacktrace = {"frames": traceback};
            fileurl = fileurl || traceback[0].filename;
        } else if (fileurl) {
            stacktrace = {
                "frames": [{
                    "filename": fileurl,
                    "lineno": lineno
                }]
            };
        }

        data = {
            "message": label,
            "culprit": fileurl,
            "sentry.interfaces.Stacktrace": stacktrace,
            "sentry.interfaces.Exception": {
                "type": type,
                "value": message
            },
            "project": self.options.projectId,
            "logger": self.options.logger,
            "site": self.options.site
        };

        data["sentry.interfaces.Http"] = {
            "url": url,
            "querystring": querystring,
            "headers": self.getHeaders()
        };

        timestamp = timestamp || (new Date()).getTime();
        encoded_msg = JSON.stringify(data);
        self.getSignature(encoded_msg, timestamp, function(signature) {
            var header = self.getAuthHeader(signature, timestamp);
            $.each(self.options.servers, function (i, server) {
                $.ajax({
                    type: 'POST',
                    url: server,
                    data: encoded_msg,
                    headers: {
                        // We send both headers, since Authentication may be blocked,
                        // and custom headers arent supported in IE9
                        'X-Sentry-Auth': header,
                        'Authentication': header
                    }
                });
            });
        });
    };
}).call(this);
<commit_msg>Improve jquery and external lib checks and perform them at runtime<commit_after>// Raven.js
//
// Originally based on the Arecibo JavaScript client.
//
// Requires:
//     * Either jQuery (>1.5) or Zepto.js (>0.8).
//     * parseUri (included in the full and minified distribution files)

(function(){
    // Save a reference to the global object (`window` in the browser, `global`
    // on the server).
    var root = this;

    var Raven;
    root.Raven = Raven = {};

    var self = Raven;

    Raven.VERSION = '@VERSION';

    // jQuery, Zepto, or Ender owns the `$` variable.
    var $ = root.jQuery || root.Zepto || root.ender;
    if (typeof($) === 'undefined') {
        throw "Raven requires one of the following libraries: jQuery, Zepto, or ender";
    }
    if (root.jQuery === $ && $.fn.jquery < '1.5.0') {
        throw "A newer version of jQuery is required";
    }

    Raven.options = {
        secretKey: undefined,  // The global key if not using project auth
        publicKey: undefined,  // Leave as undefined if not using project auth
        servers: [],
        projectId: 1,
        logger: 'javascript',
        site: undefined,
        signatureUrl: undefined,
        fetchHeaders: false,  // Generates a synchronous request to your server
        testMode: false,  // Disables some things that randomize the signature
        ignoreErrors: [],
        ignoreUrls: []
    };

    Raven.funcNameRE = /function\s*([\w\-$]+)?\s*\(/i;

    Raven.config = function(config) {
        var servers = [];

        if (typeof(config) === "string") {
            if (config.indexOf('http') === 0) {
                // new-style DSN configuration
                config = Raven.parseDSN(config);
            } else {
                throw "Base64 encoded config is no longer supported - use DSN";
            }
        }

        $.each(config, function(key, option) {
            self.options[key] = option;
        });

        // Expand server base URLs into API URLs
        $.each(self.options['servers'], function(i, server) {
            // Add a trailing slash if one isn't provided
            if (server.slice(-1) !== '/') {
                server += '/';
            }
            servers.push(server + 'api/' + self.options['projectId'] + '/store/');
        });
        self.options['servers'] = servers;

    };

    Raven.parseDSN = function(dsn) {
        var uri = parseUri(dsn);
        var path_idx = uri.path.lastIndexOf('/');
        var project_id;
        var path;

        if (path_idx === -1) {
            project_id = uri.path.substr(1);
            path = '';
        } else {
            path = uri.path.substr(1, path_idx);
            project_id = uri.path.substr(path_idx + 1);
        }

        return {
            servers: [uri.protocol + '://' + uri.host + ':' + uri.port + '/' + path],
            publicKey: uri.user,
            secretKey: uri.password,
            projectId: project_id
        };
    };

    Raven.getHeaders = function() {
        var headers = {};

        if (self.options.fetchHeaders && !self.options.testMode) {
            headers = $.ajax({type: 'HEAD', url: root.location, async: false})
                       .getAllResponseHeaders();
        }

        headers["Referer"] = document.referrer;
        headers["User-Agent"] = navigator.userAgent;
        return headers;
    };

    Raven.parseHeaders = function(headers_string) {
        /*
         * Parse the header string returned from getAllResponseHeaders
         */
        var headers = {};
        $.each(headers_string.split('\n'), function(i, header) {
            var name = header.slice(0, header.indexOf(':')),
                value = header.slice(header.indexOf(':') + 2);
            headers[name] = value;
        });
        return headers;
    };

    Raven.getSignature = function(message, timestamp, callback) {
        if (self.options.signatureUrl) {
            $.post(self.options.signatureUrl, {
                message: message, timestamp: timestamp
            }, function(data) {
                callback(data.signature);
            });
        } else {
            callback();
        }
    };

    Raven.getAuthHeader = function(signature, timestamp) {
        var header = "Sentry sentry_version=2.0, ";
        header += "sentry_timestamp=" + timestamp + ", ";
        header += "sentry_client=raven-js/" + self.VERSION;
        if (self.options.publicKey) {
            header += ", sentry_key=" + self.options.publicKey;
        }
        if (signature) {
            header += ", sentry_signature=" + signature;
        }
        return header;
    };

    Raven.captureException = function(e) {
        var lineno, traceback, fileurl;

        if (e.line) {  // WebKit
            lineno = e.line;
        } else if (e.lineNumber) {  // Mozilla
            lineno = e.lineNumber;
        }

        if (e.sourceURL) {  // Webkit
            fileurl = e.sourceURL;
        } else if (e.fileName) {  // Mozilla
            fileurl = e.fileName;
        }

        if (e.arguments && e.stack) {
            traceback = this.chromeTraceback(e);
        } else if (e.stack) {
            // Detect edge cases where Chrome doesn't have 'arguments'
            if (e.stack.indexOf('@') == -1) {
                traceback = this.chromeTraceback(e);
            } else {
                traceback = this.firefoxOrSafariTraceback(e);
            }
        } else {
            traceback = [{"filename": fileurl, "lineno": lineno}];
            traceback = traceback.concat(this.otherTraceback(arguments.callee));
        }

        self.process(e, fileurl, lineno, traceback);
    };

    Raven.captureMessage = function(msg) {
        self.process(msg);
    };

    Raven.trimString = function(str) {
        return str.replace(/^\s+|\s+$/g, "");
    };

    Raven.chromeTraceback = function(e) {
        /*
         * First line is simply the repeated message:
         *   ReferenceError: aldfjalksdjf is not defined
         *
         * Following lines contain error context:
         *   at http://localhost:9000/1/group/306:41:5
         */
        var chunks, fn, filename, lineno, fileBits,
            traceback = [],
            lines = e.stack.split('\n');
        $.each(lines.slice(1), function(i, line) {
            // Trim the 'at ' from the beginning, and split by spaces
            chunks = Raven.trimString(line).slice(3);
            if (chunks == "unknown source") {
                return;  // Skip this one
            } else {
                chunks = chunks.split(' ');
            }

            if (chunks.length > 2) {
                // If there are more than 2 chunks, there are spaces in the
                // filename
                fn = chunks[0];
                filename = chunks.slice(1).join(' ');
                lineno = '(unknown)';
            } else if (chunks.length == 2) {
                // If there are two chunks, the first one is the function name
                fn = chunks[0];
                filename = chunks[1];
            } else {
                fn = '(unknown)';
                filename = chunks[0];
            }

            if (filename && filename !== '(unknown source)') {
                if (filename[0] === '(') {
                    // Remove parentheses
                    filename = filename.slice(1, -1);
                }
                // filename should be: <scheme>://<uri>:<line>:<column>
                // where :<column> is optional
                fileBits = filename.split(':');
                lineno = fileBits[2];
                filename = fileBits.slice(0, 2).join(':');
            }

            traceback.push({
                'function': fn,
                'filename': filename,
                'lineno': lineno
            });
        });
        return traceback;
    };

    Raven.firefoxOrSafariTraceback = function(e) {
        /*
         * Each line is a function with args and a filename, separated by an ampersand.
         *   unsubstantiatedClaim("I am Batman")@http://raven-js.com/test/exception.js:7
         *
         * Anonymous functions are presented without a name, but including args.
         *   (66)@http://raven-js.com/test/vendor/qunit.js:418
         *
         */
        var chunks, fn, args, filename, lineno,
            traceback = [],
            lines = e.stack.split('\n');
        $.each(lines, function(i, line) {
            if (line) {
                chunks = line.split('@');
                if (chunks[0]) {
                    fn = chunks[0].split('(');

                    if (fn.length > 1 && fn[1] != ')') {
                        args = fn[1].slice(0, -1).split(',');
                    } else {
                        args = undefined;
                    }

                    if (fn[0]) {
                        fn = fn[0];
                    } else {
                        fn = '(unknown)';
                    }
                } else {
                    fn = '(unknown)';
                }

                if (chunks.length > 1) {
                    filename = chunks[1].split(':');
                    lineno = filename.slice(-1)[0];
                    filename = filename.slice(0, -1).join(':');
                } else if (chunks[0] == '[native code]') {
                    fn = '(unknown)';
                    filename = '[native code]';
                    lineno = 0;
                    args = undefined;
                }

                traceback.push({
                    'function': fn,
                    'filename': filename,
                    'lineno': lineno,
                    'vars': {'arguments': args}
                });
            }
        });
        return traceback;
    };

    Raven.otherTraceback = function(callee) {
        /*
         * Generates best-efforts tracebacks for other browsers, such as Safari
         * or IE.
         */
        var fn, args,
            ANON = '<anonymous>',
            traceback = [],
            max = 9;
        while (callee && traceback.length < max) {
            fn = callee.name || (this.funcNameRE.test(callee.toString()) ? RegExp.$1 || ANON : ANON);
            if (callee.arguments) {
                args = this.stringifyArguments(callee.arguments);
            } else {
                args = undefined;
            }
            traceback.push({
                'filename': '(unknown source)',
                'lineno': '(unknown)',
                'function': fn,
                'post_context': callee.toString().split('\n'),
                'vars': {'arguments': args}
            });
            callee = callee.caller;
        }
        return traceback;
    };

    Raven.stringifyArguments = function(args) {
        /*
         * Converts a callee's arguments to strings
         */
        var fn,
            self = this,
            UNKNOWN = '<unknown>',
            results = [];

        $.each(args, function(i, arg) {
            if (arg === undefined) {
                results.push('undefined');
            } else if (arg === null) {
                results.push('null');
            } else if (arg instanceof Array) {
                results.push(self.stringifyArguments(arg));
            } else if (arg.constructor) {
                fn = arg.constructor.name || (self.funcNameRE.test(arg.constructor.toString()) ? RegExp.$1 || UNKNOWN : UNKNOWN);
                if (fn == 'String') {
                    results.push('"' + arg + '"');
                } else if (fn == 'Number' || fn == 'Date') {
                    results.push(arg);
                } else if (fn == 'Boolean') {
                    results.push(arg ? 'true' : 'false');
                } else {
                    results.push(fn);
                }
            } else {
                results.push(UNKNOWN);
            }
        });

        return results;
    };

    Raven.process = function(message, fileurl, lineno, traceback, timestamp) {
        var label, stacktrace, data, encoded_msg, type,
            url = root.location.protocol + '//' + root.location.host + root.location.pathname,
            querystring = root.location.search.slice(1);  // Remove the ?

        if (typeof(message) === 'object') {
            type = message.name;
            message = message.message;
        }
        if ($.inArray(message, self.options.ignoreErrors) >= 0) {
            return;
        }

        for (var i = 0; i < self.options.ignoreUrls.length; i++) {
            if (self.options.ignoreUrls[i].test(fileurl)) {
                return;
            }
        }

        label = lineno ? message + " at " + lineno : message;

        if (traceback) {
            stacktrace = {"frames": traceback};
            fileurl = fileurl || traceback[0].filename;
        } else if (fileurl) {
            stacktrace = {
                "frames": [{
                    "filename": fileurl,
                    "lineno": lineno
                }]
            };
        }

        data = {
            "message": label,
            "culprit": fileurl,
            "sentry.interfaces.Stacktrace": stacktrace,
            "sentry.interfaces.Exception": {
                "type": type,
                "value": message
            },
            "project": self.options.projectId,
            "logger": self.options.logger,
            "site": self.options.site
        };

        data["sentry.interfaces.Http"] = {
            "url": url,
            "querystring": querystring,
            "headers": self.getHeaders()
        };

        timestamp = timestamp || (new Date()).getTime();
        encoded_msg = JSON.stringify(data);
        self.getSignature(encoded_msg, timestamp, function(signature) {
            var header = self.getAuthHeader(signature, timestamp);
            $.each(self.options.servers, function (i, server) {
                $.ajax({
                    type: 'POST',
                    url: server,
                    data: encoded_msg,
                    headers: {
                        // We send both headers, since Authentication may be blocked,
                        // and custom headers arent supported in IE9
                        'X-Sentry-Auth': header,
                        'Authentication': header
                    }
                });
            });
        });
    };
}).call(this);
<|endoftext|>


<commit_before>// ngaro module
var ngaro = require('./ngaro.js');
// node modules
var fs = require('fs');
var path = require('path');

// start retro.js
if (require.main === module) {
    run();
}

function dump(){

    var dumpArray = convertArray(ngaro.ram.image);
    console.log(String.fromCharCode(28));
    console.log(dumpArray.join(" "));
    console.log(String.fromCharCode(29));
    dumpArray = convertArray(ngaro.address.data);
    console.log(dumpArray.join(" "));
    console.log(String.fromCharCode(29));
    dumpArray = convertArray(ngaro.data.data);
    console.log(dumpArray.join(" "));
}

function convertArray(typedArray){

    var newArray = [];
    for(var i = 0; i < typedArray.length; i++){
        newArray.push(typedArray[i]);
    }
    return newArray;
}

function run(){

    var imageFile;
    var imageFileCheck;
    var dump_after = false;
    var num = 2;

    while (num < process.argv.length){
        var args = process.argv[num];
        if (args === '--with') {
            //needs implementation
        } else if (args === '--dump'){
            dump_after = true;
        } else if (args === '--image'){
            num++;
            args = process.argv[num];
            imageFileCheck = fs.existsSync(args,function(exists){});
            if(imageFileCheck){
                imageFile = args;
            } else {
                console.log('File not found');
                process.exit(2);
            }
        }
        num++;
    }

    if(!imageFile) {
        imageFile = path.resolve(__dirname,'retro-11.5.img');
    }

    var fileInfo = fs.statSync(imageFile);
    var cells = Math.ceil(fileInfo.size/4);
    var imageArray = new Array();
    var fd = fs.openSync(imageFile,'r');

    if (!fd) {
        console.log('Unable to open file');
    } else {
        var bufsize = cells*4;
        var buffer = new Buffer(bufsize);
        fs.readSync(fd,buffer,0,bufsize,0);
        for (var i = 0; i < cells; i++) {
            imageArray[i] = buffer.readInt32LE(i*4);
        }
        fs.close(fd);
        ngaro.setImage(imageArray);
        ngaro.rxProcessImage();
    }

    if(!dump_after){
       //do other stuff
    } else {
       dump();
    }
}
<commit_msg>retro.js : cleaned up display of the stacks to pass ngarotests.py<commit_after>var
  fs = require('fs'),
  path = require('path'),
  ngaro = require('./ngaro.js');

/**
 * join a typed array with spaces
 */
function join(a) {
  var chars = [ ];
  for(var i = 0; i < a.length; i++) {
    chars.push(a[i]);
  }
  return chars.join(' ');
}

function chr(n) {
  return String.fromCharCode(n);
}

/**
 * dump the virtual machine state, for ngarotest.py
 */
function dump() {
  console.log([
    chr(28),
    join(ngaro.data.data.slice(1, ngaro.data.sp + 1 )),
    chr(29),
    join(ngaro.address.data.slice(1, ngaro.address.sp + 1 )),
    chr(29),
    join(ngaro.ram.image)
  ].join(''));
}

function run(){

    var imageFile;
    var imageFileCheck;
    var dump_after = false;
    var num = 2;

    // parse args
    while (num < process.argv.length){
        var args = process.argv[num];
        if (args === '--with') {
            //needs implementation
        } else if (args === '--dump'){
            dump_after = true;
        } else if (args === '--image'){
            num++;
            args = process.argv[num];
            imageFileCheck = fs.existsSync(args,function(exists){});
            if(imageFileCheck){
                imageFile = args;
            } else {
                console.log('File not found');
                process.exit(2);
            }
        }
        num++;
    }

    // default image
    if(!imageFile) {
        imageFile = path.resolve(__dirname,'retro-11.5.img');
    }

    // load the specified image
    var fileInfo = fs.statSync(imageFile);
    var cells = Math.ceil(fileInfo.size/4);
    var fd = fs.openSync(imageFile,'r');
    var ok = false;
    var imageArray;

    if (!fd) {
        console.log('Unable to open file');
    } else {
        var bufsize = cells*4;
        var buffer = new Buffer(bufsize);
        fs.readSync(fd,buffer,0,bufsize,0);

	imageArray = new Int32Array(cells);
        for (var i = 0; i < cells; i++) {
            imageArray[i] = buffer.readInt32LE(i*4);
        }
        fs.close(fd);
	ok = true;
    }

    if ( ok ) {
        ngaro.setImage(imageArray);
        ngaro.rxPrepareVM();
        ngaro.rxProcessImage();
        if(dump_after) {
           dump(cells);
        }
    }
}

// start retro.js
if (require.main === module) {
  run();
}
<|endoftext|>