<commit_before>
/*
 *  This class represent Employee's allowance.
 *
 *  As allowance became quite complicated entity, which is calculated
 *  based on few sources, there was decision to move allowance calculation
 *  logic out into its own class.
 *
 * */

"use strict";

const
  moment = require('moment'),
  Promise= require('bluebird'),
  Joi    = require('joi');

/*
 *  Section where we declare interfaces used in methods for this class.
 * */

const

  schema_user = Joi
    .object()
    .required(),

  schema_year = Joi
    .object()
    .type(moment)
    // Consider removing defaults
    .default(() => moment.utc(), 'Default year is current one'),

  schema_now = Joi
    .object()
    .type(moment)
    // Consider removing defaults
    // Note on this line: once it used to derive now from user's company
    // get_now() method, but Joi.js has high penalty on defaults which
    // use function with 'context' so I have removed it.
    // Yes it is less precise but much more faster code.
    .default(() => moment.utc(), 'Default is UTC one not from company specific'),

  schema_promise_allowance = Joi.object().required().keys({
    year : schema_year,
    user : schema_user,
    now  : schema_now,
  }),

  scheme_constructor = Joi.object().required().keys({
    year : schema_year,
    user : schema_user,

    number_of_days_taken_from_allowance   : Joi.number().required(),
    manual_adjustment : Joi.number().required(),
    carry_over        : Joi.number().required(),
    nominal_allowance : Joi.number().required(),
    //
   // TODO now needs to replace year parameter (year should just be derived from now)
    now : schema_now,
  });

/*
 *  Class definition.
 *
 * */

class UserAllowance {

  constructor(args) {

    // Validate provided parameters
    args = Joi.attempt(
      args,
      scheme_constructor,
      'Failed parameters validation for UserAllowance constructor'
    );

    let self = this;

    // Private properties (not to be accessed directly)
    self._user                                = args.user;
    self._number_of_days_taken_from_allowance = args.number_of_days_taken_from_allowance;
    self._manual_adjustment                   = args.manual_adjustment;
    self._carry_over                          = args.carry_over;
    self._nominal_allowance                   = args.nominal_allowance;
    self._now                                 = args.now;
  }

  get total_number_of_days_in_allowance() {
    let self = this;

    return (self.nominal_allowance +
      self.carry_over +
      self.manual_adjustment +
      self.employement_range_adjustment);
  }

  get number_of_days_taken_from_allowance() {
    return this._number_of_days_taken_from_allowance;
  }

  get manual_adjustment() {
    return this._manual_adjustment;
  }

  get carry_over() {
    return this._carry_over;
  }

  get nominal_allowance() {
    return this._nominal_allowance;
  }

  get number_of_days_available_in_allowance() {
    let self = this;

    return (
      self.total_number_of_days_in_allowance
      - self.number_of_days_taken_from_allowance
      + (self.is_accrued_allowance ? self.accrued_adjustment : 0)
    );
  }

  get is_accrued_allowance() {
    return !! this.user.department.is_accrued_allowance;
  }

  get user() {
    return this._user;
  }

  get employement_range_adjustment() {
    let
      self = this,
      now  = self._now.clone();

    if (
      now.year() !== moment.utc(self.user.start_date).year()
      && ( ! self.user.end_date || moment.utc(self.user.end_date).year() > now.year() )
    ){
      return 0;
    }

    let start_date = moment.utc(self.user.start_date).year() === now.year()
      ? moment.utc(self.user.start_date)
      : now.clone().startOf('year'),
    end_date = self.user.end_date && moment.utc(self.user.end_date).year() <= now.year()
      ? moment.utc(self.user.end_date)
      : now.clone().endOf('year');

    return -1*(self.nominal_allowance - Math.round(
      self.nominal_allowance * end_date.diff(start_date, 'days') / 365
    ));
  }

  /*
   *  Accrued adjustment affects all total allowance components BUT carried
   *  over part. Because "carry over" part was already deserved.
   *
   * */
  get accrued_adjustment() {
    let
      self = this,
      now  = self._now.clone();

    // Consider only following parts of allowance when calculating accrual
    // adjustment:
    //  * nominal allowance
    //  * manual adjustment
    //  * adjustment based in start/end day of employment
    // Other components do not make sense, e.g.:
    //  * carried over part - it could be immediately used as employee
    //    already worked on them last year
    let allowance = self.nominal_allowance
      + self.manual_adjustment
      + self.employement_range_adjustment;

    let period_starts_at = moment.utc(self.user.start_date).year() === now.year()
      ? moment.utc(self.user.start_date)
      : now.clone().startOf('year');

    let period_ends_at = self.user.end_date && moment.utc(self.user.end_date).year() <= now.year()
      ? moment.utc(self.user.end_date)
      : now.clone().endOf('year');

    let days_in_period = period_ends_at.diff( period_starts_at, 'days' );

    let delta = allowance * period_ends_at.diff( now, 'days' ) / days_in_period;

    return -1 * (Math.round(delta * 2) / 2).toFixed(1);
  }

  /*
   *  The idea of this static method is to be constructor for UserAllowance class.
   *  It takes parameters and perform all necessary (and costly) actions to fetch
   *  all info required for allowance calculation for given user and year.
   * */
  static promise_allowance(args) {

    args = Joi.attempt(
      args,
      schema_promise_allowance,
      'Failed to validate parameters for promise_allowance'
    );

    let
      user = args.user,
      year = args.year,
      number_of_days_taken_from_allowance,
      manual_adjustment,
      carried_over_allowance;

    return Promise

      // We code below relies on user to have my_leaves fetched onto it, so do it if needed
      .resolve(
        user.my_leaves === undefined ? user.reload_with_leave_details({year}) : 1
      )

      // Fetch adjustment and Carry over allowance
      .then(() => user.promise_adjustment_and_carry_over_for_year(year))
      .then(adjustment_and_coa => {
        manual_adjustment      = adjustment_and_coa.adjustment;
        carried_over_allowance = adjustment_and_coa.carried_over_allowance;
        return Promise.resolve();
      })

      .then(() => Promise.resolve( number_of_days_taken_from_allowance = user.calculate_number_of_days_taken_from_allowance({ year : year.format('YYYY') }) ))

      // Got all necessary data for UserAllowance object so build it!
      .then(() => {
        const args = {
          user : user,
//          year : year,
          number_of_days_taken_from_allowance : number_of_days_taken_from_allowance,
          manual_adjustment                   : manual_adjustment,
          carry_over                          : carried_over_allowance,
          nominal_allowance                   : user.department.allowance,
        };

        if ( year && year.year() !== moment.utc().year() ) {
          args.now = year.startOf('year');
        }

        return new UserAllowance(args);
      });
  }
}

module.exports = UserAllowance;
<commit_msg>Ditch unused parameter: year<commit_after>
/*
 *  This class represent Employee's allowance.
 *
 *  As allowance became quite complicated entity, which is calculated
 *  based on few sources, there was decision to move allowance calculation
 *  logic out into its own class.
 *
 * */

"use strict";

const
  moment = require('moment'),
  Promise= require('bluebird'),
  Joi    = require('joi');

/*
 *  Section where we declare interfaces used in methods for this class.
 * */

const

  schema_user = Joi
    .object()
    .required(),

  schema_year = Joi
    .object()
    .type(moment)
    // Consider removing defaults
    .default(() => moment.utc(), 'Default year is current one'),

  schema_now = Joi
    .object()
    .type(moment)
    // Consider removing defaults
    // Note on this line: once it used to derive now from user's company
    // get_now() method, but Joi.js has high penalty on defaults which
    // use function with 'context' so I have removed it.
    // Yes it is less precise but much more faster code.
    .default(() => moment.utc(), 'Default is UTC one not from company specific'),

  schema_promise_allowance = Joi.object().required().keys({
    year : schema_year,
    user : schema_user,
    now  : schema_now,
  }),

  scheme_constructor = Joi.object().required().keys({
    user : schema_user,

    number_of_days_taken_from_allowance   : Joi.number().required(),
    manual_adjustment : Joi.number().required(),
    carry_over        : Joi.number().required(),
    nominal_allowance : Joi.number().required(),
    now : schema_now,
  });

/*
 *  Class definition.
 *
 * */

class UserAllowance {

  constructor(args) {

    // Validate provided parameters
    args = Joi.attempt(
      args,
      scheme_constructor,
      'Failed parameters validation for UserAllowance constructor'
    );

    const self = this;

    // Private properties (not to be accessed directly)
    self._user                                = args.user;
    self._number_of_days_taken_from_allowance = args.number_of_days_taken_from_allowance;
    self._manual_adjustment                   = args.manual_adjustment;
    self._carry_over                          = args.carry_over;
    self._nominal_allowance                   = args.nominal_allowance;
    self._now                                 = args.now;
  }

  get total_number_of_days_in_allowance() {
    const self = this;

    return (self.nominal_allowance +
      self.carry_over +
      self.manual_adjustment +
      self.employement_range_adjustment);
  }

  get number_of_days_taken_from_allowance() {
    return this._number_of_days_taken_from_allowance;
  }

  get manual_adjustment() {
    return this._manual_adjustment;
  }

  get carry_over() {
    return this._carry_over;
  }

  get nominal_allowance() {
    return this._nominal_allowance;
  }

  get number_of_days_available_in_allowance() {
    const self = this;

    return (
      self.total_number_of_days_in_allowance
      - self.number_of_days_taken_from_allowance
      + (self.is_accrued_allowance ? self.accrued_adjustment : 0)
    );
  }

  get is_accrued_allowance() {
    return !! this.user.department.is_accrued_allowance;
  }

  get user() {
    return this._user;
  }

  get employement_range_adjustment() {
    let
      self = this,
      now  = self._now.clone();

    if (
      now.year() !== moment.utc(self.user.start_date).year()
      && ( ! self.user.end_date || moment.utc(self.user.end_date).year() > now.year() )
    ){
      return 0;
    }

    let start_date = moment.utc(self.user.start_date).year() === now.year()
      ? moment.utc(self.user.start_date)
      : now.clone().startOf('year'),
    end_date = self.user.end_date && moment.utc(self.user.end_date).year() <= now.year()
      ? moment.utc(self.user.end_date)
      : now.clone().endOf('year');

    return -1*(self.nominal_allowance - Math.round(
      self.nominal_allowance * end_date.diff(start_date, 'days') / 365
    ));
  }

  /*
   *  Accrued adjustment affects all total allowance components BUT carried
   *  over part. Because "carry over" part was already deserved.
   *
   * */
  get accrued_adjustment() {
    const
      self = this,
      now  = self._now.clone();

    // Consider only following parts of allowance when calculating accrual
    // adjustment:
    //  * nominal allowance
    //  * manual adjustment
    //  * adjustment based in start/end day of employment
    // Other components do not make sense, e.g.:
    //  * carried over part - it could be immediately used as employee
    //    already worked on them last year
    const allowance = self.nominal_allowance
      + self.manual_adjustment
      + self.employement_range_adjustment;

    const period_starts_at = moment.utc(self.user.start_date).year() === now.year()
      ? moment.utc(self.user.start_date)
      : now.clone().startOf('year');

    const period_ends_at = self.user.end_date && moment.utc(self.user.end_date).year() <= now.year()
      ? moment.utc(self.user.end_date)
      : now.clone().endOf('year');

    let days_in_period = period_ends_at.diff( period_starts_at, 'days' );

    let delta = allowance * period_ends_at.diff( now, 'days' ) / days_in_period;

    return -1 * (Math.round(delta * 2) / 2).toFixed(1);
  }

  /*
   *  The idea of this static method is to be constructor for UserAllowance class.
   *  It takes parameters and perform all necessary (and costly) actions to fetch
   *  all info required for allowance calculation for given user and year.
   * */
  static promise_allowance(args) {

    args = Joi.attempt(
      args,
      schema_promise_allowance,
      'Failed to validate parameters for promise_allowance'
    );

    let
      user = args.user,
      year = args.year,
      number_of_days_taken_from_allowance,
      manual_adjustment,
      carried_over_allowance;

    return Promise

      // We code below relies on user to have my_leaves fetched onto it, so do it if needed
      .resolve(
        user.my_leaves === undefined ? user.reload_with_leave_details({year}) : 1
      )

      // Fetch adjustment and Carry over allowance
      .then(() => user.promise_adjustment_and_carry_over_for_year(year))
      .then(adjustment_and_coa => {
        manual_adjustment      = adjustment_and_coa.adjustment;
        carried_over_allowance = adjustment_and_coa.carried_over_allowance;
        return Promise.resolve();
      })

      .then(() => Promise.resolve( number_of_days_taken_from_allowance = user.calculate_number_of_days_taken_from_allowance({ year : year.format('YYYY') }) ))

      // Got all necessary data for UserAllowance object so build it!
      .then(() => {
        const args = {
          user,
          manual_adjustment,
          number_of_days_taken_from_allowance,
          carry_over:        carried_over_allowance,
          nominal_allowance: user.department.allowance,
        };

        if ( year && year.year() !== moment.utc().year() ) {
          args.now = year.startOf('year');
        }

        return new UserAllowance(args);
      });
  }
}

module.exports = UserAllowance;
<|endoftext|>


<commit_before>import namehash from 'eth-ens-namehash';

/*global web3, EmbarkJS*/
let __embarkENS = {};

// resolver interface
__embarkENS.resolverInterface = [
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "addr",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "content",
    "outputs": [
      {
        "name": "",
        "type": "bytes32"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "name",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "kind",
        "type": "bytes32"
      }
    ],
    "name": "has",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "addr",
        "type": "address"
      }
    ],
    "name": "setAddr",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "hash",
        "type": "bytes32"
      }
    ],
    "name": "setContent",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "name",
        "type": "string"
      }
    ],
    "name": "setName",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "contentType",
        "type": "uint256"
      }
    ],
    "name": "ABI",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "bytes"
      }
    ],
    "payable": false,
    "type": "function"
  }
];

__embarkENS.registryAddresses = {
  // Mainnet
  "1": "0x314159265dd8dbb310642f98f50c066173c1259b",
  // Ropsten
  "3": "0x112234455c3a32fd11230c42e7bccd4a84e02010",
  // Rinkeby
  "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
};

__embarkENS.setProvider = function () {
  const self = this;
  // get network id and then assign ENS contract based on that
  let registryAddresses = this.registryAddresses;
  this.ens = null;
  web3.eth.net.getId().then(id => {
    if (registryAddresses[id] !== undefined) {
      EmbarkJS.onReady(() => {
        self.ens = new EmbarkJS.Contract({abi: self.registryInterface, address: registryAddresses[id]});
      });
    }
    // todo: deploy at this point
  }).catch(e => {
    if (e.message.indexOf('Provider not set or invalid') > -1) {
      console.warn('ENS is not available in this chain');
      return;
    }
    console.error(e);
  });
};

__embarkENS.resolve = function (name) {
  const self = this;

  if (self.ens === undefined) return;

  let node = namehash.hash(name);

  return self.ens.methods.resolver(node).call().then((resolverAddress) => {
    let resolverContract = new EmbarkJS.Contract({abi: self.resolverInterface, address: resolverAddress});
    return resolverContract.methods.addr(node).call();
  }).then((addr) => {
    return addr;
  }).catch(err => err);
};

__embarkENS.lookup = function (address) {
  const self = this;

  if (!self.ens) {
    console.log("ENS provider not set. Exiting.")
    return;
  }
  if (address.startsWith("0x")) address = address.slice(2);

  let node = namehash.hash(address.toLowerCase() + ".addr.reverse");

  return self.ens.methods.resolver(node).call().then((resolverAddress) => {
    let resolverContract = new EmbarkJS.Contract({abi: self.resolverInterface, address: resolverAddress});
    return resolverContract.methods.name(node).call();
  }).catch(err => err);
};
<commit_msg>missing semicolon<commit_after>import namehash from 'eth-ens-namehash';

/*global web3, EmbarkJS*/
let __embarkENS = {};

// resolver interface
__embarkENS.resolverInterface = [
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "addr",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "content",
    "outputs": [
      {
        "name": "",
        "type": "bytes32"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "name",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "kind",
        "type": "bytes32"
      }
    ],
    "name": "has",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "addr",
        "type": "address"
      }
    ],
    "name": "setAddr",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "hash",
        "type": "bytes32"
      }
    ],
    "name": "setContent",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "name",
        "type": "string"
      }
    ],
    "name": "setName",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "contentType",
        "type": "uint256"
      }
    ],
    "name": "ABI",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "bytes"
      }
    ],
    "payable": false,
    "type": "function"
  }
];

__embarkENS.registryAddresses = {
  // Mainnet
  "1": "0x314159265dd8dbb310642f98f50c066173c1259b",
  // Ropsten
  "3": "0x112234455c3a32fd11230c42e7bccd4a84e02010",
  // Rinkeby
  "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
};

__embarkENS.setProvider = function () {
  const self = this;
  // get network id and then assign ENS contract based on that
  let registryAddresses = this.registryAddresses;
  this.ens = null;
  web3.eth.net.getId().then(id => {
    if (registryAddresses[id] !== undefined) {
      EmbarkJS.onReady(() => {
        self.ens = new EmbarkJS.Contract({abi: self.registryInterface, address: registryAddresses[id]});
      });
    }
    // todo: deploy at this point
  }).catch(e => {
    if (e.message.indexOf('Provider not set or invalid') > -1) {
      console.warn('ENS is not available in this chain');
      return;
    }
    console.error(e);
  });
};

__embarkENS.resolve = function (name) {
  const self = this;

  if (self.ens === undefined) return;

  let node = namehash.hash(name);

  return self.ens.methods.resolver(node).call().then((resolverAddress) => {
    let resolverContract = new EmbarkJS.Contract({abi: self.resolverInterface, address: resolverAddress});
    return resolverContract.methods.addr(node).call();
  }).then((addr) => {
    return addr;
  }).catch(err => err);
};

__embarkENS.lookup = function (address) {
  const self = this;

  if (!self.ens) {
    console.log("ENS provider not set. Exiting.");
    return;
  }
  if (address.startsWith("0x")) address = address.slice(2);

  let node = namehash.hash(address.toLowerCase() + ".addr.reverse");

  return self.ens.methods.resolver(node).call().then((resolverAddress) => {
    let resolverContract = new EmbarkJS.Contract({abi: self.resolverInterface, address: resolverAddress});
    return resolverContract.methods.name(node).call();
  }).catch(err => err);
};
<|endoftext|>


<commit_before>/*global EmbarkJS, web3, registerSubDomain, namehash*/

let __embarkENS = {};

// resolver interface
__embarkENS.resolverInterface = [
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "addr",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "content",
    "outputs": [
      {
        "name": "",
        "type": "bytes32"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "name",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "addr",
        "type": "address"
      }
    ],
    "name": "setAddr",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "hash",
        "type": "bytes32"
      }
    ],
    "name": "setContent",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "name",
        "type": "string"
      }
    ],
    "name": "setName",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "contentType",
        "type": "uint256"
      }
    ],
    "name": "ABI",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "bytes"
      }
    ],
    "payable": false,
    "type": "function"
  }
];

const providerNotSetError = 'ENS provider not set';
const NoDecodeAddrError = 'Error: Couldn\'t decode address from ABI: 0x';
const NoDecodeStringError = 'ERROR: The returned value is not a convertible string: 0x0';
const reverseAddrSuffix = '.addr.reverse';
const voidAddress = '0x0000000000000000000000000000000000000000';

__embarkENS.registryAddresses = {
  // Mainnet
  "1": "0x314159265dd8dbb310642f98f50c066173c1259b",
  // Ropsten
  "3": "0x112234455c3a32fd11230c42e7bccd4a84e02010",
  // Rinkeby
  "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
};

__embarkENS.setProvider = function (config) {
  const self = this;
  const ERROR_MESSAGE = 'ENS is not available in this chain';
  self.registration = config.registration;
  self.env = config.env;

  EmbarkJS.onReady(() => {
    web3.eth.net.getId()
      .then((id) => {
      const registryAddress = self.registryAddresses[id] || config.registryAddress;
      self._isAvailable = true;
      self.ens = new EmbarkJS.Contract({abi: config.registryAbi, address: registryAddress, web3: web3});
      self.registrar = new EmbarkJS.Contract({abi: config.registrarAbi, address: config.registrarAddress, web3: web3});
      self.resolver = new EmbarkJS.Contract({abi: config.resolverAbi, address: config.resolverAddress, web3: web3});
    })
      .catch(err => {
        if (err.message.indexOf('Provider not set or invalid') > -1) {
          console.warn(ERROR_MESSAGE);
          return;
        }
        console.error(err);
      });
  });
};

__embarkENS.resolve = function (name, callback) {
  callback = callback || function () {};
  if (!this.ens) {
    return callback(providerNotSetError);
  }
  let node = namehash.hash(name);

  function cb(err, addr) {
    if (err === NoDecodeAddrError) {
      return callback(name + " is not registered", "0x");
    }
    callback(err, addr);
  }

  return this.ens.methods.resolver(node).call((err, resolverAddress) => {
    if (err) {
      return cb(err);
    }
    if (resolverAddress === voidAddress) {
      return cb('Name not yet registered');
    }
    let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress, web3: web3});
    resolverContract.methods.addr(node).call(cb);
  });
};

__embarkENS.lookup = function (address, callback) {
  callback = callback || function () {};
  if (!this.ens) {
    return callback(providerNotSetError);
  }
  if (address.startsWith("0x")) {
    address = address.slice(2);
  }
  let node = web3.utils.soliditySha3(address.toLowerCase() + reverseAddrSuffix);

  function cb(err, name) {
    if (err === NoDecodeStringError || err === NoDecodeAddrError) {
      return callback('Address does not resolve to name. Try syncing chain.');
    }
    return callback(err, name);
  }

  return this.ens.methods.resolver(node).call((err, resolverAddress) => {
    if (err) {
      return cb(err);
    }
    if (resolverAddress === voidAddress) {
      return cb('Address not associated to a resolver');
    }
    let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress, web3: web3 });
    resolverContract.methods.name(node).call(cb);
  });
};

__embarkENS.registerSubDomain = function (name, address, callback) {
  callback = callback || function () {};

  if (this.env !== 'development' && this.env !== 'privatenet') {
    return callback('Sub-domain registration is only available in development or privatenet mode');
  }
  if (!this.registration || !this.registration.rootDomain) {
    return callback('No rootDomain is declared in config/namesystem.js (register.rootDomain). Unable to register a subdomain until then.');
  }
  if (!address || !web3.utils.isAddress(address)) {
    return callback('You need to specify a valid address for the subdomain');
  }

  // Register function generated by the index
  registerSubDomain(this.ens, this.registrar, this.resolver, web3.eth.defaultAccount, name, this.registration.rootDomain,
    web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix), address, console, EmbarkJS.Utils.secureSend, callback);
};

__embarkENS.isAvailable = function () {
  return Boolean(this._isAvailable);
};
<commit_msg>Fix lint<commit_after>/*global EmbarkJS, web3, registerSubDomain, namehash*/

let __embarkENS = {};

// resolver interface
__embarkENS.resolverInterface = [
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "addr",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "content",
    "outputs": [
      {
        "name": "",
        "type": "bytes32"
      }
    ],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      }
    ],
    "name": "name",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "addr",
        "type": "address"
      }
    ],
    "name": "setAddr",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "hash",
        "type": "bytes32"
      }
    ],
    "name": "setContent",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "name",
        "type": "string"
      }
    ],
    "name": "setName",
    "outputs": [],
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "node",
        "type": "bytes32"
      },
      {
        "name": "contentType",
        "type": "uint256"
      }
    ],
    "name": "ABI",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      },
      {
        "name": "",
        "type": "bytes"
      }
    ],
    "payable": false,
    "type": "function"
  }
];

const providerNotSetError = 'ENS provider not set';
const NoDecodeAddrError = 'Error: Couldn\'t decode address from ABI: 0x';
const NoDecodeStringError = 'ERROR: The returned value is not a convertible string: 0x0';
const reverseAddrSuffix = '.addr.reverse';
const voidAddress = '0x0000000000000000000000000000000000000000';

__embarkENS.registryAddresses = {
  // Mainnet
  "1": "0x314159265dd8dbb310642f98f50c066173c1259b",
  // Ropsten
  "3": "0x112234455c3a32fd11230c42e7bccd4a84e02010",
  // Rinkeby
  "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
};

__embarkENS.setProvider = function (config) {
  const self = this;
  const ERROR_MESSAGE = 'ENS is not available in this chain';
  self.registration = config.registration;
  self.env = config.env;

  EmbarkJS.onReady(() => {
    web3.eth.net.getId()
      .then((id) => {
      const registryAddress = self.registryAddresses[id] || config.registryAddress;
      self._isAvailable = true;
      self.ens = new EmbarkJS.Contract({abi: config.registryAbi, address: registryAddress, web3: web3});
      self.registrar = new EmbarkJS.Contract({abi: config.registrarAbi, address: config.registrarAddress, web3: web3});
      self.resolver = new EmbarkJS.Contract({abi: config.resolverAbi, address: config.resolverAddress, web3: web3});
    })
      .catch(err => {
        if (err.message.indexOf('Provider not set or invalid') > -1) {
          console.warn(ERROR_MESSAGE);
          return;
        }
        console.error(err);
      });
  });
};

__embarkENS.resolve = function (name, callback) {
  callback = callback || function () {};
  if (!this.ens) {
    return callback(providerNotSetError);
  }
  let node = namehash.hash(name);

  function cb(err, addr) {
    if (err === NoDecodeAddrError) {
      return callback(name + " is not registered", "0x");
    }
    callback(err, addr);
  }

  return this.ens.methods.resolver(node).call((err, resolverAddress) => {
    if (err) {
      return cb(err);
    }
    if (resolverAddress === voidAddress) {
      return cb('Name not yet registered');
    }
    let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress, web3: web3});
    resolverContract.methods.addr(node).call(cb);
  });
};

__embarkENS.lookup = function (address, callback) {
  callback = callback || function () {};
  if (!this.ens) {
    return callback(providerNotSetError);
  }
  if (address.startsWith("0x")) {
    address = address.slice(2);
  }
  let node = web3.utils.soliditySha3(address.toLowerCase() + reverseAddrSuffix);

  function cb(err, name) {
    if (err === NoDecodeStringError || err === NoDecodeAddrError) {
      return callback('Address does not resolve to name. Try syncing chain.');
    }
    return callback(err, name);
  }

  return this.ens.methods.resolver(node).call((err, resolverAddress) => {
    if (err) {
      return cb(err);
    }
    if (resolverAddress === voidAddress) {
      return cb('Address not associated to a resolver');
    }
    let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress, web3: web3});
    resolverContract.methods.name(node).call(cb);
  });
};

__embarkENS.registerSubDomain = function (name, address, callback) {
  callback = callback || function () {};

  if (this.env !== 'development' && this.env !== 'privatenet') {
    return callback('Sub-domain registration is only available in development or privatenet mode');
  }
  if (!this.registration || !this.registration.rootDomain) {
    return callback('No rootDomain is declared in config/namesystem.js (register.rootDomain). Unable to register a subdomain until then.');
  }
  if (!address || !web3.utils.isAddress(address)) {
    return callback('You need to specify a valid address for the subdomain');
  }

  // Register function generated by the index
  registerSubDomain(this.ens, this.registrar, this.resolver, web3.eth.defaultAccount, name, this.registration.rootDomain,
    web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix), address, console, EmbarkJS.Utils.secureSend, callback);
};

__embarkENS.isAvailable = function () {
  return Boolean(this._isAvailable);
};
<|endoftext|>


<commit_before>var path = require('path'),
    _ = require('lodash'),
    File = require('vinyl'),
    eachInStream = require('../util/eachInStream');

module.exports = initPlugin;

var ORDER = ['setup', 'ym', 'plus', 'map', 'async', 'fallback', 'namespace'];

var parts = null;

/**
 * Joins all 'init#' parts into a single `init.js` file with the right order.
 * @alias "modules.init"
 * @returns {stream.Transform} Stream
 */
function initPlugin () {
    parts = [];

    return eachInStream(processFile, createInitFile);
}

function processFile (file, _, cb) {
    if (file.relative.indexOf('init#') === 0) {
        var partName = file.relative.replace('init#', ''),
            index = ORDER.indexOf(partName);

        parts[index >= 0 ? index : parts.length] = Buffer.concat([new Buffer('\n'), file.contents, new Buffer('\n')]);

        cb();
    } else {
        cb(null, file);
    }
}

function createInitFile (cb) {
    this.push(new File({
        path: path.join(process.cwd(), 'init.js'),
        contents: Buffer.concat(_.compact(parts))
    }));

    cb();
}<commit_msg>fix for losing of custom `init#` parts<commit_after>var path = require('path'),
    _ = require('lodash'),
    File = require('vinyl'),
    eachInStream = require('../util/eachInStream');

module.exports = initPlugin;

var ORDER = ['setup', 'ym', 'plus', 'map', 'async', 'fallback', 'namespace'];

var parts = null,
    pushIndex = ORDER.length;

/**
 * Joins all 'init#' parts into a single `init.js` file with the right order.
 * @alias "modules.init"
 * @returns {stream.Transform} Stream
 */
function initPlugin () {
    parts = [];

    return eachInStream(processFile, createInitFile);
}

function processFile (file, _, cb) {
    if (file.relative.indexOf('init#') === 0) {
        var partName = file.relative.replace('init#', ''),
            index = ORDER.indexOf(partName);

        parts[index >= 0 ? index : pushIndex++] = Buffer.concat([new Buffer('\n'), file.contents, new Buffer('\n')]);

        cb();
    } else {
        cb(null, file);
    }
}

function createInitFile (cb) {
    this.push(new File({
        path: path.join(process.cwd(), 'init.js'),
        contents: Buffer.concat(_.compact(parts))
    }));

    cb();
}<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var UglifyJS = require('uglify-js');
var Vulcanize = require('vulcanize');
var minimatches = require('../minimatches');
var Batch = require('../batch');
var Processor = require('../processor');

var processor = new Processor();

function FSResolver(config, inputs) {
	this.config = config;
	this.inputs = inputs;
}

FSResolver.prototype.accept = function(uri, deferred) {
	var config = this.config;

	// TODO: return false if uri is not a local input path

	var input = _.find(this.inputs, { path: uri });
	if (input) {
		var text = input.data;
		try {
			// Minify JS and CSS that is already inlined (e.g. in 3rd party bower components)
			// TODO: Move this out into a separate command and processor? (e.g: make:inline before make:components)
			if (config.minimizeInline) {
				var uglifyOptions = _.extend({
					fromString: true
				}, config.uglify);

				// TODO: Use dom5.parse (like polyclean) instead of regex string replaces below
				// This could go very wrong, e.g: when you have JS that includes strings like <script> or <style>
				text = text.replace(/(<script\>)([\s\S]*?)(<\/script\>)/gm, function(match, open, js, close) {
					js = UglifyJS.minify(js, uglifyOptions).code;
					return open + js + close;
				});

				text = text.replace(/(<style.*?\>)([\s\S]*?)(<\/style\>)/gm, function(match, open, css, close) {
					css = css.
						// Reduce 2 or more spaces to one and remove leading and trailing spaces (source: polyclean)
						replace(/[\r\n]/g, '').
						replace(/ {2,}/g, ' ').
						replace(/(^|[;,\:\{\}]) /g, '$1').
						replace(/ ($|[;,\{\}])/g, '$1').
						// Remove comments (TODO: Ensure this is safe)
						replace(/\/\*.*?\*\//g, '');
					return open + css + close;
				});

				text = text.replace(/<!--.*?-->/gm, '');
			}

			deferred.resolve(text);
		} catch(error) {
			deferred.reject(error);
		}
	} else {
		deferred.reject(new Error('File not found in inputs: ' + uri));
	}

	return true;
};

processor.getBatches = function(inputPaths) {
	var bowerPath = inputPaths[0] === this.config.bower && inputPaths.shift();
	if (!inputPaths.length) {
		return [];
	}

	var inputs = inputPaths.map(function(inputPath) {
		// We need to leave component source files in place for image and font etc. references
		// and for any included demo pages to remain working etc. etc.
		return { path: inputPath, isReadOnly: true };
	});

	if (bowerPath) {
		inputs.unshift({ path: bowerPath, isReadOnly: true, type: 'json' });
	}

	return [ new Batch(inputs, [ { path: this.config.output, trackRatio: true } ]) ];
};

processor.process = function(inputs, outputs) {
	this.log.info('process');
	var config = this.config;
	var output = outputs[0];

	var importPaths = minimatches(_.pluck(inputs, 'path'), config.imports);

	// Filter out bower components that are not explicitly depended on to make output more deterministic and clean
	if (inputs[0].path === config.bower) {
		var bowerInput = inputs.shift();
		var bowerDeps = Object.keys(bowerInput.data.dependencies);

		importPaths = importPaths.filter(function(importPath) {
			if (importPath.indexOf('bower_components/') !== 0) {
				return true;
			}
			var bowerName = importPath.match(/bower_components\/([^\/]+)\//)[1];
			return bowerDeps.indexOf(bowerName) >= 0;
		});
	}

	// Generate initial un-vulcanized output data (html that imports all of the components)
	var outputData = importPaths.map(function(importPath) {
		return '<link rel="import" href="' + importPath + '">';
	}).join('\n');

	if (!config.vulcanize) {
		output.resolve(outputData);
		return;
	}

	var files = inputs.concat({
		path: output.path,
		data: outputData
	});

	var vulcanize = new Vulcanize(_.extend({}, config.vulcanize, {
		inputUrl: output.path,
		fsResolver: new FSResolver(config, files)
	}));

	vulcanize.process(output.path, function(error, html) {
		if (error) {
			output.reject(error);
		} else {
			output.resolve(html);
		}
	});
};

module.exports = processor;
<commit_msg>Woops left behind a debug log statement<commit_after>'use strict';

var _ = require('lodash');
var UglifyJS = require('uglify-js');
var Vulcanize = require('vulcanize');
var minimatches = require('../minimatches');
var Batch = require('../batch');
var Processor = require('../processor');

var processor = new Processor();

function FSResolver(config, inputs) {
	this.config = config;
	this.inputs = inputs;
}

FSResolver.prototype.accept = function(uri, deferred) {
	var config = this.config;

	// TODO: return false if uri is not a local input path

	var input = _.find(this.inputs, { path: uri });
	if (input) {
		var text = input.data;
		try {
			// Minify JS and CSS that is already inlined (e.g. in 3rd party bower components)
			// TODO: Move this out into a separate command and processor? (e.g: make:inline before make:components)
			if (config.minimizeInline) {
				var uglifyOptions = _.extend({
					fromString: true
				}, config.uglify);

				// TODO: Use dom5.parse (like polyclean) instead of regex string replaces below
				// This could go very wrong, e.g: when you have JS that includes strings like <script> or <style>
				text = text.replace(/(<script\>)([\s\S]*?)(<\/script\>)/gm, function(match, open, js, close) {
					js = UglifyJS.minify(js, uglifyOptions).code;
					return open + js + close;
				});

				text = text.replace(/(<style.*?\>)([\s\S]*?)(<\/style\>)/gm, function(match, open, css, close) {
					css = css.
						// Reduce 2 or more spaces to one and remove leading and trailing spaces (source: polyclean)
						replace(/[\r\n]/g, '').
						replace(/ {2,}/g, ' ').
						replace(/(^|[;,\:\{\}]) /g, '$1').
						replace(/ ($|[;,\{\}])/g, '$1').
						// Remove comments (TODO: Ensure this is safe)
						replace(/\/\*.*?\*\//g, '');
					return open + css + close;
				});

				text = text.replace(/<!--.*?-->/gm, '');
			}

			deferred.resolve(text);
		} catch(error) {
			deferred.reject(error);
		}
	} else {
		deferred.reject(new Error('File not found in inputs: ' + uri));
	}

	return true;
};

processor.getBatches = function(inputPaths) {
	var bowerPath = inputPaths[0] === this.config.bower && inputPaths.shift();
	if (!inputPaths.length) {
		return [];
	}

	var inputs = inputPaths.map(function(inputPath) {
		// We need to leave component source files in place for image and font etc. references
		// and for any included demo pages to remain working etc. etc.
		return { path: inputPath, isReadOnly: true };
	});

	if (bowerPath) {
		inputs.unshift({ path: bowerPath, isReadOnly: true, type: 'json' });
	}

	return [ new Batch(inputs, [ { path: this.config.output, trackRatio: true } ]) ];
};

processor.process = function(inputs, outputs) {
	var config = this.config;
	var output = outputs[0];

	var importPaths = minimatches(_.pluck(inputs, 'path'), config.imports);

	// Filter out bower components that are not explicitly depended on to make output more deterministic and clean
	if (inputs[0].path === config.bower) {
		var bowerInput = inputs.shift();
		var bowerDeps = Object.keys(bowerInput.data.dependencies);

		importPaths = importPaths.filter(function(importPath) {
			if (importPath.indexOf('bower_components/') !== 0) {
				return true;
			}
			var bowerName = importPath.match(/bower_components\/([^\/]+)\//)[1];
			return bowerDeps.indexOf(bowerName) >= 0;
		});
	}

	// Generate initial un-vulcanized output data (html that imports all of the components)
	var outputData = importPaths.map(function(importPath) {
		return '<link rel="import" href="' + importPath + '">';
	}).join('\n');

	if (!config.vulcanize) {
		output.resolve(outputData);
		return;
	}

	var files = inputs.concat({
		path: output.path,
		data: outputData
	});

	var vulcanize = new Vulcanize(_.extend({}, config.vulcanize, {
		inputUrl: output.path,
		fsResolver: new FSResolver(config, files)
	}));

	vulcanize.process(output.path, function(error, html) {
		if (error) {
			output.reject(error);
		} else {
			output.resolve(html);
		}
	});
};

module.exports = processor;
<|endoftext|>


<commit_before>/*
Language: Haskell
Author: Jeremy Hull <sourdrums@gmail.com>
*/

function(hljs) {

  var COMMENT1 = {
    className: 'haskell_comment',
    begin: '--', end: '$'
  };

  var COMMENT2 = {
    className: 'haskell_comment',
    contains: ['self'],
    begin: '{-', end: '-}'
  };

  var PRAGMA = {
    className: 'haskell_pragma',
    begin: '{-#', end: '#-}'
  };

  var PREPROCESSOR = {
    className: 'haskell_preprocessor',
    begin: '#', end: '$'
  };

  var VARIABLE = {
    className: 'haskell_variable',
    begin: '^[_a-z][\\w\']*'
  };

  // Value, type, class constructors.
  var CONSTRUCTOR = {
    className: 'haskell_constructor',
    begin: '\\b[A-Z][\\w\']*',
    relevance: 0
  };

  // Not [] :: * -> * but lists in module, import, deriving, class context, default etc.
  var LIST = {
    className: 'haskell_list',
    begin: '\\(', end: '\\)',
    illegal: '"',
    contains: [
      PRAGMA,
      COMMENT1,
      COMMENT2,
      PREPROCESSOR,
      {className: 'haskell_constructor', begin: '\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?'},
      VARIABLE
    ]
  };

  var RECORD = {
    className: 'haskell_record',
    begin: '{', end: '}',
    contains: LIST.contains
  };

  return {
    keywords:
      'let in if then else case of where do module import hiding qualified type data ' +
      'newtype deriving class instance as default infix infixl infixr ' +
      'foreign export ccall stdcall cplusplus jvm dotnet safe unsafe ' +
      'family forall mdo proc rec',
    contains: [

      // Top-level constructions.

      {
        className: 'haskell_module',
        begin: '\\bmodule', end: 'where',
        keywords: 'module where',
        contains: [LIST, COMMENT2],
        illegal: '\\W\\.|;'
      },
      {
        className: 'haskell_import',
        begin: '\\bimport', end: '$',
        keywords: 'import qualified as hiding',
        contains: [LIST, COMMENT1, COMMENT2],
        illegal: '\\W\\.|;'
      },

      {
        className: 'haskell_class',
        begin: '\\b(class|instance)', end: 'where',
        keywords: 'class family instance where',
        contains: [CONSTRUCTOR, LIST, COMMENT2]
      },
      {
        className: 'haskell_type',
        begin: '\\b(data|(new)?type)', end: '$',
        keywords: 'data family type newtype deriving',
        contains: [CONSTRUCTOR, LIST, RECORD, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_default',
        begin: '\\bdefault', end: '$',
        keywords: 'default',
        contains: [CONSTRUCTOR, LIST, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_infix',
        begin: '\\b(infix|infixl|infixr)', end: '$',
        keywords: 'infix infixl infixr',
        contains: [hljs.C_NUMBER_MODE, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_foreign',
        begin: '\\bforeign', end: '$',
        keywords: 'foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe',
        contains: [CONSTRUCTOR, hljs.QUOTE_STRING_MODE, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_shebang',
        begin: '#!\\/usr\\/bin\\/env\ runhaskell', end: '$'
      },

      // "Whitespaces".

      PRAGMA,
      COMMENT1,
      COMMENT2,
      PREPROCESSOR,

      // Literals and names.

      {
        className: 'haskell_char',
        begin: '\\s+\'', end: '\'',
        contains: [hljs.BACKSLASH_ESCAPE],
        relevance: 0
      },
      hljs.QUOTE_STRING_MODE,
      hljs.C_NUMBER_MODE,
      CONSTRUCTOR,
      VARIABLE,

      {begin: '->|<-'} // No markup, relevance booster
    ]
  };
}
<commit_msg>Haskell: bug fixes.<commit_after>/*
Language: Haskell
Author: Jeremy Hull <sourdrums@gmail.com>
*/

function(hljs) {

  var COMMENT1 = {
    className: 'haskell_comment',
    begin: '--', end: '$'
  };

  var COMMENT2 = {
    className: 'haskell_comment',
    contains: ['self'],
    begin: '{-', end: '-}'
  };

  var PRAGMA = {
    className: 'haskell_pragma',
    begin: '{-#', end: '#-}'
  };

  var PREPROCESSOR = {
    className: 'haskell_preprocessor',
    begin: '#', end: '$'
  };

  var VARIABLE = {
    className: 'haskell_variable',
    begin: '^[_a-z][\\w\']*'
  };

  // Value, type, class constructors.
  var CONSTRUCTOR = {
    className: 'haskell_constructor',
    begin: '\\b[A-Z][\\w\']*', // TODO: other constructors.
    relevance: 0
  };

  // Not [] :: * -> * but lists in module, import, deriving, class context, default etc.
  var LIST = {
    className: 'haskell_list',
    begin: '\\(', end: '\\)',
    illegal: '"',
    contains: [
      PRAGMA,
      COMMENT1,
      COMMENT2,
      PREPROCESSOR,
      {className: 'haskell_constructor', begin: '\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?'},
      VARIABLE
    ]
  };

  var RECORD = {
    className: 'haskell_record',
    begin: '{', end: '}',
    contains: LIST.contains
  };

  return {
    keywords:
      'let in if then else case of where do module import hiding qualified type data ' +
      'newtype deriving class instance as default infix infixl infixr ' +
      'foreign export ccall stdcall cplusplus jvm dotnet safe unsafe ' +
      'family forall mdo proc rec',
    contains: [

      // Top-level constructions.

      {
        className: 'haskell_module',
        begin: '\\bmodule\ ', end: 'where',
        keywords: 'module where',
        contains: [LIST, COMMENT2],
        illegal: '\\W\\.|;'
      },
      {
        className: 'haskell_import',
        begin: '\\bimport\ ', end: '$',
        keywords: 'import qualified as hiding',
        contains: [LIST, COMMENT1, COMMENT2],
        illegal: '\\W\\.|;'
      },

      {
        className: 'haskell_class',
        begin: '\\b(class\ |instance\ )', end: 'where',
        keywords: 'class family instance where',
        contains: [CONSTRUCTOR, LIST, COMMENT2]
      },
      {
        className: 'haskell_type',
        begin: '\\b(data\ |(new)?type\ )', end: '$',
        keywords: 'data family type newtype deriving',
        contains: [CONSTRUCTOR, LIST, RECORD, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_default',
        begin: '\\bdefault\ ', end: '$',
        keywords: 'default',
        contains: [CONSTRUCTOR, LIST, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_infix',
        begin: '\\b(infix\ |infixl\ |infixr\ )', end: '$',
        keywords: 'infix infixl infixr',
        contains: [hljs.C_NUMBER_MODE, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_foreign',
        begin: '\\bforeign\ ', end: '$',
        keywords: 'foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe',
        contains: [CONSTRUCTOR, hljs.QUOTE_STRING_MODE, COMMENT1, COMMENT2]
      },
      {
        className: 'haskell_shebang',
        begin: '#!\\/usr\\/bin\\/env\ runhaskell', end: '$'
      },

      // "Whitespaces".

      PRAGMA,
      COMMENT1,
      COMMENT2,
      PREPROCESSOR,

      // Literals and names.

      // TODO: characters.
      hljs.QUOTE_STRING_MODE,
      hljs.C_NUMBER_MODE,
      CONSTRUCTOR,
      VARIABLE,

      {begin: '->|<-'} // No markup, relevance booster
    ]
  };
}
<|endoftext|>


<commit_before>export default {
  base: {
    remove: '刪除',
    cancel: '取消',
    confirm: '確定',
    inert: '插入',
    width: '宽度',
    height: '高度'
  },
  controls: {
    clear: '清除内容',
    undo: '撤銷',
    redo: '重做',
    fontSize: '字號',
    color: '顏色',
    textColor: '文字顏色',
    backgroundColor: '背景顏色',
    tempColors: '臨時顏色',
    bold: '加粗',
    lineHeight: '行高',
    letterSpacing: '字間距',
    textIndent: '段落縮進',
    increaseIndent: '增加縮進',
    decreaseIndent: '减少縮進',
    border: '邊框',
    italic: '斜體',
    underline: '下劃線',
    strikeThrough: '刪除線',
    fontFamily: '字體',
    textAlign: '文本對齊',
    alignLeft: '居左',
    alignCenter: '居中',
    alignRight: '居右',
    alignJustify: '兩端對齊',
    floatLeft: '左浮動',
    floatRight: '右浮動',
    superScript: '上標',
    subScript: '下標',
    removeStyles: '清除样式',
    headings: '標題',
    header: '標題',
    normal: '常規',
    orderedList: '有序列表',
    unorderedList: '無序列表',
    blockQuote: '引用',
    code: '代碼',
    link: '鏈接',
    unlink: '清除鏈接',
    hr: '水平线',
    media: '媒體',
    mediaLibirary: '媒體库',
    emoji: '小表情',
    fullscreen: '全熒幕',
    exitFullscreen: '退出全熒幕',
  },
  linkEditor: {
    textInputPlaceHolder: '輸入鏈接文字',
    linkInputPlaceHolder: '輸入鏈接地址',
    inputWithEnterPlaceHolder: '輸入鏈接地址並回車',
    openInNewWindow: '在新窗口打開',
    removeLink: '移除鏈接'
  },
  audioPlayer: {
    title: '播放音頻文件'
  },
  videoPlayer: {
    title: '播放視頻文件',
    embedTitle: '嵌入式媒體'
  },
  media: {
    image: '圖像',
    video: '視頻',
    audio: '音頻',
    embed: '嵌入式媒體'
  }
}<commit_msg>feat: 修正繁體中文未翻到的文字，與修正繁體中文用詞 (#685)<commit_after>export default {
  base: {
    remove: '刪除',
    cancel: '取消',
    confirm: '確定',
    inert: '插入',
    width: '寬度',
    height: '高度'
  },
  controls: {
    clear: '清除内容',
    undo: '復原',
    redo: '取消復原',
    fontSize: '字型大小',
    color: '顏色',
    textColor: '文字顏色',
    backgroundColor: '背景顏色',
    tempColors: '臨時顏色',
    bold: '粗體',
    lineHeight: '行高',
    letterSpacing: '字間距',
    textIndent: '段落縮進',
    increaseIndent: '增加縮進',
    decreaseIndent: '减少縮進',
    border: '邊框',
    italic: '斜體',
    underline: '底線',
    strikeThrough: '刪除線',
    fontFamily: '字體',
    textAlign: '文字對齊',
    alignLeft: '置左',
    alignCenter: '置中',
    alignRight: '置右',
    alignJustify: '左右對齊',
    floatLeft: '左浮動',
    floatRight: '右浮動',
    superScript: '上標',
    subScript: '下標',
    removeStyles: '清除樣式',
    headings: '標題',
    header: '標題',
    normal: '常規',
    orderedList: '有序列表',
    unorderedList: '無序列表',
    blockQuote: '引用',
    code: '程式碼',
    link: '連結',
    unlink: '清除連結',
    hr: '水平線',
    media: '媒體',
    mediaLibirary: '媒體庫',
    emoji: '表情符號',
    fullscreen: '全螢幕',
    exitFullscreen: '退出全螢幕',
  },
  linkEditor: {
    textInputPlaceHolder: '輸入連結文字',
    linkInputPlaceHolder: '輸入連結地址',
    inputWithEnterPlaceHolder: '輸入連結地址並換行',
    openInNewWindow: '在新視窗打開',
    removeLink: '移除連結'
  },
  audioPlayer: {
    title: '播放音檔'
  },
  videoPlayer: {
    title: '播放影片',
    embedTitle: '嵌入式媒體'
  },
  media: {
    image: '圖片',
    video: '影片',
    audio: '音檔',
    embed: '嵌入式媒體'
  }
}
<|endoftext|>


<commit_before>/*
 * Adds popup-related methods to all layers.
 */

L.Layer.include({

	bindPopup: function (content, options) {

		if (content instanceof L.Popup) {
			this._popup = content;
		} else {
			if (!this._popup || options) {
				this._popup = new L.Popup(options, this);
			}
			this._popup.setContent(content);
		}

		if (!this._popupHandlersAdded) {
			this.on({
				click: this._openPopup,
				remove: this.closePopup,
				move: this._movePopup
			});
			this._popupHandlersAdded = true;
		}

		return this;
	},

	unbindPopup: function () {
		if (this._popup) {
			this.on({
			    click: this._openPopup,
			    remove: this.closePopup,
			    move: this._movePopup
			});
			this._popupHandlersAdded = false;
			this._popup = null;
		}
		return this;
	},

	openPopup: function (latlng) {
		if (this._popup && this._map) {
			this._map.openPopup(this._popup, latlng || this._latlng || this.getCenter());
		}
		return this;
	},

	closePopup: function () {
		if (this._popup) {
			this._popup._close();
		}
		return this;
	},

	togglePopup: function () {
		if (this._popup) {
			if (this._popup._map) {
				this.closePopup();
			} else {
				this.openPopup();
			}
		}
		return this;
	},

	setPopupContent: function (content) {
		if (this._popup) {
			this._popup.setContent(content);
		}
		return this;
	},

	getPopup: function () {
		return this._popup;
	},

	_openPopup: function (e) {
		this._map.openPopup(this._popup, e.latlng);
	},

	_movePopup: function (e) {
		this._popup.setLatLng(e.latlng);
	}
});
<commit_msg>set the source in bindPopup(popup), close #2354<commit_after>/*
 * Adds popup-related methods to all layers.
 */

L.Layer.include({

	bindPopup: function (content, options) {

		if (content instanceof L.Popup) {
			this._popup = content;
			content._source = this;
		} else {
			if (!this._popup || options) {
				this._popup = new L.Popup(options, this);
			}
			this._popup.setContent(content);
		}

		if (!this._popupHandlersAdded) {
			this.on({
				click: this._openPopup,
				remove: this.closePopup,
				move: this._movePopup
			});
			this._popupHandlersAdded = true;
		}

		return this;
	},

	unbindPopup: function () {
		if (this._popup) {
			this.on({
			    click: this._openPopup,
			    remove: this.closePopup,
			    move: this._movePopup
			});
			this._popupHandlersAdded = false;
			this._popup = null;
		}
		return this;
	},

	openPopup: function (latlng) {
		if (this._popup && this._map) {
			this._map.openPopup(this._popup, latlng || this._latlng || this.getCenter());
		}
		return this;
	},

	closePopup: function () {
		if (this._popup) {
			this._popup._close();
		}
		return this;
	},

	togglePopup: function () {
		if (this._popup) {
			if (this._popup._map) {
				this.closePopup();
			} else {
				this.openPopup();
			}
		}
		return this;
	},

	setPopupContent: function (content) {
		if (this._popup) {
			this._popup.setContent(content);
		}
		return this;
	},

	getPopup: function () {
		return this._popup;
	},

	_openPopup: function (e) {
		this._map.openPopup(this._popup, e.latlng);
	},

	_movePopup: function (e) {
		this._popup.setLatLng(e.latlng);
	}
});
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Link from 'gatsby-link'
import { css } from 'emotion'
import styled from 'emotion/react'
import cx from 'classnames'
import Scroll from 'react-scroll'
import {
  monofont,
  sansfont,
  childLink,
  breakpoint1,
  breakpoint2,
  breakpoint3,
} from './emotion-base'

const ImageSet = styled.div`
  &:not(:last-child) {
    margin-bottom: 60px;

    @media (${breakpoint1}) {
      margin-bottom: 30px;
    }
  }
`

const SetTitle = styled.h3`
  composes: ${sansfont};
  margin: 0 72px 28px 0;
  font-weight: 400;
  font-size: 28px;
  text-align: right;

  @media (${breakpoint1}) {
    text-align: left;
    font-size: 22px;
    margin: 0 0 28px 0;
  }

  @media (${breakpoint3}) {
    margin: 0 0 20px 0;
  }
`

const ImageContainer = styled.div`
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  align-items: flex-end;
  box-sizing: border-box;

  &.center {
    justify-content: center;
  }
`

const ImageItem = styled.div`
  margin: 0 20px 20px 0;
  display: inline-block;
  max-width: 144px;

  & img {
    margin: 0;
    padding: 0;
    max-width: 100%;
    max-height: 144px;
    cursor: pointer;
  }

  &.with-small-text {
    max-width: 204px;

    & img {
      max-height: 204px;
    }
  }

  &.compact img {
    display: block;
    margin: 0 auto;
  }

  &.expanded {
    padding-right: 20px;
    max-width: none;

    & img {
      cursor: default;
      max-height: 90vh;
    }
  }

  @media (${breakpoint3}) {
    margin: 0 0 20px 0;

    &.expanded {
      padding-right: 0;
    }

    & img,
    &.expanded img {
      max-width: none;
      max-height: none;
      width: 100%;
      cursor: default;
    }
  }
`

const ImageTextContainer = styled.div`
  composes: ${sansfont};
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;

  &.compact {
    margin-top: 6px;
    & .expanded-text {
      display: none;
    }
  }

  &.expanded {
    & .small {
      display: none;
    }
  }

  @media (${breakpoint3}) {
    & .small {
      display: none;
    }

    &.compact .expanded-text {
      display: block;
    }
  }
`

const ImageText = styled.div`
  composes: ${childLink};
  text-align: left;
  min-width: 50%;
  font-size: 20px;
  font-weight: 300;
  line-height: 28px;

  &.right {
    text-align: right;
  }

  &.primary {
    font-size: 24px;
    order: -3;
  }

  &.credit {
    order: -2;
  }

  &.caption {
    order: -1;
  }

  &.small {
    width: 100%;
    font-size: 13px;
    line-height: 1;
  }

  @media (${breakpoint2}) {
    font-size: 16px;
    line-height: 24px;
    width: auto;

    &.caption {
      width: 75%;
      text-align: right;
    }

    &.data-texts {
      width: 75%;
      text-align: right;
      margin-top: 2px;
    }
  }

  @media (${breakpoint3}) {
    line-height: 24px;

    &.primary {
      font-size: 19px;
    }
  }
`

const ImageTextData = styled.span`
  display: inline-block;

  &:not(:first-child) {
    margin-left: 24px;

    @media (${breakpoint1}) {
      margin-left: 18px;
    }

    @media (${breakpoint3}) {
      margin-left: 10px;
    }
  }
`

const ExpansionButton = styled.button`
  composes: ${monofont};
  position: fixed;
  right: 50px;
  bottom: 50px;
  cursor: pointer;
  font-size: 96px;
  background: none;
  border: none;
  outline: none;
  user-select: none;

  @media (${breakpoint1}) {
    bottom: 30px;
    right: 0;
  }

  @media (${breakpoint3}) {
    display: none;
  }
`

class ImageList extends Component {
  constructor(props) {
    super(props)

    this.onKeyDown = this.onKeyDown.bind(this)

    this.state = {
      isExpanded: props.alwaysExpand ? true : false,
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.onKeyDown)
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.onKeyDown)
  }

  onKeyDown(ev) {
    // if expanded and ESC pressed, unexpand
    if (this.state.isExpanded && ev.keyCode === 27) {
      this.unexpand()
    }
  }

  renderExpansionButton() {
    const { isExpanded } = this.state

    if (!isExpanded) {
      return null // no longer show the "O" open state
    }

    const onClick = () => {
      if (!this.state.isExpanded) {
        this.setState({ isExpanded: true })
      } else {
        this.unexpand()
      }
    }

    return (
      <ExpansionButton onClick={onClick}>
        {isExpanded ? 'x' : 'o'}
      </ExpansionButton>
    )
  }

  onImageClick(setIndex, imageIndex) {
    if (this.props.unexpandable || this.state.isExpanded) return

    if (this.props.onImageHover) {
      this.props.onImageHover(null)
    }

    this.setState({ isExpanded: true }, () => {
      this.scrollTo(`set-${setIndex}-image-${imageIndex}`, -24)
    })
  }

  unexpand() {
    if (this.props.alwaysExpand) {
      return
    }

    this.setState({ isExpanded: false }, () => {
      this.scrollTo('set-0-image-0', -170) // scroll to top
    })
  }

  scrollTo(name, offset = 0) {
    Scroll.scroller.scrollTo(name, {
      duration: 100,
      smooth: true,
      offset,
    })
  }

  render() {
    const {
      imageSets,
      onImageHover,
      alwaysExpand,
      unexpandable,
      centerImages,
    } = this.props
    const { isExpanded } = this.state

    return (

        {!alwaysExpand && !unexpandable && this.renderExpansionButton()}

        {imageSets.map(({ images, title }, setIndex) => (
          <ImageSet key={setIndex} className={cx({ unexpandable })}>
            {title && <SetTitle>{title}</SetTitle>}

            <ImageContainer className={cx({ center: centerImages })}>
              {images.map((image, i) => {
                const { src, texts, unexpandedLink, alt = '' } = image

                const onMouseEnter =
                  isExpanded || !onImageHover ? null : () => onImageHover(image)
                const onMouseLeave =
                  isExpanded || !onImageHover ? null : () => onImageHover(null)
                const img = (

                )

                const imageItemClass = cx({
                  expanded: isExpanded,
                  compact: !isExpanded,
                  'with-small-text': texts && texts.smallText,
                })
                const textContainerClass = cx({
                  expanded: isExpanded,
                  compact: !isExpanded,
                })

                return (
                  <Scroll.Element
                    name={`set-${setIndex}-image-${i}`}
                    key={`image-${i}`}
                  >
                    <ImageItem
                      className={imageItemClass}
                      onClick={() => this.onImageClick(setIndex, i)}
                    >
                      {isExpanded || !unexpandedLink ? (
                        img
                      ) : (
                        <Link to={unexpandedLink}>{img}</Link>
                      )}

                      {texts && (
                        <ImageTextContainer className={textContainerClass}>
                          {texts.smallText && (
                            <ImageText className="small">
                              {texts.smallText}
                            </ImageText>
                          )}

                          <ImageText className="expanded-text left primary">
                            {texts.title}
                          </ImageText>
                          <ImageText className="expanded-text right data-texts">
                            {texts.data.map(txt => (
                              <ImageTextData key={txt}>{txt}</ImageTextData>
                            ))}
                          </ImageText>
                          <ImageText className="expanded-text left caption">
                            {texts.caption}
                          </ImageText>
                          <ImageText className="expanded-text right credit">
                            {texts.credit}
                          </ImageText>
                        </ImageTextContainer>
                      )}
                    </ImageItem>
                  </Scroll.Element>
                )
              })}
            </ImageContainer>
          </ImageSet>
        ))}

    )
  }
}

ImageList.propTypes = {
  imageSets: PropTypes.array.isRequired,
  onImageHover: PropTypes.func,
  alwaysExpand: PropTypes.bool,
  unexpandable: PropTypes.bool,
}

export default ImageList
<commit_msg>feature: improve design of expanded vertical images<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Link from 'gatsby-link'
import { css } from 'emotion'
import styled from 'emotion/react'
import cx from 'classnames'
import Scroll from 'react-scroll'
import {
  monofont,
  sansfont,
  childLink,
  breakpoint1,
  breakpoint2,
  breakpoint3,
} from './emotion-base'

const ImageSet = styled.div`
  &:not(:last-child) {
    margin-bottom: 60px;

    @media (${breakpoint1}) {
      margin-bottom: 30px;
    }
  }
`

const SetTitle = styled.h3`
  composes: ${sansfont};
  margin: 0 72px 28px 0;
  font-weight: 400;
  font-size: 28px;
  text-align: right;

  @media (${breakpoint1}) {
    text-align: left;
    font-size: 22px;
    margin: 0 0 28px 0;
  }

  @media (${breakpoint3}) {
    margin: 0 0 20px 0;
  }
`

const ImageContainer = styled.div`
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  align-items: flex-end;
  box-sizing: border-box;

  &.center {
    justify-content: center;
  }
`

const scrollElementExpanded = css`
  width: 100%;
`

const ImageItem = styled.div`
  margin: 0 20px 20px 0;
  display: inline-block;
  max-width: 144px;
  text-align: center;

  & img {
    margin: 0;
    padding: 0;
    max-width: 100%;
    max-height: 144px;
    cursor: pointer;
  }

  &.with-small-text {
    max-width: 204px;

    & img {
      max-height: 204px;
    }
  }

  &.expanded {
    display: table;
    padding-right: 20px;
    max-width: none;

    & img {
      cursor: default;
      max-width: 100%;
      max-height: calc(100vh - 200px);
    }
  }

  @media (${breakpoint3}) {
    margin: 0 0 20px 0;

    &.expanded {
      padding-right: 0;
    }

    & img,
    &.expanded img {
      max-width: none;
      max-height: none;
      width: 100%;
      cursor: default;
    }
  }
`

const ImageTextWrapper = styled.div`
  composes: ${sansfont};

  &.compact {
    & .expanded-text {
      display: none;
    }
  }

  &.expanded {
    display: table-caption;
    caption-side: bottom;
    padding: 0 20px 0 0;
    & .small {
      display: none;
    }
  }

  @media (${breakpoint3}) {
    & .small {
      display: none;
    }

    &.compact .expanded-text {
      display: block;
    }
  }
`

const ImageTextContainer = styled.div`
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  text-align: left;
`

const ImageText = styled.div`
  composes: ${childLink};
  text-align: left;
  min-width: 50%;
  font-size: 20px;
  font-weight: 300;
  line-height: 28px;

  &.right {
    text-align: right;
  }

  &.primary {
    font-size: 24px;
    width: 50%;
    margin-bottom: 4px;
  }

  &.credit {
    width: 50%;
  }

  &.small {
    width: 100%;
    font-size: 13px;
    line-height: 1;
  }

  @media (${breakpoint2}) {
    font-size: 16px;
    line-height: 24px;
    width: auto;

    &.caption {
      width: 75%;
      text-align: right;
    }

    &.data-texts {
      width: 75%;
      text-align: right;
      margin-top: 2px;
    }
  }

  @media (${breakpoint3}) {
    line-height: 24px;

    &.primary {
      font-size: 19px;
    }
  }
`

const ImageTextData = styled.span`
  display: inline-block;

  &:not(:first-child) {
    margin-left: 24px;

    @media (${breakpoint1}) {
      margin-left: 18px;
    }

    @media (${breakpoint3}) {
      margin-left: 10px;
    }
  }
`

const ExpansionButton = styled.button`
  composes: ${monofont};
  position: fixed;
  right: 50px;
  bottom: 50px;
  cursor: pointer;
  font-size: 96px;
  background: none;
  border: none;
  outline: none;
  user-select: none;

  @media (${breakpoint1}) {
    bottom: 30px;
    right: 0;
  }

  @media (${breakpoint3}) {
    display: none;
  }
`

class ImageList extends Component {
  constructor(props) {
    super(props)

    this.onKeyDown = this.onKeyDown.bind(this)

    this.state = {
      isExpanded: props.alwaysExpand ? true : false,
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.onKeyDown)
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.onKeyDown)
  }

  onKeyDown(ev) {
    // if expanded and ESC pressed, unexpand
    if (this.state.isExpanded && ev.keyCode === 27) {
      this.unexpand()
    }
  }

  renderExpansionButton() {
    const { isExpanded } = this.state

    if (!isExpanded) {
      return null // no longer show the "O" open state
    }

    const onClick = () => {
      if (!this.state.isExpanded) {
        this.setState({ isExpanded: true })
      } else {
        this.unexpand()
      }
    }

    return (
      <ExpansionButton onClick={onClick}>
        {isExpanded ? 'x' : 'o'}
      </ExpansionButton>
    )
  }

  onImageClick(setIndex, imageIndex) {
    if (this.props.unexpandable || this.state.isExpanded) return

    if (this.props.onImageHover) {
      this.props.onImageHover(null)
    }

    this.setState({ isExpanded: true }, () => {
      this.scrollTo(`set-${setIndex}-image-${imageIndex}`, -24)
    })
  }

  unexpand() {
    if (this.props.alwaysExpand) {
      return
    }

    this.setState({ isExpanded: false }, () => {
      this.scrollTo('set-0-image-0', -170) // scroll to top
    })
  }

  scrollTo(name, offset = 0) {
    Scroll.scroller.scrollTo(name, {
      duration: 100,
      smooth: true,
      offset,
    })
  }

  render() {
    const {
      imageSets,
      onImageHover,
      alwaysExpand,
      unexpandable,
      centerImages,
    } = this.props
    const { isExpanded } = this.state

    return (

        {!alwaysExpand && !unexpandable && this.renderExpansionButton()}

        {imageSets.map(({ images, title }, setIndex) => (
          <ImageSet key={setIndex} className={cx({ unexpandable })}>
            {title && <SetTitle>{title}</SetTitle>}

            <ImageContainer className={cx({ center: centerImages })}>
              {images.map((image, i) => {
                const { src, texts, unexpandedLink, alt = '' } = image

                const onMouseEnter =
                  isExpanded || !onImageHover ? null : () => onImageHover(image)
                const onMouseLeave =
                  isExpanded || !onImageHover ? null : () => onImageHover(null)
                const img = (

                )

                const scrollElementClass = isExpanded ? scrollElementExpanded : null
                const imageItemClass = cx({
                  expanded: isExpanded,
                  compact: !isExpanded,
                  'with-small-text': texts && texts.smallText,
                })
                const textContainerClass = cx({
                  expanded: isExpanded,
                  compact: !isExpanded,
                })

                return (
                  <Scroll.Element
                    name={`set-${setIndex}-image-${i}`}
                    key={`image-${i}`}
                    className={scrollElementClass}
                  >
                    <ImageItem
                      className={imageItemClass}
                      onClick={() => this.onImageClick(setIndex, i)}
                    >
                      {isExpanded || !unexpandedLink ? (
                        img
                      ) : (
                        <Link to={unexpandedLink}>{img}</Link>
                      )}

                      {texts && (
                        <ImageTextWrapper className={textContainerClass}>
                          <ImageTextContainer>
                            {texts.smallText && (
                              <ImageText className="small">
                                {texts.smallText}
                              </ImageText>
                            )}

                            <ImageText className="expanded-text left primary">
                              {texts.title}
                            </ImageText>
                            <ImageText className="expanded-text right credit">
                              {texts.credit}
                            </ImageText>
                            <ImageText className="expanded-text left caption">
                              {texts.caption}
                            </ImageText>
                            <ImageText className="expanded-text right data-texts">
                              {texts.data.map(txt => (
                                <ImageTextData key={txt}>{txt}</ImageTextData>
                              ))}
                            </ImageText>
                          </ImageTextContainer>
                        </ImageTextWrapper>
                      )}
                    </ImageItem>
                  </Scroll.Element>
                )
              })}
            </ImageContainer>
          </ImageSet>
        ))}

    )
  }
}

ImageList.propTypes = {
  imageSets: PropTypes.array.isRequired,
  onImageHover: PropTypes.func,
  alwaysExpand: PropTypes.bool,
  unexpandable: PropTypes.bool,
}

export default ImageList
<|endoftext|>


<commit_before>var url = require('url'),
    http = require('http'),
    resourceful = require('resourceful');

resourceful.Resource.webhooks = function (options) {
  var self = this;

  var parsed = url.parse(options.url);

  options.events.forEach(function (event) {
    self.before(event, function (obj, callback) {
      function onError(err) {
        callback(options.ignoreErrors ? null : err);
      }

      function onResponse(res) {
        var body = '';

        res.on('data', function (chunk) {
          body += chunk;
        });

        res.on('end', function () {
          if (options.after) {
            if (typeof options.after === 'function') {
              return options.after(res, body, callback);
            }
            else if (typeof options.after[event] === 'function') {
              return options.after[event](res, body, callback);
            }
          }

          if (res.statusCode !== 200) {
            return callback(new Error('HTTP ' + res.statusCode));
          }

          //
          // TODO:
          // If response had a body, assume that the body contains modified
          // document.
          //
          return callback();
        });
      }

      var req = http.request({
        host: parsed.hostname,
        port: parsed.port,
        method: 'POST',
        path: parsed.path + '?event=' + event
      }, onResponse).on('error', onError);

      req.write(JSON.stringify(obj));
      req.end();
    });
  });
};
<commit_msg>[fix] Use `application/json` as `content-type`<commit_after>var url = require('url'),
    http = require('http'),
    resourceful = require('resourceful');

resourceful.Resource.webhooks = function (options) {
  var self = this;

  var parsed = url.parse(options.url);

  options.events.forEach(function (event) {
    self.before(event, function (obj, callback) {
      function onError(err) {
        callback(options.ignoreErrors ? null : err);
      }

      function onResponse(res) {
        var body = '';

        res.on('data', function (chunk) {
          body += chunk;
        });

        res.on('end', function () {
          if (options.after) {
            if (typeof options.after === 'function') {
              return options.after(res, body, callback);
            }
            else if (typeof options.after[event] === 'function') {
              return options.after[event](res, body, callback);
            }
          }

          if (res.statusCode !== 200) {
            return callback(new Error('HTTP ' + res.statusCode));
          }

          //
          // TODO:
          // If response had a body, assume that the body contains modified
          // document.
          //
          return callback();
        });
      }

      var req = http.request({
        host: parsed.hostname,
        port: parsed.port,
        method: 'POST',
        path: parsed.path + '?event=' + event,
        headers: {
          'content-type': 'application/json'
        }
      }, onResponse).on('error', onError);

      req.write(JSON.stringify(obj));
      req.end();
    });
  });
};
<|endoftext|>


<commit_before>'use strict'
/**
 * Provides Solid helper functions involved with parsing a user's WebId profile.
 * @module identity
 */
module.exports.discoverWebID = discoverWebID
module.exports.getProfile = getProfile
module.exports.loadExtendedProfile = loadExtendedProfile

var SolidProfile = require('./solid/profile')

/**
 * Discovers a user's WebId (URL) starting from the account/domain URL.
 * Usage:
 *
 *   ```
 *   solid.discoverWebID(url)
 *     .then(function (webId) {
 *       console.log('Web ID is: ' + webId)
 *     })
 *     .catch(function (err) {
 *       console.log('Could not discover web id: ' + err)
 *     })
 *   ```
 * @method discoverWebID
 * @param url {String} Location of a user's account or domain.
 * @throw {Error} Reason why the WebID could not be discovered
 * @return {Promise<String>}
 */
function discoverWebID (url, webClient, ns) {
  return webClient.options(url)
    .then(function (response) {
      var metaUrl = response.metaAbsoluteUrl()
      if (!metaUrl) {
        throw new Error('Could not find a meta URL in the Link header')
      }
      return webClient.get(metaUrl)
    })
    .then(function (response) {
      var graph = response.parsedGraph()
      var webId = graph.any(undefined, ns.solid('account'))
      if (!webId || !webId.uri) {
        throw new Error('Could not find a WebID matching the domain ' + url)
      }
      return webId
    })
}

/**
 * Fetches a user's WebId profile, optionally follows `sameAs` etc links,
 *   and return a promise with a parsed SolidProfile instance.
 * @method getProfile
 * @param profileUrl {String} WebId or Location of a user's profile.
 * @param [options={}] Options hashmap (see solid.web.solidRequest()
 *   function docs)
 * @param [options.ignoreExtended=false] Do not load extended profile if true.
 * @param webClient {SolidWebClient}
 * @param rdf {RDF} RDF Library
 * @return {Promise<SolidProfile>}
 */
function getProfile (profileUrl, options, webClient, rdf) {
  options = options || {}
  // Politely ask for Turtle formatted profiles
  options.headers = options.headers || {
    'Accept': 'text/turtle'
  }
  options.noCredentials = true  // profiles are always public
  // Load main profile
  return webClient.get(profileUrl, options)
    .then(function (response) {
      var parsedProfile = response.parsedGraph()
      var profile = new SolidProfile(profileUrl, parsedProfile, rdf, webClient,
        response)
      profile.isLoaded = true
      if (options.ignoreExtended) {
        return profile
      } else {
        return loadExtendedProfile(profile, options, webClient)
      }
    })
}

/**
 * Loads the related external profile resources (all the `sameAs` and `seeAlso`
 * links, as well as Preferences), and appends them to the profile's
 * `parsedGraph`. Returns the profile instance.
 * @method loadExtendedProfile
 * @private
 * @param profile {SolidProfile}
 * @param [options] Options hashmap (see solid.web.solidRequest() function docs)
 * @return {Promise<SolidProfile>}
 */
function loadExtendedProfile (profile, options, webClient) {
  var links = profile.relatedProfilesLinks()
  return webClient.loadParsedGraphs(links, options)
    .then(function (loadedGraphs) {
      loadedGraphs.forEach(function (graph) {
        if (graph && graph.value) {
          profile.appendFromGraph(graph.value, graph.uri)
        }
      })
      return profile
    })
}
<commit_msg>getProfile supports 303 WebId<commit_after>'use strict'
/**
 * Provides Solid helper functions involved with parsing a user's WebId profile.
 * @module identity
 */
module.exports.discoverWebID = discoverWebID
module.exports.getProfile = getProfile
module.exports.loadExtendedProfile = loadExtendedProfile

var SolidProfile = require('./solid/profile')

/**
 * Discovers a user's WebId (URL) starting from the account/domain URL.
 * Usage:
 *
 *   ```
 *   solid.discoverWebID(url)
 *     .then(function (webId) {
 *       console.log('Web ID is: ' + webId)
 *     })
 *     .catch(function (err) {
 *       console.log('Could not discover web id: ' + err)
 *     })
 *   ```
 * @method discoverWebID
 * @param url {String} Location of a user's account or domain.
 * @throw {Error} Reason why the WebID could not be discovered
 * @return {Promise<String>}
 */
function discoverWebID (url, webClient, ns) {
  return webClient.options(url)
    .then(function (response) {
      var metaUrl = response.metaAbsoluteUrl()
      if (!metaUrl) {
        throw new Error('Could not find a meta URL in the Link header')
      }
      return webClient.get(metaUrl)
    })
    .then(function (response) {
      var graph = response.parsedGraph()
      var webId = graph.any(undefined, ns.solid('account'))
      if (!webId || !webId.uri) {
        throw new Error('Could not find a WebID matching the domain ' + url)
      }
      return webId
    })
}

/**
 * Fetches a user's WebId profile, optionally follows `sameAs` etc links,
 *   and return a promise with a parsed SolidProfile instance.
 * @method getProfile
 * @param webId {String} WebId
 * @param [options={}] Options hashmap (see solid.web.solidRequest()
 *   function docs)
 * @param [options.ignoreExtended=false] Do not load extended profile if true.
 * @param webClient {SolidWebClient}
 * @param rdf {RDF} RDF Library
 * @return {Promise<SolidProfile>}
 */
function getProfile (webId, options, webClient, rdf) {
  options = options || {}
  // Politely ask for Turtle formatted profiles
  options.headers = options.headers || {
    'Accept': 'text/turtle'
  }
  options.noCredentials = true  // profiles are always public
  // Load main profile
  return webClient.get(webId, options)
    .then(function (response) {
      var parsedProfile = response.parsedGraph()
      var profile = new SolidProfile(response.url, parsedProfile, rdf, webClient,
        response)
      profile.isLoaded = true
      if (options.ignoreExtended) {
        return profile
      } else {
        return loadExtendedProfile(profile, options, webClient)
      }
    })
}

/**
 * Loads the related external profile resources (all the `sameAs` and `seeAlso`
 * links, as well as Preferences), and appends them to the profile's
 * `parsedGraph`. Returns the profile instance.
 * @method loadExtendedProfile
 * @private
 * @param profile {SolidProfile}
 * @param [options] Options hashmap (see solid.web.solidRequest() function docs)
 * @return {Promise<SolidProfile>}
 */
function loadExtendedProfile (profile, options, webClient) {
  var links = profile.relatedProfilesLinks()
  return webClient.loadParsedGraphs(links, options)
    .then(function (loadedGraphs) {
      loadedGraphs.forEach(function (graph) {
        if (graph && graph.value) {
          profile.appendFromGraph(graph.value, graph.uri)
        }
      })
      return profile
    })
}
<|endoftext|>


<commit_before>String.prototype.repeat=String.prototype.repeat||function(x){return Array(~~x+1).join(this)};

infimath = {
	alignNums:function(){
		var args;
		if(typeof(arguments[0])=="object")
			args=arguments[0];
		else
			args=[].slice.call(arguments);
		var maxE=-1,maxD=-1;
		args=args.map(function(x){
			var a="",b="";
			x.replace(/([\d.]+)e([+-]?\d+)/i,function(_,y,z){a=y,b=z});
			if(a&&b)x=infimath.exp10(a,b);
			if(x.indexOf(".")<0)x+=".";
			return x;
		});
		args.map(function(x){
			maxE=Math.max(maxE,x.indexOf("."));
			maxD=Math.max(maxD,x.length-x.indexOf(".")-1);
		});
		args=args.map(function(x,i){
			return"0".repeat(maxE-x.indexOf("."))+x+"0".repeat(maxD-(x.length-x.indexOf(".")-1));
		});
		return args;
	},

	formatNum:function(x){
		return x
            .replace(/(.)0+$/,"$1")
            .replace(/\.$/,"")
            .replace(/^0(.)/,"$1")
            .replace(/^\./,"0.");
	},

	exp10:function(x,y){
		if(typeof(y)=="undefined")x.replace(/([\d.]+)e([+-]?\d+)/i,function(_,a,b){x=a,y=b});
		x=""+x,y=+y;
		function swap2(z){return z[1]+z[0]}
		if(y>0){
			while(/\.\d/.test(x)&&y--)
				x=x.replace(/\.\d/,swap2);
			x=x.replace(/\./,function(){return"0".repeat(y)+"."});
		}else if(y<0){
			while(/\d\./.test(x)&&y++)
				x=x.replace(/\d\./,swap2);
			x=x.replace(/\./,function(){return"."+"0".repeat(-y)});
		}
		return x;
	},

	addAligned:function(args){
		return args.reduce(function(a,b){return infimath.addTwo(a,b)});
	},

	addTwo:function(x,y){
		var e=x.indexOf(".");
		x=x.replace(/\./,"");
		y=y.replace(/\./,"");
		var a=[0],r=0;
		for(var i=0;i<x.length;i++){r=+x[i];r+=+y[i];a[i+1]=r;}
		for(r=0,i=a.length;i--;){a[i]+=r;r=0;if(a[i]>9)r=a[i]/10|0,a[i]%=10;}
		a.splice(e+1,0,".");
		a=a.join("");
		return a;
	},

	add:function(){
		var args;
		if(typeof(arguments[0])=="object") args=arguments[0];
		else args=[].slice.call(arguments);
		args.push("0");
		args=infimath.alignNums(args);
		var r=infimath.addAligned(args);
		return infimath.formatNum(r);
	}
};<commit_msg>Bug fixes<commit_after>String.prototype.repeat=String.prototype.repeat||function(x){return Array(~~x+1).join(this)};

infimath = {
	alignNums:function(){
		var args;
		if(typeof(arguments[0])=="object")
			args=arguments[0];
		else
			args=[].slice.call(arguments);
		var maxE=-1,maxD=-1;
		args=args.map(function(x){
			var a="",b="";
			x.replace(/([\d.]+)e([+-]?\d+)/i,function(_,y,z){a=y,b=z});
			if(a&&b)x=infimath.exp10(a,b);
			if(x.indexOf(".")<0)x+=".";
			return x;
		});
		args.map(function(x){
			maxE=Math.max(maxE,x.indexOf("."));
			maxD=Math.max(maxD,x.length-x.indexOf(".")-1);
		});
		args=args.map(function(x,i){
			return"0".repeat(maxE-x.indexOf("."))+x+"0".repeat(maxD-(x.length-x.indexOf(".")-1));
		});
		return args;
	},

	formatNum:function(x){
		return x
            .replace(/^0+/g,"") // Bwahaha... Grandma's secret 0-trimming trick:
            .replace(/\..+/g,function(z){return z.replace(/0/g," ")})
                                // replace 0's after the decimal point with spaces,
            .trim()             // trim off the extras,
            .replace(/ /g,"0")  // and switch the 0's back.
            .replace(/\.$/,"")  // Evil, isn't it? >:-)
            .replace(/^\./,"0.");
	},

	exp10:function(x,y){
		if(typeof(y)=="undefined")x.replace(/([\d.]+)e([+-]?\d+)/i,function(_,a,b){x=a,y=b});
		x=""+x,y=+y;
		function swap2(z){return z[1]+z[0]}
		if(y>0){
			while(/\.\d/.test(x)&&y--)
				x=x.replace(/\.\d/,swap2);
			x=x.replace(/\./,function(){return"0".repeat(y)+"."});
		}else if(y<0){
			while(/\d\./.test(x)&&y++)
				x=x.replace(/\d\./,swap2);
			x=x.replace(/\./,function(){return"."+"0".repeat(-y)});
		}
		return x;
	},

	addTwo:function(x,y){
        var p=infimath.alignNums(x,y);
        x=p[0],y=p[1];
		var e=x.indexOf(".");
		x=x.replace(/\./,"");
		y=y.replace(/\./,"");
		var a=[0],r=0;
		for(var i=0;i<x.length;i++){r=+x[i];r+=+y[i];a[i+1]=r;}
		for(r=0,i=a.length;i--;){a[i]+=r;r=0;if(a[i]>9)r=a[i]/10|0,a[i]%=10;}
		a.splice(e+1,0,".");
		a=a.join("");
		return infimath.formatNum(a);
	},

	add:function(){
		var args;
		if(typeof(arguments[0])=="object") args=arguments[0];
		else args=[].slice.call(arguments);
		if(args.length<1) return "0";
		var r=args.reduce(infimath.addTwo);
		return infimath.formatNum(r);
	}
};<|endoftext|>