<commit_before>'use strict';
import path from 'path';
import bbox from '@turf/bbox';
import centerOfMass from '@turf/center-of-mass';
import _ from 'lodash';

import config from '../../config';
import db from '../../db/';
import Operation from '../../utils/operation';
import { getJSONFileContents, putFileStream } from '../../s3/utils';
// import { getFileContents, getJSONFileContents } from '../../s3/utils';
// import { importRoadNetwork } from '../rra-osm-p2p';
import AppLogger from '../../utils/app-logger';
import * as overpass from '../../utils/overpass';

const DEBUG = config.debug;
let appLogger = AppLogger({ output: DEBUG });
let logger;

process.on('message', function (e) {
  // Capture all the errors.
  try {
    logger = appLogger.group(`p${e.projId} s${e.scId} proj-setup`);
    logger.log('init');
    e.callback = (err) => {
      if (err) return process.exit(1);
      else process.exit(0);
    };
    concludeProjectSetup(e);
  } catch (err) {
    process.send({type: 'error', data: err.message, stack: err.stack});
    throw err;
  }
});

// The project setup script is setup so that it run on a different node process
// using fork. This allows us to offload the main server not causing blocking
// operations.

/**
 * Finishes the project setup by processing all the needed files:
 * Road network:
 *   - Convert the osm file to a changeset and import it to the osm-p2p-db
 * Admin Bound:
 *   - Extract all the village names, and store them on the database. This is
 *   needed to later select what admin areas are to be processed.
 *
 * @param  {object} e       Data.
 *         e.opId           Operation Id. It has to be already started.
 *         e.projId         Project Id.
 *         e.scId           Scenario Id.
 *         e.callback
 */
export function concludeProjectSetup (e) {
  const {opId, projId, scId, callback} = e;

  function processAdminAreas (adminBoundsFc) {
    logger && logger.log('process admin areas');

    let adminAreaTask = () => {
      return db.transaction(function (trx) {
        if (!adminBoundsFc.features) {
          throw new Error('Invalid administrative boundaries file');
        }
        let adminAreas = _(adminBoundsFc.features)
          .filter(o => !!o.properties.name && o.geometry.type !== 'Point')
          .sortBy(o => _.kebabCase(o.properties.name))
          .map(o => {
            return {
              name: o.properties.name,
              type: o.properties.type || 'Admin Area',
              geometry: JSON.stringify(o.geometry.coordinates),
              project_id: projId
            };
          })
          .value();

        let adminAreasBbox = bbox(adminBoundsFc);

        return Promise.all([
          trx('projects')
            .update({
              bbox: JSON.stringify(adminAreasBbox),
              updated_at: (new Date())
            })
            .where('id', projId),

          trx.batchInsert('projects_aa', adminAreas)
            .returning('id'),

          trx('scenarios_settings')
            .insert({
              scenario_id: scId,
              key: 'admin_areas',
              value: '[]',
              created_at: (new Date()),
              updated_at: (new Date())
            })
            .where('id', projId)
        ]);
      });
    };

    // Clean the tables so any remnants of previous attempts are removed.
    // This avoids primary keys collisions.
    let cleanAATable = () => {
      return Promise.all([
        db('projects_aa')
          .where('project_id', projId)
          .del(),
        db('scenarios_settings')
          .where('scenario_id', scId)
          .where('key', 'admin_areas')
          .del()
      ]);
    };

    return op.log('process:admin-bounds', {message: 'Processing admin areas'})
      .then(() => cleanAATable())
      .then(() => adminAreaTask());
  }

  function processOrigins (originsData) {
    logger && logger.log('process origins');

    let originsTask = () => {
      let indicators = originsData.data.indicators;
      let neededProps = indicators.map(o => o.key);
      neededProps.push('name');

      return getJSONFileContents(originsData.path)
        .then(originsFC => {
          logger && logger.log('origins before filter', originsFC.features.length);
          let features = originsFC.features.filter(feat => {
            let props = Object.keys(feat.properties);
            return neededProps.every(o => props.indexOf(o) !== -1);
          });

          logger && logger.log('origins after filter', features.length);

          let originsIndicators = [];
          let origins = features.map(feat => {
            let coordinates = feat.geometry.type === 'Point'
              ? feat.geometry.coordinates
              : centerOfMass(feat).geometry.coordinates;

            // Will be flattened later.
            // The array is constructed in this way so we can match the index of the
            // results array and attribute the correct id.
            let featureIndicators = indicators.map(ind => ({
              key: ind.key,
              label: ind.label,
              value: parseInt(feat.properties[ind.key])
            }));
            originsIndicators.push(featureIndicators);

            return {
              project_id: projId,
              name: feat.properties.name,
              coordinates: JSON.stringify(coordinates)
            };
          });

          return db.transaction(function (trx) {
            return trx.batchInsert('projects_origins', origins)
              .returning('id')
              .then(ids => {
                // Add ids to the originsIndicators and flatten the array in the process.
                let flat = [];
                originsIndicators.forEach((resInd, resIdx) => {
                  resInd.forEach(ind => {
                    ind.origin_id = ids[resIdx];
                    flat.push(ind);
                  });
                });
                return flat;
              })
              .then(data => trx.batchInsert('projects_origins_indicators', data));
          });
        });
    };

    // Clean the tables so any remnants of previous attempts are removed.
    // This avoids primary keys collisions.
    let cleanOriginsTable = () => {
      return db('projects_origins')
        .where('project_id', projId)
        .del();
    };

    return op.log('process:origins', {message: 'Processing origins'})
      .then(() => cleanOriginsTable())
      .then(() => originsTask());
  }

  function importRoadNetwork (bbox) {
    return op.log('process:road-network', {message: 'Importing road network from OSM'})
      .then(() => overpass.importRoadNetwork(bbox))
      .then(osmData => {
        // Insert file into DB.
        let fileName = `road-network_${Date.now()}`;
        let filePath = `scenario-${scId}/${fileName}`;
        let data = {
          name: fileName,
          type: 'road-network',
          path: filePath,
          project_id: projId,
          scenario_id: scId,
          created_at: (new Date()),
          updated_at: (new Date())
        };

        return putFileStream(filePath, osmData)
          .then(() => db('scenarios_files').insert(data));
      });
  }

  let op = new Operation(db);
  op.loadById(opId)
  .then(() => Promise.all([
    // Get source for Road Network.
    db('scenarios_source_data')
      .select('*')
      .where('scenario_id', scId)
      .where('name', 'road-network')
      .first(),
    // db('scenarios_files')
    //   .select('*')
    //   .where('project_id', projId)
    //   .where('type', 'road-network')
    //   .first()
    //   .then(file => getFileContents(file.path)),
    db('projects_files')
      .select('*')
      .where('project_id', projId)
      .whereIn('type', ['admin-bounds', 'origins'])
      .orderBy('type')
      .then(files => {
        // Get the data from the admin bounds file immediately but pass
        // the full data for the origins file because other values from the db
        // are needed.
        let [adminBoundsData, originsData] = files;
        return getJSONFileContents(adminBoundsData.path)
          .then(adminBoundsContent => ([adminBoundsContent, originsData]));
      })
  ]))
  .then(filesContent => {
    // let [roadNetwork, [adminBoundsFc, originsData]] = filesContent;
    let [rnSource, [adminBoundsFc, originsData]] = filesContent;

    let rnProcessPromise;
    switch (rnSource.type) {
      case 'file':
        // We'll need to get the files contents to import to
        // the osm-p2p-db. Eventually...
        rnProcessPromise = Promise.resolve();
        break;
      case 'osm':
        rnProcessPromise = importRoadNetwork(overpass.fcBbox(adminBoundsFc));
        break;
      default:
        throw new Error(`Invalid source type for road-network`);
    }

    // Run the tasks in series rather than in parallel.
    // This is better for error handling. If they run in parallel and
    // `processAdminAreas` errors, the script hangs a bit while
    // `processRoadNetwork` (which is resource intensive) finished and only then
    // the error is captured by the promise.
    // Since processing the admin areas is a pretty fast operation, the
    // performance is not really affected.
    return rnProcessPromise
      .then(() => Promise.all([
        processAdminAreas(adminBoundsFc),
        processOrigins(originsData)
      ]));
      // .then(() => {
      //   logger && logger.log('process road network');
      //   return importRoadNetwork(projId, scId, op, roadNetwork);
      // });
  })
  .then(() => {
    return db.transaction(function (trx) {
      return Promise.all([
        trx('projects')
          .update({updated_at: (new Date()), status: 'active'})
          .where('id', projId),
        trx('scenarios')
          .update({updated_at: (new Date()), status: 'active'})
          .where('id', scId)
      ])
      .then(() => op.log('success', {message: 'Operation complete'}).then(op => op.finish()));
    });
  })
  .then(() => {
    logger && logger.log('process complete');
    DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../project-setup_p${projId}s${scId}.log`));
    callback();
  })
  .catch(err => {
    logger && logger.log('error', err);
    DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../project-setup_p${projId}s${scId}.log`));
    return op.log('error', {error: err.message})
      .then(op => op.finish())
      .then(() => callback(err.message), () => callback(err.message));
  });
}
<commit_msg>Initial code for poi import from osm<commit_after>'use strict';
import path from 'path';
import bbox from '@turf/bbox';
import centerOfMass from '@turf/center-of-mass';
import _ from 'lodash';

import config from '../../config';
import db from '../../db/';
import Operation from '../../utils/operation';
import { getJSONFileContents, putFileStream } from '../../s3/utils';
// import { getFileContents, getJSONFileContents } from '../../s3/utils';
// import { importRoadNetwork } from '../rra-osm-p2p';
import AppLogger from '../../utils/app-logger';
import * as overpass from '../../utils/overpass';

const DEBUG = config.debug;
let appLogger = AppLogger({ output: DEBUG });
let logger;

process.on('message', function (e) {
  // Capture all the errors.
  try {
    logger = appLogger.group(`p${e.projId} s${e.scId} proj-setup`);
    logger.log('init');
    e.callback = (err) => {
      if (err) return process.exit(1);
      else process.exit(0);
    };
    concludeProjectSetup(e);
  } catch (err) {
    process.send({type: 'error', data: err.message, stack: err.stack});
    throw err;
  }
});

// The project setup script is setup so that it run on a different node process
// using fork. This allows us to offload the main server not causing blocking
// operations.

/**
 * Finishes the project setup by processing all the needed files:
 * Road network:
 *   - Convert the osm file to a changeset and import it to the osm-p2p-db
 * Admin Bound:
 *   - Extract all the village names, and store them on the database. This is
 *   needed to later select what admin areas are to be processed.
 *
 * @param  {object} e       Data.
 *         e.opId           Operation Id. It has to be already started.
 *         e.projId         Project Id.
 *         e.scId           Scenario Id.
 *         e.callback
 */
export function concludeProjectSetup (e) {
  const {opId, projId, scId, callback} = e;

  function processAdminAreas (adminBoundsFc) {
    logger && logger.log('process admin areas');

    let adminAreaTask = () => {
      return db.transaction(function (trx) {
        if (!adminBoundsFc.features) {
          throw new Error('Invalid administrative boundaries file');
        }
        let adminAreas = _(adminBoundsFc.features)
          .filter(o => !!o.properties.name && o.geometry.type !== 'Point')
          .sortBy(o => _.kebabCase(o.properties.name))
          .map(o => {
            return {
              name: o.properties.name,
              type: o.properties.type || 'Admin Area',
              geometry: JSON.stringify(o.geometry.coordinates),
              project_id: projId
            };
          })
          .value();

        let adminAreasBbox = bbox(adminBoundsFc);

        return Promise.all([
          trx('projects')
            .update({
              bbox: JSON.stringify(adminAreasBbox),
              updated_at: (new Date())
            })
            .where('id', projId),

          trx.batchInsert('projects_aa', adminAreas)
            .returning('id'),

          trx('scenarios_settings')
            .insert({
              scenario_id: scId,
              key: 'admin_areas',
              value: '[]',
              created_at: (new Date()),
              updated_at: (new Date())
            })
            .where('id', projId)
        ]);
      });
    };

    // Clean the tables so any remnants of previous attempts are removed.
    // This avoids primary keys collisions.
    let cleanAATable = () => {
      return Promise.all([
        db('projects_aa')
          .where('project_id', projId)
          .del(),
        db('scenarios_settings')
          .where('scenario_id', scId)
          .where('key', 'admin_areas')
          .del()
      ]);
    };

    return op.log('process:admin-bounds', {message: 'Processing admin areas'})
      .then(() => cleanAATable())
      .then(() => adminAreaTask());
  }

  function processOrigins (originsData) {
    logger && logger.log('process origins');

    let originsTask = () => {
      let indicators = originsData.data.indicators;
      let neededProps = indicators.map(o => o.key);
      neededProps.push('name');

      return getJSONFileContents(originsData.path)
        .then(originsFC => {
          logger && logger.log('origins before filter', originsFC.features.length);
          let features = originsFC.features.filter(feat => {
            let props = Object.keys(feat.properties);
            return neededProps.every(o => props.indexOf(o) !== -1);
          });

          logger && logger.log('origins after filter', features.length);

          let originsIndicators = [];
          let origins = features.map(feat => {
            let coordinates = feat.geometry.type === 'Point'
              ? feat.geometry.coordinates
              : centerOfMass(feat).geometry.coordinates;

            // Will be flattened later.
            // The array is constructed in this way so we can match the index of the
            // results array and attribute the correct id.
            let featureIndicators = indicators.map(ind => ({
              key: ind.key,
              label: ind.label,
              value: parseInt(feat.properties[ind.key])
            }));
            originsIndicators.push(featureIndicators);

            return {
              project_id: projId,
              name: feat.properties.name,
              coordinates: JSON.stringify(coordinates)
            };
          });

          return db.transaction(function (trx) {
            return trx.batchInsert('projects_origins', origins)
              .returning('id')
              .then(ids => {
                // Add ids to the originsIndicators and flatten the array in the process.
                let flat = [];
                originsIndicators.forEach((resInd, resIdx) => {
                  resInd.forEach(ind => {
                    ind.origin_id = ids[resIdx];
                    flat.push(ind);
                  });
                });
                return flat;
              })
              .then(data => trx.batchInsert('projects_origins_indicators', data));
          });
        });
    };

    // Clean the tables so any remnants of previous attempts are removed.
    // This avoids primary keys collisions.
    let cleanOriginsTable = () => {
      return db('projects_origins')
        .where('project_id', projId)
        .del();
    };

    return op.log('process:origins', {message: 'Processing origins'})
      .then(() => cleanOriginsTable())
      .then(() => originsTask());
  }

  function importRoadNetwork (bbox) {
    return op.log('process:road-network', {message: 'Importing road network from OSM'})
      .then(() => overpass.importRoadNetwork(bbox))
      .then(osmData => {
        // Insert file into DB.
        let fileName = `road-network_${Date.now()}`;
        let filePath = `scenario-${scId}/${fileName}`;
        let data = {
          name: fileName,
          type: 'road-network',
          path: filePath,
          project_id: projId,
          scenario_id: scId,
          created_at: (new Date()),
          updated_at: (new Date())
        };

        return putFileStream(filePath, osmData)
          .then(() => db('scenarios_files').insert(data));
      });
  }

  function importPOIs (bbox) {
    return op.log('process:poi', {message: 'Importing poi from OSM'})
      .then(() => overpass.importPOI(bbox))
      .then(osmData => {
        console.log('osmData', osmData);
      });
  }

  let op = new Operation(db);
  op.loadById(opId)
  .then(() => Promise.all([
    // Get source for Road Network.
    db('scenarios_source_data')
      .select('*')
      .where('scenario_id', scId)
      .whereIn('name', ['poi', 'road-network'])
      .orderBy('name'),
    // db('scenarios_files')
    //   .select('*')
    //   .where('project_id', projId)
    //   .where('type', 'road-network')
    //   .first()
    //   .then(file => getFileContents(file.path)),
    db('projects_files')
      .select('*')
      .where('project_id', projId)
      .whereIn('type', ['admin-bounds', 'origins'])
      .orderBy('type')
      .then(files => {
        // Get the data from the admin bounds file immediately but pass
        // the full data for the origins file because other values from the db
        // are needed.
        let [adminBoundsData, originsData] = files;
        return getJSONFileContents(adminBoundsData.path)
          .then(adminBoundsContent => ([adminBoundsContent, originsData]));
      })
  ]))
  .then(filesContent => {
    // let [roadNetwork, [adminBoundsFc, originsData]] = filesContent;
    let [[poiSource, rnSource], [adminBoundsFc, originsData]] = filesContent;

    let rnProcessPromise = rnSource.type === 'osm'
      ? () => importRoadNetwork(overpass.fcBbox(adminBoundsFc))
      // We'll need to get the files contents to import to
      // the osm-p2p-db. Eventually...
      : () => Promise.resolve();

    let poiProcessPromise = poiSource.type === 'osm'
      ? () => importPOIs(overpass.fcBbox(adminBoundsFc), poiSource.data.osmPoiTypes)
      : () => Promise.resolve();

    // Run the tasks in series rather than in parallel.
    // This is better for error handling. If they run in parallel and
    // `processAdminAreas` errors, the script hangs a bit while
    // `processRoadNetwork` (which is resource intensive) finished and only then
    // the error is captured by the promise.
    // Since processing the admin areas is a pretty fast operation, the
    // performance is not really affected.
    return rnProcessPromise()
      .then(() => poiProcessPromise())
      .then(() => Promise.all([
        processAdminAreas(adminBoundsFc),
        processOrigins(originsData)
      ]));
      // .then(() => {
      //   logger && logger.log('process road network');
      //   return importRoadNetwork(projId, scId, op, roadNetwork);
      // });
  })
  .then(() => {
    return db.transaction(function (trx) {
      return Promise.all([
        trx('projects')
          .update({updated_at: (new Date()), status: 'active'})
          .where('id', projId),
        trx('scenarios')
          .update({updated_at: (new Date()), status: 'active'})
          .where('id', scId)
      ])
      .then(() => op.log('success', {message: 'Operation complete'}).then(op => op.finish()));
    });
  })
  .then(() => {
    logger && logger.log('process complete');
    DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../project-setup_p${projId}s${scId}.log`));
    callback();
  })
  .catch(err => {
    logger && logger.log('error', err);
    DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../project-setup_p${projId}s${scId}.log`));
    return op.log('error', {error: err.message})
      .then(op => op.finish())
      .then(() => callback(err.message), () => callback(err.message));
  });
}
<|endoftext|>


<commit_before>var global = require('../internals/global');
var fails = require('../internals/fails');
var classof = require('../internals/classof-raw');
var bind = require('../internals/function-bind-context');
var html = require('../internals/html');
var createElement = require('../internals/document-create-element');
var IS_IOS = require('../internals/engine-is-ios');

var location = global.location;
var set = global.setImmediate;
var clear = global.clearImmediate;
var process = global.process;
var MessageChannel = global.MessageChannel;
var Dispatch = global.Dispatch;
var counter = 0;
var queue = {};
var ONREADYSTATECHANGE = 'onreadystatechange';
var defer, channel, port;

var run = function (id) {
  // eslint-disable-next-line no-prototype-builtins
  if (queue.hasOwnProperty(id)) {
    var fn = queue[id];
    delete queue[id];
    fn();
  }
};

var runner = function (id) {
  return function () {
    run(id);
  };
};

var listener = function (event) {
  run(event.data);
};

var post = function (id) {
  // old engines have not location.origin
  global.postMessage(id + '', location.protocol + '//' + location.host);
};

// Node.js 0.9+ & IE10+ has setImmediate, otherwise:
if (!set || !clear) {
  set = function setImmediate(fn) {
    var args = [];
    var i = 1;
    while (arguments.length > i) args.push(arguments[i++]);
    queue[++counter] = function () {
      // eslint-disable-next-line no-new-func
      (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
    };
    defer(counter);
    return counter;
  };
  clear = function clearImmediate(id) {
    delete queue[id];
  };
  // Node.js 0.8-
  if (classof(process) == 'process') {
    defer = function (id) {
      process.nextTick(runner(id));
    };
  // Sphere (JS game engine) Dispatch API
  } else if (Dispatch && Dispatch.now) {
    defer = function (id) {
      Dispatch.now(runner(id));
    };
  // Browsers with MessageChannel, includes WebWorkers
  // except iOS - https://github.com/zloirock/core-js/issues/624
  } else if (MessageChannel && !IS_IOS) {
    channel = new MessageChannel();
    port = channel.port2;
    channel.port1.onmessage = listener;
    defer = bind(port.postMessage, port, 1);
  // Browsers with postMessage, skip WebWorkers
  // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
  } else if (global.addEventListener && typeof postMessage == 'function' && !global.importScripts && !fails(post) && location.protocol !== 'file:') {
    defer = post;
    global.addEventListener('message', listener, false);
  // IE8-
  } else if (ONREADYSTATECHANGE in createElement('script')) {
    defer = function (id) {
      html.appendChild(createElement('script'))[ONREADYSTATECHANGE] = function () {
        html.removeChild(this);
        run(id);
      };
    };
  // Rest old browsers
  } else {
    defer = function (id) {
      setTimeout(runner(id), 0);
    };
  }
}

module.exports = {
  set: set,
  clear: clear
};
<commit_msg>Break the postMessage check clause into multiple lines<commit_after>var global = require('../internals/global');
var fails = require('../internals/fails');
var classof = require('../internals/classof-raw');
var bind = require('../internals/function-bind-context');
var html = require('../internals/html');
var createElement = require('../internals/document-create-element');
var IS_IOS = require('../internals/engine-is-ios');

var location = global.location;
var set = global.setImmediate;
var clear = global.clearImmediate;
var process = global.process;
var MessageChannel = global.MessageChannel;
var Dispatch = global.Dispatch;
var counter = 0;
var queue = {};
var ONREADYSTATECHANGE = 'onreadystatechange';
var defer, channel, port;

var run = function (id) {
  // eslint-disable-next-line no-prototype-builtins
  if (queue.hasOwnProperty(id)) {
    var fn = queue[id];
    delete queue[id];
    fn();
  }
};

var runner = function (id) {
  return function () {
    run(id);
  };
};

var listener = function (event) {
  run(event.data);
};

var post = function (id) {
  // old engines have not location.origin
  global.postMessage(id + '', location.protocol + '//' + location.host);
};

// Node.js 0.9+ & IE10+ has setImmediate, otherwise:
if (!set || !clear) {
  set = function setImmediate(fn) {
    var args = [];
    var i = 1;
    while (arguments.length > i) args.push(arguments[i++]);
    queue[++counter] = function () {
      // eslint-disable-next-line no-new-func
      (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
    };
    defer(counter);
    return counter;
  };
  clear = function clearImmediate(id) {
    delete queue[id];
  };
  // Node.js 0.8-
  if (classof(process) == 'process') {
    defer = function (id) {
      process.nextTick(runner(id));
    };
  // Sphere (JS game engine) Dispatch API
  } else if (Dispatch && Dispatch.now) {
    defer = function (id) {
      Dispatch.now(runner(id));
    };
  // Browsers with MessageChannel, includes WebWorkers
  // except iOS - https://github.com/zloirock/core-js/issues/624
  } else if (MessageChannel && !IS_IOS) {
    channel = new MessageChannel();
    port = channel.port2;
    channel.port1.onmessage = listener;
    defer = bind(port.postMessage, port, 1);
  // Browsers with postMessage, skip WebWorkers
  // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
  } else if (
    global.addEventListener &&
    typeof postMessage == 'function' &&
    !global.importScripts &&
    !fails(post) &&
    location.protocol !== 'file:'
  ) {
    defer = post;
    global.addEventListener('message', listener, false);
  // IE8-
  } else if (ONREADYSTATECHANGE in createElement('script')) {
    defer = function (id) {
      html.appendChild(createElement('script'))[ONREADYSTATECHANGE] = function () {
        html.removeChild(this);
        run(id);
      };
    };
  // Rest old browsers
  } else {
    defer = function (id) {
      setTimeout(runner(id), 0);
    };
  }
}

module.exports = {
  set: set,
  clear: clear
};
<|endoftext|>


<commit_before>const payload = require('@bugsnag/core/lib/json-payload')
const { isoDate } = require('@bugsnag/core/lib/es-utils')
const UndeliveredPayloadQueue = require('./queue')
const NetworkStatus = require('./network-status')
const RedeliveryLoop = require('./redelivery')

module.exports = (client, fetch = global.fetch) => {
  const networkStatus = new NetworkStatus()

  const send = (url, opts, cb) => {
    fetch(url, opts)
      .then(response => {
        if (response.ok) return response.text()
        const err = new Error(`Bad status code from API: ${response.status}`)
        err.isRetryable = isRetryable(response.status)
        return Promise.reject(err)
      })
      .then(() => cb(null))
      .catch(err => cb(err))
  }

  const logError = e => client._logger.error('Error redelivering payload', e)

  const enqueue = async (payloadKind, failedPayload) => {
    client._logger.info(`Writing ${payloadKind} payloads to cache`)
    await queues[payloadKind].enqueue(failedPayload, logError)
    if (networkStatus.isConnected) queueConsumers[payloadKind].start()
  }

  const onerror = async (err, failedPayload, payloadKind, cb) => {
    client._logger.error(`${payloadKind} failed to send…\n${(err && err.stack) ? err.stack : err}`, err)
    if (failedPayload && err.isRetryable !== false) enqueue(payloadKind, failedPayload)
    cb(err)
  }

  const { queues, queueConsumers } = initRedelivery(networkStatus, logError, send)

  return {
    sendReport: (report, cb = () => {}) => {
      const url = client.config.endpoints.notify

      let body, opts
      try {
        body = payload.report(report, client.config.filters)
        opts = {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Bugsnag-Api-Key': report.apiKey || client.config.apiKey,
            'Bugsnag-Payload-Version': '4',
            'Bugsnag-Sent-At': isoDate()
          },
          body
        }
        if (!networkStatus.isConnected || report.attemptImmediateDelivery === false) {
          enqueue('report', { url, opts })
          return cb(null)
        }
        client._logger.info(`Sending report ${report.events[0].errorClass}: ${report.events[0].errorMessage}`)
        send(url, opts, err => {
          if (err) return onerror(err, { url, opts }, 'report', cb)
          cb(null)
        })
      } catch (e) {
        onerror(e, { url, opts }, 'report', cb)
      }
    },

    sendSession: (session, cb = () => {}) => {
      const url = client.config.endpoints.sessions

      let body, opts
      try {
        body = payload.session(session, client.config.filters)
        opts = {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Bugsnag-Api-Key': client.config.apiKey,
            'Bugsnag-Payload-Version': '1',
            'Bugsnag-Sent-At': isoDate()
          },
          body
        }
        if (!networkStatus.isConnected) {
          enqueue('session', { url, opts })
          return cb(null)
        }
        client._logger.info(`Sending session`)
        send(url, opts, err => {
          if (err) return onerror(err, { url, opts }, 'session', cb)
          cb(null)
        })
      } catch (e) {
        onerror(e, { url, opts }, 'session', cb)
      }
    }
  }
}

const initRedelivery = (networkStatus, onerror, send) => {
  const queues = {
    'report': new UndeliveredPayloadQueue('report', onerror),
    'session': new UndeliveredPayloadQueue('session', onerror)
  }

  const queueConsumers = {
    'report': new RedeliveryLoop(send, queues.report, onerror),
    'session': new RedeliveryLoop(send, queues.session, onerror)
  }

  Promise.all([ queues.report.init(), queues.session.init() ])
    .then(() => {
      networkStatus.watch(isConnected => {
        if (isConnected) {
          queueConsumers.report.start()
          queueConsumers.session.start()
        } else {
          queueConsumers.report.stop()
          queueConsumers.session.stop()
        }
      })
    })
    .catch(onerror)

  return { queues, queueConsumers }
}

// basically, if it starts with a 4, don't retry (unless it's in the list of exceptions)
const isRetryable = status => {
  return (
    status < 400 ||
    status > 499 ||
    [
      408, // timeout
      429 // too many requests
    ].includes(status))
}
<commit_msg>fix(expo-delivery): Remove extraneous "s" from log message<commit_after>const payload = require('@bugsnag/core/lib/json-payload')
const { isoDate } = require('@bugsnag/core/lib/es-utils')
const UndeliveredPayloadQueue = require('./queue')
const NetworkStatus = require('./network-status')
const RedeliveryLoop = require('./redelivery')

module.exports = (client, fetch = global.fetch) => {
  const networkStatus = new NetworkStatus()

  const send = (url, opts, cb) => {
    fetch(url, opts)
      .then(response => {
        if (response.ok) return response.text()
        const err = new Error(`Bad status code from API: ${response.status}`)
        err.isRetryable = isRetryable(response.status)
        return Promise.reject(err)
      })
      .then(() => cb(null))
      .catch(err => cb(err))
  }

  const logError = e => client._logger.error('Error redelivering payload', e)

  const enqueue = async (payloadKind, failedPayload) => {
    client._logger.info(`Writing ${payloadKind} payload to cache`)
    await queues[payloadKind].enqueue(failedPayload, logError)
    if (networkStatus.isConnected) queueConsumers[payloadKind].start()
  }

  const onerror = async (err, failedPayload, payloadKind, cb) => {
    client._logger.error(`${payloadKind} failed to send…\n${(err && err.stack) ? err.stack : err}`, err)
    if (failedPayload && err.isRetryable !== false) enqueue(payloadKind, failedPayload)
    cb(err)
  }

  const { queues, queueConsumers } = initRedelivery(networkStatus, logError, send)

  return {
    sendReport: (report, cb = () => {}) => {
      const url = client.config.endpoints.notify

      let body, opts
      try {
        body = payload.report(report, client.config.filters)
        opts = {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Bugsnag-Api-Key': report.apiKey || client.config.apiKey,
            'Bugsnag-Payload-Version': '4',
            'Bugsnag-Sent-At': isoDate()
          },
          body
        }
        if (!networkStatus.isConnected || report.attemptImmediateDelivery === false) {
          enqueue('report', { url, opts })
          return cb(null)
        }
        client._logger.info(`Sending report ${report.events[0].errorClass}: ${report.events[0].errorMessage}`)
        send(url, opts, err => {
          if (err) return onerror(err, { url, opts }, 'report', cb)
          cb(null)
        })
      } catch (e) {
        onerror(e, { url, opts }, 'report', cb)
      }
    },

    sendSession: (session, cb = () => {}) => {
      const url = client.config.endpoints.sessions

      let body, opts
      try {
        body = payload.session(session, client.config.filters)
        opts = {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Bugsnag-Api-Key': client.config.apiKey,
            'Bugsnag-Payload-Version': '1',
            'Bugsnag-Sent-At': isoDate()
          },
          body
        }
        if (!networkStatus.isConnected) {
          enqueue('session', { url, opts })
          return cb(null)
        }
        client._logger.info(`Sending session`)
        send(url, opts, err => {
          if (err) return onerror(err, { url, opts }, 'session', cb)
          cb(null)
        })
      } catch (e) {
        onerror(e, { url, opts }, 'session', cb)
      }
    }
  }
}

const initRedelivery = (networkStatus, onerror, send) => {
  const queues = {
    'report': new UndeliveredPayloadQueue('report', onerror),
    'session': new UndeliveredPayloadQueue('session', onerror)
  }

  const queueConsumers = {
    'report': new RedeliveryLoop(send, queues.report, onerror),
    'session': new RedeliveryLoop(send, queues.session, onerror)
  }

  Promise.all([ queues.report.init(), queues.session.init() ])
    .then(() => {
      networkStatus.watch(isConnected => {
        if (isConnected) {
          queueConsumers.report.start()
          queueConsumers.session.start()
        } else {
          queueConsumers.report.stop()
          queueConsumers.session.stop()
        }
      })
    })
    .catch(onerror)

  return { queues, queueConsumers }
}

// basically, if it starts with a 4, don't retry (unless it's in the list of exceptions)
const isRetryable = status => {
  return (
    status < 400 ||
    status > 499 ||
    [
      408, // timeout
      429 // too many requests
    ].includes(status))
}
<|endoftext|>


<commit_before>import { __ } from 'embark-i18n';
require('colors');
let async = require('async');
let shelljs = require('shelljs');

const path = require('path');

class IPFS {
  constructor(options) {
    this.options = options;
    this.buildDir = options.buildDir || 'dist/';
    this.storageConfig = options.storageConfig;
    this.configIpfsBin = this.storageConfig.ipfs_bin || "ipfs";
    this.env = options.env;
  }

  deploy(cb) {
    console.log("deploying to ipfs!");
    let self = this;
    async.waterfall([
      function findBinary(callback) {
        let ipfs_bin = shelljs.which(self.configIpfsBin);

        if (ipfs_bin === 'ipfs not found' || !ipfs_bin) {
          console.log(('=== WARNING: ' + self.configIpfsBin + ' ' + __('not found or not in the path. Guessing %s for path', '~/go/bin/ipfs')).yellow);
          ipfs_bin = "~/go/bin/ipfs";
        }

        callback(null, ipfs_bin);
      },
      function runCommand(ipfs_bin, callback) {
        let cmd = `"${ipfs_bin}" add -r ${self.buildDir}`;
        console.log(("=== " + __("adding %s to ipfs", self.buildDir)).green);
        console.debug(cmd);
        shelljs.exec(cmd, {silent:true}, function(code, stdout, stderr){ // {silent:true}: don't echo cmd output so it can be controlled via logLevel
          console.log(stdout.green);
          callback(stderr, stdout);
        });
      },
      function getHashFromOutput(result, callback) {
        const pattern = `added ([a-zA-Z1-9]{46}) ${path.basename(self.buildDir)}\n`;
        const regex = RegExp(pattern, 'm');
        const dirHash = result.match(regex)[1];

        callback(null, dirHash);
      },
      function printUrls(dir_hash, callback) {
        console.log(("=== " + __("DApp available at") + " http://localhost:8080/ipfs/" + dir_hash + "/").green);
        console.log(("=== " + __("DApp available at") + " https://ipfs.infura.io/ipfs/" + dir_hash + "/").green);
        console.log(("=== " + __("DApp available at") + " https://gateway.ipfs.io/ipfs/" + dir_hash + "/").green);
        console.log(("=== " + __("DApp available at") + " https://cloudflare-ipfs.com/ipfs/" + dir_hash + "/").green);
        if(self.env === 'development') {
          console.log(("\n=== " +
            "Blockchain must be running".bold +
            " ===").yellow);
          console.log((
            "embark run".italic +
            __(" or ") +
            "embark blockchain".italic +
            __(" must be running when the site is loaded to interact with the blockchain.\n")
          ).yellow);
          console.log(("=== " +
            "Usage with the public gateway".bold +
            " ===").yellow);
          console.log((
            __("If you wish to load your development site from the public gateway (ipfs.infura.io), you will need to first update your CORS settings (") +
            "config/blockchain.js > wsOrigins".italic +
            __(" and ") +
            "config/blockchain.js > rpcCorsDomain".italic +
            __(") to allow ") +
            "ipfs.infura.io".underline +
            __(". If these were set to 'auto', they would now need to be set to ") +
            "https://ipfs.infura.io,http://localhost:8000,http://localhost:8500,embark".underline +
            ".\n").yellow);
        }

        callback(null, dir_hash);
      }
    ], function (err, dir_hash) {
      if (err) {
        console.log(__("error uploading to ipfs").red);
        console.log(err);
        cb(err);
      }
      else cb(null, dir_hash);
    });
  }
}

module.exports = IPFS;
<commit_msg>fix(@embark/ipfs): fix ipfs upload with wrong error message<commit_after>import { __ } from 'embark-i18n';
require('colors');
let async = require('async');
let shelljs = require('shelljs');

const path = require('path');

class IPFS {
  constructor(options) {
    this.options = options;
    this.buildDir = options.buildDir || 'dist/';
    this.storageConfig = options.storageConfig;
    this.configIpfsBin = this.storageConfig.ipfs_bin || "ipfs";
    this.env = options.env;
  }

  deploy(cb) {
    console.log("deploying to ipfs!");
    let self = this;
    async.waterfall([
      function findBinary(callback) {
        let ipfs_bin = shelljs.which(self.configIpfsBin);

        if (ipfs_bin === 'ipfs not found' || !ipfs_bin) {
          console.log(('=== WARNING: ' + self.configIpfsBin + ' ' + __('not found or not in the path. Guessing %s for path', '~/go/bin/ipfs')).yellow);
          ipfs_bin = "~/go/bin/ipfs";
        }

        callback(null, ipfs_bin);
      },
      function runCommand(ipfs_bin, callback) {
        let cmd = `"${ipfs_bin}" add -r ${self.buildDir}`;
        console.log(("=== " + __("adding %s to ipfs", self.buildDir)).green);
        console.debug(cmd);
        shelljs.exec(cmd, {silent:true}, function(code, stdout, stderr){ // {silent:true}: don't echo cmd output so it can be controlled via logLevel
          console.log(stdout.green);
          if (code) {
            // stderr can sometimes be an error or the total uploaded size
            return callback(stderr || __('IPFS exited with code %s', code.toString()));
          }
          callback(null, stdout);
        });
      },
      function getHashFromOutput(result, callback) {
        const pattern = `added ([a-zA-Z1-9]{46}) ${path.basename(self.buildDir)}\n`;
        const regex = RegExp(pattern, 'm');
        const dirHash = result.match(regex)[1];

        callback(null, dirHash);
      },
      function printUrls(dir_hash, callback) {
        console.log(("=== " + __("DApp available at") + " http://localhost:8080/ipfs/" + dir_hash + "/").green);
        console.log(("=== " + __("DApp available at") + " https://ipfs.infura.io/ipfs/" + dir_hash + "/").green);
        console.log(("=== " + __("DApp available at") + " https://gateway.ipfs.io/ipfs/" + dir_hash + "/").green);
        console.log(("=== " + __("DApp available at") + " https://cloudflare-ipfs.com/ipfs/" + dir_hash + "/").green);
        if(self.env === 'development') {
          console.log(("\n=== " +
            "Blockchain must be running".bold +
            " ===").yellow);
          console.log((
            "embark run".italic +
            __(" or ") +
            "embark blockchain".italic +
            __(" must be running when the site is loaded to interact with the blockchain.\n")
          ).yellow);
          console.log(("=== " +
            "Usage with the public gateway".bold +
            " ===").yellow);
          console.log((
            __("If you wish to load your development site from the public gateway (ipfs.infura.io), you will need to first update your CORS settings (") +
            "config/blockchain.js > wsOrigins".italic +
            __(" and ") +
            "config/blockchain.js > rpcCorsDomain".italic +
            __(") to allow ") +
            "ipfs.infura.io".underline +
            __(". If these were set to 'auto', they would now need to be set to ") +
            "https://ipfs.infura.io,http://localhost:8000,http://localhost:8500,embark".underline +
            ".\n").yellow);
        }

        callback(null, dir_hash);
      }
    ], function (err, dir_hash) {
      if (err) {
        console.error(__("error uploading to ipfs").red);
        cb(err);
      }
      else cb(null, dir_hash);
    });
  }
}

module.exports = IPFS;
<|endoftext|>


<commit_before>/**
  @module ember
  @submodule ember-testing
 */
var slice = [].slice,
    helpers = {},
    originalMethods = {},
    injectHelpersCallbacks = [];

/**
  This is a container for an assortment of testing related functionality:

  * Choose your default test adapter (for your framework of choice).
  * Register/Unregister additional test helpers.
  * Setup callbacks to be fired when the test helpers are injected into
    your application.

  @class Test
  @namespace Ember
*/
Ember.Test = {

  /**
    `registerHelper` is used to register a test helper that will be injected
    when `App.injectTestHelpers` is called.

    The helper method will always be called with the current Application as
    the first parameter.

    For example:
    ```javascript
      Ember.Test.registerHelper('boot', function(app) {
        Ember.run(app, app.advanceReadiness);
      });
    ```

    This helper can later be called without arguments because it will be
    called with `app` as the first parameter.

    ```javascript
      App = Ember.Application.create();
      App.injectTestHelpers();
      boot();
    ```

    @public
    @method registerHelper
    @param {String} name The name of the helper method to add.
    @param {Function} helperMethod
    @param options {Object}
  */
  registerHelper: function(name, helperMethod) {
    helpers[name] = {
      method: helperMethod,
      meta: { wait: false }
    };
  },

  /**
    `registerAsyncHelper` is used to register an async test helper that will be injected
    when `App.injectTestHelpers` is called.

    The helper method will always be called with the current Application as
    the first parameter.

    For example:
    ```javascript
      Ember.Test.registerAsyncHelper('boot', function(app) {
        Ember.run(app, app.advanceReadiness);
      });
    ```

    The advantage of an async helper is that it will not run
    until the last async helper has completed.  All async helpers
    after it will wait for it complete before running.

    For example:
    ```javascript
      Ember.Test.registerAsyncHelper('deletePost', function(app, postId) {
        click('.delete-' + postId);
      });

      // ... in your test
      visit('/post/2');
      deletePost(2);
      visit('/post/3');
      deletePost(3);
    ```

    @public
    @method registerAsyncHelper
    @param {String} name The name of the helper method to add.
    @param {Function} helperMethod
  */
  registerAsyncHelper: function(name, helperMethod) {
    helpers[name] = {
      method: helperMethod,
      meta: { wait: true }
    };
  },

  /**
    Remove a previously added helper method.

    Example:
    ```
    Ember.Test.unregisterHelper('wait');
    ```

    @public
    @method unregisterHelper
    @param {String} name The helper to remove.
  */
  unregisterHelper: function(name) {
    delete helpers[name];
    if (originalMethods[name]) {
      this.helperContainer[name] = originalMethods[name];
    }
    delete originalMethods[name];
    delete Ember.Test.Promise.prototype[name];
  },

  /**
    Used to register callbacks to be fired whenever `App.injectTestHelpers`
    is called.

    The callback will receive the current application as an argument.

    Example:
    ```
    Ember.Test.onInjectHelpers(function() {
      Ember.$(document).ajaxStart(function() {
        Test.pendingAjaxRequests++;
      });

      Ember.$(document).ajaxStop(function() {
        Test.pendingAjaxRequests--;
      });
    });
    ```

    @public
    @method onInjectHelpers
    @param {Function} callback The function to be called.
  */
  onInjectHelpers: function(callback) {
    injectHelpersCallbacks.push(callback);
  },

  /**
    This returns a thenable tailored for testing.  It catches failed
    `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception`
    callback in the last chained then.

    This method should be returned by async helpers such as `wait`.

    @public
    @method promise
    @param {Function} resolver The function used to resolve the promise.
  */
  promise: function(resolver) {
    return new Ember.Test.Promise(resolver);
  },

  /**
   Used to allow ember-testing to communicate with a specific testing
   framework.

   You can manually set it before calling `App.setupForTesting()`.

   Example:
   ```
   Ember.Test.adapter = MyCustomAdapter.create()
   ```

   If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`.

   @public
   @property adapter
   @type {Class} The adapter to be used.
   @default Ember.Test.QUnitAdapter
  */
  adapter: null,

  /**
    Replacement for `Ember.RSVP.resolve`
    The only difference is this uses
    and instance of `Ember.Test.Promise`

    @public
    @method resolve
    @param {Mixed} The value to resolve
  */
  resolve: function(val) {
    return Ember.Test.promise(function(resolve) {
      return resolve(val);
    });
  },

  /**
   @public

     This allows ember-testing to play nicely with other asynchronous
     events, such as an application that is waiting for a CSS3
     transition or an IndexDB transaction.

     For example:
     ```javascript
     Ember.Test.registerWaiter(function() {
     return myPendingTransactions() == 0;
     });
     ```
     The `context` argument allows you to optionally specify the `this`
     with which your callback will be invoked.

     For example:
     ```javascript
     Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions);
     ```
     @public
     @method registerWaiter
     @param {Object} context (optional)
     @param {Function} callback
  */
  registerWaiter: function(context, callback) {
    if (arguments.length === 1) {
      callback = context;
      context = null;
    }
    if (!this.waiters) {
      this.waiters = Ember.A();
    }
    this.waiters.push([context, callback]);
  },
  /**
     `unregisterWaiter` is used to unregister a callback that was
     registered with `registerWaiter`.

     @public
     @method unregisterWaiter
     @param {Object} context (optional)
     @param {Function} callback
  */
  unregisterWaiter: function(context, callback) {
    var pair;
    if (!this.waiters) { return; }
    if (arguments.length === 1) {
      callback = context;
      context = null;
    }
    pair = [context, callback];
    this.waiters = Ember.A(this.waiters.filter(function(elt) {
      return Ember.compare(elt, pair)!==0;
    }));
  }
};

function helper(app, name) {
  var fn = helpers[name].method,
      meta = helpers[name].meta;

  return function() {
    var args = slice.call(arguments),
        lastPromise = Ember.Test.lastPromise;

    args.unshift(app);

    // some helpers are not async and
    // need to return a value immediately.
    // example: `find`
    if (!meta.wait) {
      return fn.apply(app, args);
    }

    if (!lastPromise) {
      // It's the first async helper in current context
      lastPromise = fn.apply(app, args);
    } else {
      // wait for last helper's promise to resolve
      // and then execute
      run(function() {
        lastPromise = Ember.Test.resolve(lastPromise).then(function() {
          return fn.apply(app, args);
        });
      });
    }

    return lastPromise;
  };
}

function run(fn) {
  if (!Ember.run.currentRunLoop) {
    Ember.run(fn);
  } else {
    fn();
  }
}

Ember.Application.reopen({
  /**
    @property testHelpers
    @type {Object}
    @default {}
  */
  testHelpers: {},

  /**
   This hook defers the readiness of the application, so that you can start
   the app when your tests are ready to run. It also sets the router's
   location to 'none', so that the window's location will not be modified
   (preventing both accidental leaking of state between tests and interference
   with your testing framework).

   Example:
  ```
  App.setupForTesting();
  ```

    @method setupForTesting
  */
  setupForTesting: function() {
    Ember.testing = true;

    this.deferReadiness();

    this.Router.reopen({
      location: 'none'
    });

    // if adapter is not manually set default to QUnit
    if (!Ember.Test.adapter) {
       Ember.Test.adapter = Ember.Test.QUnitAdapter.create();
    }
  },

  /**
    This will be used as the container to inject the test helpers into. By
    default the helpers are injected into `window`.

    @property helperContainer
   @type {Object} The object to be used for test helpers.
   @default window
  */
  helperContainer: window,

  /**
    This injects the test helpers into the `helperContainer` object. If an object is provided
    it will be used as the helperContainer. If `helperContainer` is not set it will default
    to `window`. If a function of the same name has already been defined it will be cached
    (so that it can be reset if the helper is removed with `unregisterHelper` or
    `removeTestHelpers`).

   Any callbacks registered with `onInjectHelpers` will be called once the
   helpers have been injected.

  Example:
  ```
  App.injectTestHelpers();
  ```

    @method injectTestHelpers
  */
  injectTestHelpers: function(helperContainer) {
    if (helperContainer) { this.helperContainer = helperContainer; }

    this.testHelpers = {};
    for (var name in helpers) {
      originalMethods[name] = this.helperContainer[name];
      this.testHelpers[name] = this.helperContainer[name] = helper(this, name);
      protoWrap(Ember.Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait);
    }

    for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) {
      injectHelpersCallbacks[i](this);
    }

    Ember.RSVP.configure('onerror', onerror);
  },

  /**
    This removes all helpers that have been registered, and resets and functions
    that were overridden by the helpers.

    Example:
    ```
    App.removeTestHelpers();
    ```

    @public
    @method removeTestHelpers
  */
  removeTestHelpers: function() {
    for (var name in helpers) {
      this.helperContainer[name] = originalMethods[name];
      delete this.testHelpers[name];
      delete originalMethods[name];
    }
    Ember.RSVP.configure('onerror', null);
  }

});

// This method is no longer needed
// But still here for backwards compatibility
// of helper chaining
function protoWrap(proto, name, callback, isAsync) {
  proto[name] = function() {
    var args = arguments;
    if (isAsync) {
      return callback.apply(this, args);
    } else {
      return this.then(function() {
        return callback.apply(this, args);
      });
    }
  };
}

Ember.Test.Promise = function() {
  Ember.RSVP.Promise.apply(this, arguments);
  Ember.Test.lastPromise = this;
};

Ember.Test.Promise.prototype = Ember.create(Ember.RSVP.Promise.prototype);
Ember.Test.Promise.prototype.constructor = Ember.Test.Promise;

// Patch `then` to isolate async methods
// specifically `Ember.Test.lastPromise`
var originalThen = Ember.RSVP.Promise.prototype.then;
Ember.Test.Promise.prototype.then = function(onSuccess, onFailure) {
  return originalThen.call(this, function(val) {
    return isolate(onSuccess, val);
  }, onFailure);
};

// This method isolates nested async methods
// so that they don't conflict with other last promises.
//
// 1. Set `Ember.Test.lastPromise` to null
// 2. Invoke method
// 3. Return the last promise created during method
// 4. Restore `Ember.Test.lastPromise` to original value
function isolate(fn, val) {
  var value, lastPromise;

  // Reset lastPromise for nested helpers
  Ember.Test.lastPromise = null;

  value = fn.call(null, val);

  lastPromise = Ember.Test.lastPromise;

  // If the method returned a promise
  // return that promise. If not,
  // return the last async helper's promise
  if ((value && (value instanceof Ember.Test.Promise)) || !lastPromise) {
    return value;
  } else {
    run(function() {
      lastPromise = Ember.Test.resolve(lastPromise).then(function() {
        return value;
      });
    });
    return lastPromise;
  }
}

function onerror(error) {
  Ember.Test.adapter.exception(error);
}
<commit_msg>[DOC release] Add Ember.Application.testHelper documentation.<commit_after>/**
  @module ember
  @submodule ember-testing
 */
var slice = [].slice,
    helpers = {},
    originalMethods = {},
    injectHelpersCallbacks = [];

/**
  This is a container for an assortment of testing related functionality:

  * Choose your default test adapter (for your framework of choice).
  * Register/Unregister additional test helpers.
  * Setup callbacks to be fired when the test helpers are injected into
    your application.

  @class Test
  @namespace Ember
*/
Ember.Test = {

  /**
    `registerHelper` is used to register a test helper that will be injected
    when `App.injectTestHelpers` is called.

    The helper method will always be called with the current Application as
    the first parameter.

    For example:
    ```javascript
      Ember.Test.registerHelper('boot', function(app) {
        Ember.run(app, app.advanceReadiness);
      });
    ```

    This helper can later be called without arguments because it will be
    called with `app` as the first parameter.

    ```javascript
      App = Ember.Application.create();
      App.injectTestHelpers();
      boot();
    ```

    @public
    @method registerHelper
    @param {String} name The name of the helper method to add.
    @param {Function} helperMethod
    @param options {Object}
  */
  registerHelper: function(name, helperMethod) {
    helpers[name] = {
      method: helperMethod,
      meta: { wait: false }
    };
  },

  /**
    `registerAsyncHelper` is used to register an async test helper that will be injected
    when `App.injectTestHelpers` is called.

    The helper method will always be called with the current Application as
    the first parameter.

    For example:
    ```javascript
      Ember.Test.registerAsyncHelper('boot', function(app) {
        Ember.run(app, app.advanceReadiness);
      });
    ```

    The advantage of an async helper is that it will not run
    until the last async helper has completed.  All async helpers
    after it will wait for it complete before running.

    For example:
    ```javascript
      Ember.Test.registerAsyncHelper('deletePost', function(app, postId) {
        click('.delete-' + postId);
      });

      // ... in your test
      visit('/post/2');
      deletePost(2);
      visit('/post/3');
      deletePost(3);
    ```

    @public
    @method registerAsyncHelper
    @param {String} name The name of the helper method to add.
    @param {Function} helperMethod
  */
  registerAsyncHelper: function(name, helperMethod) {
    helpers[name] = {
      method: helperMethod,
      meta: { wait: true }
    };
  },

  /**
    Remove a previously added helper method.

    Example:
    ```
    Ember.Test.unregisterHelper('wait');
    ```

    @public
    @method unregisterHelper
    @param {String} name The helper to remove.
  */
  unregisterHelper: function(name) {
    delete helpers[name];
    if (originalMethods[name]) {
      this.helperContainer[name] = originalMethods[name];
    }
    delete originalMethods[name];
    delete Ember.Test.Promise.prototype[name];
  },

  /**
    Used to register callbacks to be fired whenever `App.injectTestHelpers`
    is called.

    The callback will receive the current application as an argument.

    Example:
    ```
    Ember.Test.onInjectHelpers(function() {
      Ember.$(document).ajaxStart(function() {
        Test.pendingAjaxRequests++;
      });

      Ember.$(document).ajaxStop(function() {
        Test.pendingAjaxRequests--;
      });
    });
    ```

    @public
    @method onInjectHelpers
    @param {Function} callback The function to be called.
  */
  onInjectHelpers: function(callback) {
    injectHelpersCallbacks.push(callback);
  },

  /**
    This returns a thenable tailored for testing.  It catches failed
    `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception`
    callback in the last chained then.

    This method should be returned by async helpers such as `wait`.

    @public
    @method promise
    @param {Function} resolver The function used to resolve the promise.
  */
  promise: function(resolver) {
    return new Ember.Test.Promise(resolver);
  },

  /**
   Used to allow ember-testing to communicate with a specific testing
   framework.

   You can manually set it before calling `App.setupForTesting()`.

   Example:
   ```
   Ember.Test.adapter = MyCustomAdapter.create()
   ```

   If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`.

   @public
   @property adapter
   @type {Class} The adapter to be used.
   @default Ember.Test.QUnitAdapter
  */
  adapter: null,

  /**
    Replacement for `Ember.RSVP.resolve`
    The only difference is this uses
    and instance of `Ember.Test.Promise`

    @public
    @method resolve
    @param {Mixed} The value to resolve
  */
  resolve: function(val) {
    return Ember.Test.promise(function(resolve) {
      return resolve(val);
    });
  },

  /**
   @public

     This allows ember-testing to play nicely with other asynchronous
     events, such as an application that is waiting for a CSS3
     transition or an IndexDB transaction.

     For example:
     ```javascript
     Ember.Test.registerWaiter(function() {
     return myPendingTransactions() == 0;
     });
     ```
     The `context` argument allows you to optionally specify the `this`
     with which your callback will be invoked.

     For example:
     ```javascript
     Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions);
     ```
     @public
     @method registerWaiter
     @param {Object} context (optional)
     @param {Function} callback
  */
  registerWaiter: function(context, callback) {
    if (arguments.length === 1) {
      callback = context;
      context = null;
    }
    if (!this.waiters) {
      this.waiters = Ember.A();
    }
    this.waiters.push([context, callback]);
  },
  /**
     `unregisterWaiter` is used to unregister a callback that was
     registered with `registerWaiter`.

     @public
     @method unregisterWaiter
     @param {Object} context (optional)
     @param {Function} callback
  */
  unregisterWaiter: function(context, callback) {
    var pair;
    if (!this.waiters) { return; }
    if (arguments.length === 1) {
      callback = context;
      context = null;
    }
    pair = [context, callback];
    this.waiters = Ember.A(this.waiters.filter(function(elt) {
      return Ember.compare(elt, pair)!==0;
    }));
  }
};

function helper(app, name) {
  var fn = helpers[name].method,
      meta = helpers[name].meta;

  return function() {
    var args = slice.call(arguments),
        lastPromise = Ember.Test.lastPromise;

    args.unshift(app);

    // some helpers are not async and
    // need to return a value immediately.
    // example: `find`
    if (!meta.wait) {
      return fn.apply(app, args);
    }

    if (!lastPromise) {
      // It's the first async helper in current context
      lastPromise = fn.apply(app, args);
    } else {
      // wait for last helper's promise to resolve
      // and then execute
      run(function() {
        lastPromise = Ember.Test.resolve(lastPromise).then(function() {
          return fn.apply(app, args);
        });
      });
    }

    return lastPromise;
  };
}

function run(fn) {
  if (!Ember.run.currentRunLoop) {
    Ember.run(fn);
  } else {
    fn();
  }
}

Ember.Application.reopen({
  /**
   This property contains the testing helpers for the current application. These
   are created once you call `injectTestHelpers` on your `Ember.Application`
   instance. The included helpers are also available on the `window` object by
   default, but can be used from this object on the individual application also.

    @property testHelpers
    @type {Object}
    @default {}
  */
  testHelpers: {},

  /**
   This hook defers the readiness of the application, so that you can start
   the app when your tests are ready to run. It also sets the router's
   location to 'none', so that the window's location will not be modified
   (preventing both accidental leaking of state between tests and interference
   with your testing framework).

   Example:
  ```
  App.setupForTesting();
  ```

    @method setupForTesting
  */
  setupForTesting: function() {
    Ember.testing = true;

    this.deferReadiness();

    this.Router.reopen({
      location: 'none'
    });

    // if adapter is not manually set default to QUnit
    if (!Ember.Test.adapter) {
       Ember.Test.adapter = Ember.Test.QUnitAdapter.create();
    }
  },

  /**
    This will be used as the container to inject the test helpers into. By
    default the helpers are injected into `window`.

    @property helperContainer
   @type {Object} The object to be used for test helpers.
   @default window
  */
  helperContainer: window,

  /**
    This injects the test helpers into the `helperContainer` object. If an object is provided
    it will be used as the helperContainer. If `helperContainer` is not set it will default
    to `window`. If a function of the same name has already been defined it will be cached
    (so that it can be reset if the helper is removed with `unregisterHelper` or
    `removeTestHelpers`).

   Any callbacks registered with `onInjectHelpers` will be called once the
   helpers have been injected.

  Example:
  ```
  App.injectTestHelpers();
  ```

    @method injectTestHelpers
  */
  injectTestHelpers: function(helperContainer) {
    if (helperContainer) { this.helperContainer = helperContainer; }

    this.testHelpers = {};
    for (var name in helpers) {
      originalMethods[name] = this.helperContainer[name];
      this.testHelpers[name] = this.helperContainer[name] = helper(this, name);
      protoWrap(Ember.Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait);
    }

    for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) {
      injectHelpersCallbacks[i](this);
    }

    Ember.RSVP.configure('onerror', onerror);
  },

  /**
    This removes all helpers that have been registered, and resets and functions
    that were overridden by the helpers.

    Example:
    ```
    App.removeTestHelpers();
    ```

    @public
    @method removeTestHelpers
  */
  removeTestHelpers: function() {
    for (var name in helpers) {
      this.helperContainer[name] = originalMethods[name];
      delete this.testHelpers[name];
      delete originalMethods[name];
    }
    Ember.RSVP.configure('onerror', null);
  }

});

// This method is no longer needed
// But still here for backwards compatibility
// of helper chaining
function protoWrap(proto, name, callback, isAsync) {
  proto[name] = function() {
    var args = arguments;
    if (isAsync) {
      return callback.apply(this, args);
    } else {
      return this.then(function() {
        return callback.apply(this, args);
      });
    }
  };
}

Ember.Test.Promise = function() {
  Ember.RSVP.Promise.apply(this, arguments);
  Ember.Test.lastPromise = this;
};

Ember.Test.Promise.prototype = Ember.create(Ember.RSVP.Promise.prototype);
Ember.Test.Promise.prototype.constructor = Ember.Test.Promise;

// Patch `then` to isolate async methods
// specifically `Ember.Test.lastPromise`
var originalThen = Ember.RSVP.Promise.prototype.then;
Ember.Test.Promise.prototype.then = function(onSuccess, onFailure) {
  return originalThen.call(this, function(val) {
    return isolate(onSuccess, val);
  }, onFailure);
};

// This method isolates nested async methods
// so that they don't conflict with other last promises.
//
// 1. Set `Ember.Test.lastPromise` to null
// 2. Invoke method
// 3. Return the last promise created during method
// 4. Restore `Ember.Test.lastPromise` to original value
function isolate(fn, val) {
  var value, lastPromise;

  // Reset lastPromise for nested helpers
  Ember.Test.lastPromise = null;

  value = fn.call(null, val);

  lastPromise = Ember.Test.lastPromise;

  // If the method returned a promise
  // return that promise. If not,
  // return the last async helper's promise
  if ((value && (value instanceof Ember.Test.Promise)) || !lastPromise) {
    return value;
  } else {
    run(function() {
      lastPromise = Ember.Test.resolve(lastPromise).then(function() {
        return value;
      });
    });
    return lastPromise;
  }
}

function onerror(error) {
  Ember.Test.adapter.exception(error);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Deferred
 * @typechecks
 * @flow
 */

/**
 * Deferred provides a Promise-like API that exposes methods to resolve and
 * reject the Promise. It is most useful when converting non-Promise code to use
 * Promises.
 *
 * If you want to export the Promise without exposing access to the resolve and
 * reject methods, you should export `getPromise` which returns a Promise with
 * the same semantics excluding those methods.
 */
class Deferred<Tvalue, Treason> {
  _settled: boolean;
  _promise: Promise<any>;
  _resolve: (value: Tvalue) => void;
  _reject: (reason: Treason) => void;

  constructor() {
    this._settled = false;
    this._promise = new Promise((resolve, reject) => {
      this._resolve = (resolve: any);
      this._reject = (reject: any);
    });
  }

  getPromise(): Promise<any> {
    return this._promise;
  }

  resolve(value: Tvalue): void {
    this._settled = true;
    this._resolve(value);
  }

  reject(reason: Treason): void {
    this._settled = true;
    this._reject(reason);
  }

  catch(): Promise<any> {
    return Promise.prototype.catch.apply(this._promise, arguments);
  }

  then(): Promise<any> {
    return Promise.prototype.then.apply(this._promise, arguments);
  }

  done(
    onFulfill?: ?(value: any) => mixed,
    onReject?: ?(error: any) => mixed
  ): void {
    // Embed the polyfill for the non-standard Promise.prototype.done so that
    // users of the open source fbjs don't need a custom lib for Promise
    const promise = arguments.length ?
      this._promise.then.apply(this._promise, arguments) :
      this._promise;
    promise.then(undefined, function(err) {
      setTimeout(function() {
        throw err;
      }, 0);
    });
  }

  isSettled(): boolean {
    return this._settled;
  }
}

module.exports = Deferred;
<commit_msg>Make arity fixes for fetch and catch<commit_after>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Deferred
 * @typechecks
 * @flow
 */

/**
 * Deferred provides a Promise-like API that exposes methods to resolve and
 * reject the Promise. It is most useful when converting non-Promise code to use
 * Promises.
 *
 * If you want to export the Promise without exposing access to the resolve and
 * reject methods, you should export `getPromise` which returns a Promise with
 * the same semantics excluding those methods.
 */
class Deferred<Tvalue, Treason> {
  _settled: boolean;
  _promise: Promise<any>;
  _resolve: (value: Tvalue) => void;
  _reject: (reason: Treason) => void;

  constructor() {
    this._settled = false;
    this._promise = new Promise((resolve, reject) => {
      this._resolve = (resolve: any);
      this._reject = (reject: any);
    });
  }

  getPromise(): Promise<any> {
    return this._promise;
  }

  resolve(value: Tvalue): void {
    this._settled = true;
    this._resolve(value);
  }

  reject(reason: Treason): void {
    this._settled = true;
    this._reject(reason);
  }

  catch(
    onReject?: ?(error: any) => mixed
  ): Promise<any> {
    return Promise.prototype.catch.apply(this._promise, arguments);
  }

  then(
    onFulfill?: ?(value: any) => mixed,
    onReject?: ?(error: any) => mixed
  ): Promise<any> {
    return Promise.prototype.then.apply(this._promise, arguments);
  }

  done(
    onFulfill?: ?(value: any) => mixed,
    onReject?: ?(error: any) => mixed
  ): void {
    // Embed the polyfill for the non-standard Promise.prototype.done so that
    // users of the open source fbjs don't need a custom lib for Promise
    const promise = arguments.length ?
      this._promise.then.apply(this._promise, arguments) :
      this._promise;
    promise.then(undefined, function(err) {
      setTimeout(function() {
        throw err;
      }, 0);
    });
  }

  isSettled(): boolean {
    return this._settled;
  }
}

module.exports = Deferred;
<|endoftext|>


<commit_before>var should = require('should');
var binary = require('binary');
var BufferMaker = require('buffermaker');
var Message = require('../lib/message').Message;
var Protocol = require('../lib/Protocol');

describe("Protocol", function(){
  describe("Message Encoding", function(){
    it("should encode a  >= 0.7 message", function(){
      var message = new Message("kafkatest");
      var fullMessage = new BufferMaker()
      .UInt8(message.magic)
      .UInt8(message.compression)
      .UInt32BE(message.calculateChecksum())
      .string(message.payload)
      .make();
      var protocol = new Protocol();
      protocol.encodeMessage(message).should.eql(fullMessage);

    });

    it("should encode an empty >= 0.7 message", function(){
      var message = new Message("");
      var fullMessage = new BufferMaker()
      .UInt8(message.magic)
      .UInt8(message.compression)
      .UInt32BE(message.calculateChecksum())
      .string(message.payload)
      .make();
      var protocol = new Protocol();
      protocol.encodeMessage(message).should.eql(fullMessage);
    });

    it("should encode strings containing non-ASCII characters", function(){

      var message = new Message("ümlaut");
      var fullMessage = new BufferMaker()
      .UInt8(message.magic)
      .UInt8(message.compression)
      .UInt32BE(message.calculateChecksum())
      .string(message.payload)
      .make();
      var protocol = new Protocol();
      protocol.encodeMessage(message).should.eql(fullMessage);
    });
  });

  describe("#encodedRequestSize", function(){

    it("should return the size of the request", function(){
      var protocol = new Protocol("someothertopicname", 0);
      var buffer = new Buffer(4);
      buffer.writeUInt32BE(38, 0);
      protocol.encodedRequestSize().should.eql(buffer);
    });

  });

  describe("#encodeOffsetsRequests", function(){
    it("should fetch the latest offset" , function(){
      var expectedBytes = new BufferMaker()
      .UInt8(0)
      .UInt8(0)
      .UInt8(0)
      .UInt8(24) // request length
      .UInt8(0)
      .UInt8(4)  // request type
      .UInt8(0)
      .UInt8(4)  // topic length
      .string('test')
      .Int32BE(3)  // partition
      .string(new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]))
      .UInt32BE(1)  // max # of offsets
      .make();
      var protocol = new Protocol("test", 3);
      var request = protocol.encodeOffsetsRequest(-1, 1);
      request.should.eql(expectedBytes);
    });
  });

  describe("#encodedRequest", function(){
    it("should encode a request to consume", function(){
      var protocol = new Protocol("test", 0, 14);
      var bytes = new BufferMaker()
      .UInt16BE(protocol.RequestTypes.FETCH)
      .UInt16BE(protocol.topic.length)
      .string("test")
      .UInt32BE(0)
      .UInt32BE(0)
      .UInt32BE(0)
      .UInt32BE(protocol.maxMessageSize)
      .make();

      //var bytes = new Buffer(24);

      protocol.encodeRequest(protocol.RequestTypes.FETCH,
                                  0,
                                  14).should.eql(bytes);
    });
});

      describe("Request Encoding", function(){
        it("should binary encode an empty request", function() {
          var fullRequest = new BufferMaker()
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(16)
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(4)
                              .string('test')
                              .Int64BE(0)
                              .make();
          var protocol = new Protocol('test', 0);
          var request = protocol.encodeProduceRequest([]);
          request.length.should.equal(20);
          request.should.eql(fullRequest);
        });

      });

      it("should binary encode a request with a message, using a specific wire format", function(){
        var protocol = new Protocol('test', 0);
        var message = new Message("ale");

        var encodedRequest = protocol.encodeProduceRequest([message]);
        var unpacked = binary.parse(encodedRequest)
        .word32bu('dataSize')
        .word16bu('requestId')
        .word16bu('topicLength')
        .buffer('topic', 4)
        .word32bu('partition')
        .word32bu('messagesLength')
        .tap(function(vars){
          this.buffer('messages', vars.messagesLength);
        })
        .vars;

        encodedRequest.length.should.equal(33);
        unpacked.dataSize.should.eql(29);
        unpacked.requestId.should.eql(0);
        unpacked.topicLength.should.eql(4);
        unpacked.topic.toString('utf8').should.eql("test");
        unpacked.partition.should.eql(0);
       unpacked.messagesLength.should.eql(13);
      });
});
<commit_msg>another linux case-sensitity bug.<commit_after>var should = require('should');
var binary = require('binary');
var BufferMaker = require('BufferMaker');
var Message = require('../lib/message').Message;
var Protocol = require('../lib/Protocol');

describe("Protocol", function(){
  describe("Message Encoding", function(){
    it("should encode a  >= 0.7 message", function(){
      var message = new Message("kafkatest");
      var fullMessage = new BufferMaker()
      .UInt8(message.magic)
      .UInt8(message.compression)
      .UInt32BE(message.calculateChecksum())
      .string(message.payload)
      .make();
      var protocol = new Protocol();
      protocol.encodeMessage(message).should.eql(fullMessage);

    });

    it("should encode an empty >= 0.7 message", function(){
      var message = new Message("");
      var fullMessage = new BufferMaker()
      .UInt8(message.magic)
      .UInt8(message.compression)
      .UInt32BE(message.calculateChecksum())
      .string(message.payload)
      .make();
      var protocol = new Protocol();
      protocol.encodeMessage(message).should.eql(fullMessage);
    });

    it("should encode strings containing non-ASCII characters", function(){

      var message = new Message("ümlaut");
      var fullMessage = new BufferMaker()
      .UInt8(message.magic)
      .UInt8(message.compression)
      .UInt32BE(message.calculateChecksum())
      .string(message.payload)
      .make();
      var protocol = new Protocol();
      protocol.encodeMessage(message).should.eql(fullMessage);
    });
  });

  describe("#encodedRequestSize", function(){

    it("should return the size of the request", function(){
      var protocol = new Protocol("someothertopicname", 0);
      var buffer = new Buffer(4);
      buffer.writeUInt32BE(38, 0);
      protocol.encodedRequestSize().should.eql(buffer);
    });

  });

  describe("#encodeOffsetsRequests", function(){
    it("should fetch the latest offset" , function(){
      var expectedBytes = new BufferMaker()
      .UInt8(0)
      .UInt8(0)
      .UInt8(0)
      .UInt8(24) // request length
      .UInt8(0)
      .UInt8(4)  // request type
      .UInt8(0)
      .UInt8(4)  // topic length
      .string('test')
      .Int32BE(3)  // partition
      .string(new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]))
      .UInt32BE(1)  // max # of offsets
      .make();
      var protocol = new Protocol("test", 3);
      var request = protocol.encodeOffsetsRequest(-1, 1);
      request.should.eql(expectedBytes);
    });
  });

  describe("#encodedRequest", function(){
    it("should encode a request to consume", function(){
      var protocol = new Protocol("test", 0, 14);
      var bytes = new BufferMaker()
      .UInt16BE(protocol.RequestTypes.FETCH)
      .UInt16BE(protocol.topic.length)
      .string("test")
      .UInt32BE(0)
      .UInt32BE(0)
      .UInt32BE(0)
      .UInt32BE(protocol.maxMessageSize)
      .make();

      //var bytes = new Buffer(24);

      protocol.encodeRequest(protocol.RequestTypes.FETCH,
                                  0,
                                  14).should.eql(bytes);
    });
});

      describe("Request Encoding", function(){
        it("should binary encode an empty request", function() {
          var fullRequest = new BufferMaker()
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(16)
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(0)
                              .UInt8(4)
                              .string('test')
                              .Int64BE(0)
                              .make();
          var protocol = new Protocol('test', 0);
          var request = protocol.encodeProduceRequest([]);
          request.length.should.equal(20);
          request.should.eql(fullRequest);
        });

      });

      it("should binary encode a request with a message, using a specific wire format", function(){
        var protocol = new Protocol('test', 0);
        var message = new Message("ale");

        var encodedRequest = protocol.encodeProduceRequest([message]);
        var unpacked = binary.parse(encodedRequest)
        .word32bu('dataSize')
        .word16bu('requestId')
        .word16bu('topicLength')
        .buffer('topic', 4)
        .word32bu('partition')
        .word32bu('messagesLength')
        .tap(function(vars){
          this.buffer('messages', vars.messagesLength);
        })
        .vars;

        encodedRequest.length.should.equal(33);
        unpacked.dataSize.should.eql(29);
        unpacked.requestId.should.eql(0);
        unpacked.topicLength.should.eql(4);
        unpacked.topic.toString('utf8').should.eql("test");
        unpacked.partition.should.eql(0);
       unpacked.messagesLength.should.eql(13);
      });
});
<|endoftext|>


<commit_before>import React from "react"
import PropTypes from "prop-types"

let io
const listeners = []
if (typeof window !== `undefined` && window.IntersectionObserver) {
  io = new window.IntersectionObserver(
    entries => {
      entries.forEach(entry => {
        listeners.forEach(l => {
          if (l[0] === entry.target) {
            if (entry.isIntersecting) {
              io.unobserve(l[0])
              l[1]()
            }
          }
        })
      })
    },
    { rootMargin: `200px` }
  )
}

const listenToIntersections = (el, cb) => {
  io.observe(el)
  listeners.push([el, cb])
}

const Img = props => {
  const { opacity, onLoad, ...otherProps } = props
  return (
    <img
      {...otherProps}
      onLoad={onLoad}
      style={{
        position: `absolute`,
        top: 0,
        left: 0,
        transition: `opacity 0.5s`,
        opacity,
        width: `100%`,
        height: `100%`,
        objectFit: `cover`,
        objectPosition: `center`,
      }}
    />
  )
}

Img.propTypes = {
  opacity: PropTypes.number,
  onLoad: PropTypes.function,
}

class Image extends React.Component {
  constructor(props) {
    super(props)

    // If this browser doesn't support the IntersectionObserver API
    // we just start downloading the image right away.
    let isVisible = true
    if (typeof window !== `undefined` && window.IntersectionObserver) {
      isVisible = false
    }

    this.state = {
      isVisible,
    }

    this.handleRef = this.handleRef.bind(this)
  }

  handleRef(ref) {
    if (window.IntersectionObserver && ref) {
      listenToIntersections(ref, () => {
        this.setState({ isVisible: true, imgLoaded: false })
      })
    }
  }

  render() {
    const {
      title,
      alt,
      className,
      style,
      responsiveSizes,
      responsiveResolution,
      backgroundColor,
    } = this.props

    if (responsiveSizes) {
      const image = responsiveSizes
      return (
        <div
          className={`${className ? className : ``} gatsby-image-wrapper`}
          style={{
            position: `relative`,
            overflow: `hidden`,
            ...style,
          }}
          ref={this.handleRef}
        >
          {/* Preserve the aspect ratio. */}
          <div
            style={{
              width: `100%`,
              paddingBottom: `${100 / image.aspectRatio}%`,
            }}
          />

          {/* Show the blury base64 image. */}
          {image.base64 && (

          )}

          {/* Show a solid background color. */}
          {backgroundColor && (
            <div
              title={title}
              style={{
                backgroundColor: backgroundColor,
                position: `absolute`,
                top: 0,
                bottom: 0,
                right: 0,
                left: 0,
              }}
            />
          )}

          {/* Once the image is visible, start downloading the image */}
          {this.state.isVisible && (
             this.setState({ imgLoaded: true })}
            />
          )}

      )
    }

    if (responsiveResolution) {
      const image = responsiveResolution
      return (
        <div
          className={`${className ? className : ``} gatsby-image-wrapper`}
          style={{
            position: `relative`,
            overflow: `hidden`,
            width: image.width,
            height: image.height,
            background: `lightgray`,
            ...style,
          }}
          ref={this.handleRef}
        >
          {/* Show the blury base64 image. */}
          {image.base64 && (

          )}

          {/* Show a solid background color. */}
          {backgroundColor && (

          )}

          {/* Once the image is visible, start downloading the image */}
          {this.state.isVisible && (
             this.setState({ imgLoaded: true })}
            />
          )}

      )
    }

    return null
  }
}

Image.defaultProps = {
  fadeIn: true,
  alt: ``,
}

Image.propTypes = {
  responsiveResolution: PropTypes.object,
  responsiveSizes: PropTypes.object,
  fadeIn: PropTypes.bool,
  title: PropTypes.string,
  alt: PropTypes.string,
  className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // Support Glamor's css prop.
  style: PropTypes.object,
  backgroundColor: PropTypes.string,
  wrapperClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // Support Glamor's css prop.
}

export default Image
<commit_msg>syntax should now be 'func' (#2296)<commit_after>import React from "react"
import PropTypes from "prop-types"

let io
const listeners = []
if (typeof window !== `undefined` && window.IntersectionObserver) {
  io = new window.IntersectionObserver(
    entries => {
      entries.forEach(entry => {
        listeners.forEach(l => {
          if (l[0] === entry.target) {
            if (entry.isIntersecting) {
              io.unobserve(l[0])
              l[1]()
            }
          }
        })
      })
    },
    { rootMargin: `200px` }
  )
}

const listenToIntersections = (el, cb) => {
  io.observe(el)
  listeners.push([el, cb])
}

const Img = props => {
  const { opacity, onLoad, ...otherProps } = props
  return (
    <img
      {...otherProps}
      onLoad={onLoad}
      style={{
        position: `absolute`,
        top: 0,
        left: 0,
        transition: `opacity 0.5s`,
        opacity,
        width: `100%`,
        height: `100%`,
        objectFit: `cover`,
        objectPosition: `center`,
      }}
    />
  )
}

Img.propTypes = {
  opacity: PropTypes.number,
  onLoad: PropTypes.func
}

class Image extends React.Component {
  constructor(props) {
    super(props)

    // If this browser doesn't support the IntersectionObserver API
    // we just start downloading the image right away.
    let isVisible = true
    if (typeof window !== `undefined` && window.IntersectionObserver) {
      isVisible = false
    }

    this.state = {
      isVisible,
    }

    this.handleRef = this.handleRef.bind(this)
  }

  handleRef(ref) {
    if (window.IntersectionObserver && ref) {
      listenToIntersections(ref, () => {
        this.setState({ isVisible: true, imgLoaded: false })
      })
    }
  }

  render() {
    const {
      title,
      alt,
      className,
      style,
      responsiveSizes,
      responsiveResolution,
      backgroundColor,
    } = this.props

    if (responsiveSizes) {
      const image = responsiveSizes
      return (
        <div
          className={`${className ? className : ``} gatsby-image-wrapper`}
          style={{
            position: `relative`,
            overflow: `hidden`,
            ...style,
          }}
          ref={this.handleRef}
        >
          {/* Preserve the aspect ratio. */}
          <div
            style={{
              width: `100%`,
              paddingBottom: `${100 / image.aspectRatio}%`,
            }}
          />

          {/* Show the blury base64 image. */}
          {image.base64 && (

          )}

          {/* Show a solid background color. */}
          {backgroundColor && (
            <div
              title={title}
              style={{
                backgroundColor: backgroundColor,
                position: `absolute`,
                top: 0,
                bottom: 0,
                right: 0,
                left: 0,
              }}
            />
          )}

          {/* Once the image is visible, start downloading the image */}
          {this.state.isVisible && (
             this.setState({ imgLoaded: true })}
            />
          )}

      )
    }

    if (responsiveResolution) {
      const image = responsiveResolution
      return (
        <div
          className={`${className ? className : ``} gatsby-image-wrapper`}
          style={{
            position: `relative`,
            overflow: `hidden`,
            width: image.width,
            height: image.height,
            background: `lightgray`,
            ...style,
          }}
          ref={this.handleRef}
        >
          {/* Show the blury base64 image. */}
          {image.base64 && (

          )}

          {/* Show a solid background color. */}
          {backgroundColor && (

          )}

          {/* Once the image is visible, start downloading the image */}
          {this.state.isVisible && (
             this.setState({ imgLoaded: true })}
            />
          )}

      )
    }

    return null
  }
}

Image.defaultProps = {
  fadeIn: true,
  alt: ``,
}

Image.propTypes = {
  responsiveResolution: PropTypes.object,
  responsiveSizes: PropTypes.object,
  fadeIn: PropTypes.bool,
  title: PropTypes.string,
  alt: PropTypes.string,
  className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // Support Glamor's css prop.
  style: PropTypes.object,
  backgroundColor: PropTypes.string,
  wrapperClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // Support Glamor's css prop.
}

export default Image
<|endoftext|>