<commit_before>var Handlebones = require("handlebones");
var template = require("../tmpl/create-user-form");
var PolisStorage = require("../util/polisStorage");
var $ = require("jquery");
var serialize = require("../util/serialize");
var URLs = require("../util/url");
var metric = require("../util/gaMetric");
var gaEvent = metric.gaEvent;

var urlPrefix = URLs.urlPrefix;

var ModelView = Handlebones.ModelView;

  module.exports = ModelView.extend({
    name: "create-user-form",
    template: template,
    gotoCreate: function() {
      this.model.set("create", true);
      gaEvent("SignUp", "land");
    },
    gotoSignIn: function() {
      this.model.set("create", false);
      gaEvent("Session", "land");
    },
    events: {
      "click .gotoSignIn": "gotoSignIn",
      "click .gotoCreate": "gotoCreate",
      "click .facebook-button": "facebookButtonClicked",
      "submit form": function(event){
        if (this.model.get("create")) {
          return this.createUser.call(this, event);
        } else {
          return this.signIn.call(this, event);
        }
      },
      "invalid": function(errors){
        console.log("invalid form input" + errors[0].name);
        console.log(errors);

       //_.each(errors, function(err){
          $("input[name=\""+errors[0].name+"\"]").closest("label").append(errors[0].message); // relationship between each input and error name
        //})
      }
    },
    onFail: function(message) {
      $('#errorDiv').html("
"+message+"
");
    },
    clearFailMessage: function() {
      $('#errorDiv').html("");
    },
    createUser: function(event) {
    var that = this;
    that.clearFailMessage();
    event.preventDefault();

    serialize(this, function(attrs){
        // Incorporate options, like zinvite.
        var zinvite = that.model.get("zinvite");
        if (zinvite) {
          attrs.zinvite = zinvite;
        }
      if (!attrs.email || !/.@./.exec(attrs.email)) {
        return that.onFail("Email is missing \"@\"");
      }
      if (!attrs.password || attrs.password.length < 8) {
        return that.onFail("Password must be 8 or more characters.");
      }
      $.ajax({
        url: urlPrefix + "api/v3/auth/new",
        type: "POST",
        dataType: "json",
        xhrFields: {
            withCredentials: true
        },
        // crossDomain: true,
        data: attrs
      }).then(function(data) {
        that.trigger("authenticated");
        gaEvent("SignUp", "done");
        setTimeout(function() {
          gaEvent("Session", "create", "signUp");
        }, 100);
      }, function(err) {
          that.onFail("login was unsuccessful");
          gaEvent("SignUp", "createFail", "signUp");
      });
    });
  },
  signIn: function(event) {
    var that = this;
    that.clearFailMessage();
    event.preventDefault();

    serialize(this, function(attrs){
      $.ajax({
        url: urlPrefix + "api/v3/auth/login",
        type: "POST",
        dataType: "json",
        xhrFields: {
          withCredentials: true
        },
        // crossDomain: true,
        data: attrs
      }).then(function(data) {
        that.trigger("authenticated");
        gaEvent("Session", "create", "signIn");
      }, function(err) {
          that.onFail("login was unsuccessful");
          gaEvent("Session", "createFail", "signIn");
      });
    });
  },
  validateInput: function(attrs){
    var errors = [];
    if(attrs.email === ""){
      errors.push({name: "description",  message: "hey there... you need an email"});
    }
    return errors;
  },
  facebookButtonClicked: function() {
    // FB.getLoginStatus(function(response) {
    //   if (response.status === 'connected') {
    //     alert(1);
    //     console.log('Logged in.');
    //   }
    //   else {
          FB.login(function(response) {
            alert(response);
          }, {
            return_scopes: true, // response should contain the scopes the user allowed
            scope: 'email,user_friends'
          });
      // }
  },
  initialize: function(options) {
    Handlebones.ModelView.prototype.initialize.apply(this, arguments);
    this.authStyleHeader = true;
    var that = this;
    // this.model = options.model;
    this.listenTo(this, "render", function() {
      var email = that.model.get("email");
      if (email) {
        that.$("#email").val(email);
      }

      // TODO do this differently
      // setTimeout(function() {
      //   FB.XFBML.parse();
      // }, 100);

    });
  }
});
<commit_msg>fb api test<commit_after>var Handlebones = require("handlebones");
var template = require("../tmpl/create-user-form");
var PolisStorage = require("../util/polisStorage");
var $ = require("jquery");
var serialize = require("../util/serialize");
var URLs = require("../util/url");
var metric = require("../util/gaMetric");
var gaEvent = metric.gaEvent;

var urlPrefix = URLs.urlPrefix;

var ModelView = Handlebones.ModelView;

  module.exports = ModelView.extend({
    name: "create-user-form",
    template: template,
    gotoCreate: function() {
      this.model.set("create", true);
      gaEvent("SignUp", "land");
    },
    gotoSignIn: function() {
      this.model.set("create", false);
      gaEvent("Session", "land");
    },
    events: {
      "click .gotoSignIn": "gotoSignIn",
      "click .gotoCreate": "gotoCreate",
      "click .facebook-button": "facebookButtonClicked",
      "submit form": function(event){
        if (this.model.get("create")) {
          return this.createUser.call(this, event);
        } else {
          return this.signIn.call(this, event);
        }
      },
      "invalid": function(errors){
        console.log("invalid form input" + errors[0].name);
        console.log(errors);

       //_.each(errors, function(err){
          $("input[name=\""+errors[0].name+"\"]").closest("label").append(errors[0].message); // relationship between each input and error name
        //})
      }
    },
    onFail: function(message) {
      $('#errorDiv').html("
"+message+"
");
    },
    clearFailMessage: function() {
      $('#errorDiv').html("");
    },
    createUser: function(event) {
    var that = this;
    that.clearFailMessage();
    event.preventDefault();

    serialize(this, function(attrs){
        // Incorporate options, like zinvite.
        var zinvite = that.model.get("zinvite");
        if (zinvite) {
          attrs.zinvite = zinvite;
        }
      if (!attrs.email || !/.@./.exec(attrs.email)) {
        return that.onFail("Email is missing \"@\"");
      }
      if (!attrs.password || attrs.password.length < 8) {
        return that.onFail("Password must be 8 or more characters.");
      }
      $.ajax({
        url: urlPrefix + "api/v3/auth/new",
        type: "POST",
        dataType: "json",
        xhrFields: {
            withCredentials: true
        },
        // crossDomain: true,
        data: attrs
      }).then(function(data) {
        that.trigger("authenticated");
        gaEvent("SignUp", "done");
        setTimeout(function() {
          gaEvent("Session", "create", "signUp");
        }, 100);
      }, function(err) {
          that.onFail("login was unsuccessful");
          gaEvent("SignUp", "createFail", "signUp");
      });
    });
  },
  signIn: function(event) {
    var that = this;
    that.clearFailMessage();
    event.preventDefault();

    serialize(this, function(attrs){
      $.ajax({
        url: urlPrefix + "api/v3/auth/login",
        type: "POST",
        dataType: "json",
        xhrFields: {
          withCredentials: true
        },
        // crossDomain: true,
        data: attrs
      }).then(function(data) {
        that.trigger("authenticated");
        gaEvent("Session", "create", "signIn");
      }, function(err) {
          that.onFail("login was unsuccessful");
          gaEvent("Session", "createFail", "signIn");
      });
    });
  },
  validateInput: function(attrs){
    var errors = [];
    if(attrs.email === ""){
      errors.push({name: "description",  message: "hey there... you need an email"});
    }
    return errors;
  },
  facebookButtonClicked: function() {
    // FB.getLoginStatus(function(response) {
    //   if (response.status === 'connected') {
    //     alert(1);
    //     console.log('Logged in.');
    //   }
    //   else {

      function getFriends() {
        FB.api('/me/friends',function (response) {
          if (response && !response.error) {
            alert(JSON.stringify(response));
            if (response.data) {
              for (var i = 0; i < response.data.length; i++) {
                alert(response.data[i]);
              }
            }
          } else {
            alert('failed');
          }
        });
      }

          FB.login(function(response) {
            alert(JSON.stringify(response));
            getFriends();
          }, {
            return_scopes: true, // response should contain the scopes the user allowed
            scope: 'email,user_friends'
          });
      // }
  },
  initialize: function(options) {
    Handlebones.ModelView.prototype.initialize.apply(this, arguments);
    this.authStyleHeader = true;
    var that = this;
    // this.model = options.model;
    this.listenTo(this, "render", function() {
      var email = that.model.get("email");
      if (email) {
        that.$("#email").val(email);
      }

      // TODO do this differently
      // setTimeout(function() {
      //   FB.XFBML.parse();
      // }, 100);

    });
  }
});
<|endoftext|>


<commit_before>// import { createStore } from 'redux';

// function todoStore(state = defaultState, action) {
//   switch (action.type) {
//     case 'ADD_TODO':
//       const allTodos = state.allTodos.concat([{
//         task: action.task,
//         state: 'pending'
//       }]);
//       return Object.assign({}, state, {
//         allTodos,
//         todos: allTodos.filter(todo => todo.state === state.filter)
//       });
//     case 'DONE_TODO':
//       const doneTodo =  Object.assign({}, action.todo,{
//         state: 'done'
//       });

//       const updatedAllTodos = state.allTodos.map(todo => {
//         return todo === action.todo ? doneTodo : todo;
//       });

//       return Object.assign({}, state, {
//         allTodos: updatedAllTodos,
//         todos: updatedAllTodos.filter(todo => todo.state === state.filter)
//       });
//     case 'TOGGLE_STATE':
//       const filter = state.filter === 'pending' ? 'done' : 'pending';
//       return Object.assign({}, state, {
//         filter,
//         todos: state.allTodos.filter(todo => todo.state === filter)
//       });
//     default:
//       return state;
//   }
// }
// const store = createStore(todoStore);

// export default store;

import {
  createStore,
  applyMiddleware
} from 'redux';
import { composeWithDevTools } from 'remote-redux-devtools';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';

import rootReducer from '../reducers';

export default function configureStore(initialState) {
  const logger = createLogger();
  const middlewares = [
    thunk,
    logger
  ];

  const store = createStore(rootReducer, initialState, composeWithDevTools(
    applyMiddleware(...middlewares)
  ));

  if (module.hot) {
    module.hot.accept(() => {
      const nextRootReducer = require('../reducers/index').default;
      store.replaceReducer(nextRootReducer);
    });
  }
  return store;
};
<commit_msg>Forbid react-logger to log anything in production<commit_after>import {
  createStore,
  applyMiddleware
} from 'redux';
import { composeWithDevTools } from 'remote-redux-devtools';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';

import rootReducer from '../reducers';

export default function configureStore(initialState) {

  const logger = createLogger({
      predicate: (getState, action) => __DEV__
  });
  const middlewares = [
    thunk,
    logger
  ];

  const store = createStore(rootReducer, initialState, composeWithDevTools(
    applyMiddleware(...middlewares)
  ));

  if (module.hot) {
    module.hot.accept(() => {
      const nextRootReducer = require('../reducers/index').default;
      store.replaceReducer(nextRootReducer);
    });
  }
  return store;
};
<|endoftext|>


<commit_before>import Immutable from 'immutable';

const initialState = Immutable.fromJS({
    hd: {
        base: "44'/61'/0'/0'",
        offset: 0
    },
    addresses: []
});

const addr = Immutable.fromJS({
    hdpath: null,
    address: null,
    value: null
});

function updateHd(state, hd, f) {
    return state.update('addresses', (list) => {
        const pos = list.findKey((a) => a.get('hdpath') === hd);
        if (pos >= 0) {
            return list.update(pos, f);
        }
        return list;
    })
}

function onGetAddress(state, action) {
    if (action.type === 'LEDGER/ADDR') {
        return updateHd(state, action.hdpath, (addr) => addr.set('address', action.addr))
    }
    return state
}

function onSetPath(state, action) {
    if (action.type === 'LEDGER/SET_LIST_HDPATH') {
        return state.update('addresses', (list) =>
            list.set(action.index, addr.set('hdpath', action.hdpath))
        )
    }
    return state
}

function onSetHd(state, action) {
    if (action.type === 'LEDGER/SET_BASEHD') {
        return state.setIn(['hd', 'base'], action.value)
    }
    return state
}
function onSetOffset(state, action) {
    if (action.type === 'LEDGER/SET_HDOFFSET') {
        return state.setIn(['hd', 'offset'], action.value)
    }
    return state
}

export default function ledgerReducers(state, action) {
    state = state || initialState;
    state = onGetAddress(state, action);
    state = onSetPath(state, action);
    state = onSetOffset(state, action);
    state = onSetHd(state, action);
    return state
}<commit_msg>problem: uses wrong HD path<commit_after>import Immutable from 'immutable';

const initialState = Immutable.fromJS({
    hd: {
        base: "44'/61'/0'/0",
        offset: 0
    },
    addresses: []
});

const addr = Immutable.fromJS({
    hdpath: null,
    address: null,
    value: null
});

function updateHd(state, hd, f) {
    return state.update('addresses', (list) => {
        const pos = list.findKey((a) => a.get('hdpath') === hd);
        if (pos >= 0) {
            return list.update(pos, f);
        }
        return list;
    })
}

function onGetAddress(state, action) {
    if (action.type === 'LEDGER/ADDR') {
        return updateHd(state, action.hdpath, (addr) => addr.set('address', action.addr))
    }
    return state
}

function onSetPath(state, action) {
    if (action.type === 'LEDGER/SET_LIST_HDPATH') {
        return state.update('addresses', (list) =>
            list.set(action.index, addr.set('hdpath', action.hdpath))
        )
    }
    return state
}

function onSetHd(state, action) {
    if (action.type === 'LEDGER/SET_BASEHD') {
        return state.setIn(['hd', 'base'], action.value)
    }
    return state
}
function onSetOffset(state, action) {
    if (action.type === 'LEDGER/SET_HDOFFSET') {
        return state.setIn(['hd', 'offset'], action.value)
    }
    return state
}

export default function ledgerReducers(state, action) {
    state = state || initialState;
    state = onGetAddress(state, action);
    state = onSetPath(state, action);
    state = onSetOffset(state, action);
    state = onSetHd(state, action);
    return state
}<|endoftext|>


<commit_before>/**
 * @fileOverview grid
 * @author huangtonger@aliyun.com
 */

const G6 = require('@antv/g6');
const Util = G6.Util;

class Plugin {
  constructor(options) {
    Util.mix(this, {
      /**
       * grid cell
       * @type {number}
       */
      cell: 16,

      /**
       * grid line style
       * @type {object}
       */
      line: {
        stroke: '#A3B1BF',
        lineWidth: 0.5
      },

      /**
       * grid line style
       * @type {string}
       */
      type: 'dot',

      /**
       * visible
       * @type {boolean}
       */
      visible: true
    }, options);
  }
  /**
   * init plugin
   */
  init() {
    const graph = this.graph;
    graph.on('afterinit', () => {
      this._draw();
    });
    graph.on('afterviewportchange', () => {
      this.update();
    });
    graph.on('beforechangesize', () => {
      this.update();
    });
    !this.visible && this.hide();
  }
  // draw grid
  _draw() {
    const graph = this.graph;
    const path = this._getPath();
    const group = graph.getRootGroup();
    const attrs = Util.mix({}, this.line);
    const matrix = graph.getMatrix();
    const type = this.type;
    const lineWidth = type === 'line' ? 1 / matrix[0] : 2 / matrix[0];
    if (type === 'dot') {
      attrs.lineDash = null;
    }
    attrs.lineWidth = lineWidth;
    attrs.path = path;
    const gridEl = group.addShape('path', {
      attrs,
      capture: false,
      zIndex: 0
    });
    gridEl.toBack();
    this.gridEl = gridEl;
  }
  // get line style grid path
  _getLinePath() {
    const graph = this.graph;
    const width = graph.getWidth();
    const height = graph.getHeight();
    const tl = graph.getPoint({
      x: 0,
      y: 0
    });
    const br = graph.getPoint({
      x: width,
      y: height
    });
    const cell = this.cell;
    const flooX = Math.ceil(tl.x / cell) * cell;
    const flooY = Math.ceil(tl.y / cell) * cell;
    const path = [];
    for (let i = 0; i <= br.x - tl.x; i += cell) {
      const x = flooX + i;
      path.push([ 'M', x, tl.y ]);
      path.push([ 'L', x, br.y ]);
    }
    for (let j = 0; j <= br.y - tl.y; j += cell) {
      const y = flooY + j;
      path.push([ 'M', tl.x, y ]);
      path.push([ 'L', br.x, y ]);
    }
    return path;
  }
  // get grid path
  _getPath() {
    const type = this.type;
    return this['_get' + Util.upperFirst(type) + 'Path']();
  }
  // get dot style grid path
  _getPointPath() {
    const graph = this.graph;
    const width = graph.getWidth();
    const height = graph.getHeight();
    const tl = graph.getPoint({
      x: 0,
      y: 0
    });
    const br = graph.getPoint({
      x: width,
      y: height
    });
    const cell = this.cell;
    const flooX = Math.ceil(tl.x / cell) * cell;
    const flooY = Math.ceil(tl.y / cell) * cell;
    const matrix = graph.getMatrix();
    const detalx = 2 / matrix[0];
    const path = [];
    for (let i = 0; i <= br.x - tl.x; i += cell) {
      const x = flooX + i;
      for (let j = 0; j <= br.y - tl.y; j += cell) {
        const y = flooY + j;
        path.push([ 'M', x, y ]);
        path.push([ 'L', x + detalx, y ]);
      }
    }
    return path;
  }
  show() {
    this.gridEl.show();
    this.visible = true;
  }
  hide() {
    this.gridEl.hide();
    this.visible = false;
  }
  getCell() {
    const cell = this.cell;
    const graph = this.graph;
    const matrix = graph.getMatrix();
    const scale = matrix[0];
    if (cell * scale < 9.6) {
      return 9.6 / scale;
    }
    return cell;
  }
  update(cfg) {
    const gridEl = this.gridEl;
    if (!gridEl) {
      return;
    }
    cfg && Util.mix(this, cfg);
    const path = this._getPath();
    const graph = this.graph;
    const zoom = graph.getZoom();
    const type = this.type;
    const lineWidth = type === 'line' ? 1 / zoom : 2 / zoom;
    if (this.cell * zoom < 8 || this.cell * zoom > 32) {
      this.cell = 16 / zoom;
    }
    gridEl.attr('lineWidth', lineWidth);
    gridEl.attr('path', path);
  }
  destroy() {
    const gridEl = this.gridEl;
    gridEl && gridEl.remove();
  }
}

G6.Plugins['tool.grid'] = Plugin;

module.exports = Plugin;
<commit_msg>fix: plugin.grid.Closes #479<commit_after>/**
 * @fileOverview grid
 * @author huangtonger@aliyun.com
 */

const G6 = require('@antv/g6');
const Util = G6.Util;

class Plugin {
  constructor(options) {
    Util.mix(this, {
      /**
       * grid cell
       * @type {number}
       */
      cell: 16,

      /**
       * grid line style
       * @type {object}
       */
      line: {
        stroke: '#A3B1BF',
        lineWidth: 0.5
      },

      /**
       * grid line style
       * @type {string}
       */
      type: 'dot',

      /**
       * visible
       * @type {boolean}
       */
      visible: true
    }, options);
  }
  /**
   * init plugin
   */
  init() {
    const graph = this.graph;
    graph.on('afterinit', () => {
      this._draw();
    });
    graph.on('afterviewportchange', () => {
      this.update();
    });
    graph.on('beforechangesize', () => {
      this.update();
    });
    !this.visible && this.hide();
  }
  // draw grid
  _draw() {
    const graph = this.graph;
    const path = this._getPath();
    const group = graph.getRootGroup();
    const attrs = Util.mix({}, this.line);
    const matrix = graph.getMatrix();
    const type = this.type;
    const lineWidth = type === 'line' ? 1 / matrix[0] : 2 / matrix[0];
    if (type === 'dot') {
      attrs.lineDash = null;
    }
    attrs.lineWidth = lineWidth;
    attrs.path = path;
    const gridEl = group.addShape('path', {
      attrs,
      capture: false,
      zIndex: 0
    });
    gridEl.toBack();
    this.gridEl = gridEl;
  }
  // get line style grid path
  _getLinePath() {
    const graph = this.graph;
    const width = graph.getWidth();
    const height = graph.getHeight();
    const tl = graph.getPoint({
      x: 0,
      y: 0
    });
    const br = graph.getPoint({
      x: width,
      y: height
    });
    const cell = this.cell;
    const flooX = Math.ceil(tl.x / cell) * cell;
    const flooY = Math.ceil(tl.y / cell) * cell;
    const path = [];
    for (let i = 0; i <= br.x - tl.x; i += cell) {
      const x = flooX + i;
      path.push([ 'M', x, tl.y ]);
      path.push([ 'L', x, br.y ]);
    }
    for (let j = 0; j <= br.y - tl.y; j += cell) {
      const y = flooY + j;
      path.push([ 'M', tl.x, y ]);
      path.push([ 'L', br.x, y ]);
    }
    return path;
  }
  // get grid path
  _getPath() {
    const type = this.type;
    return this['_get' + Util.upperFirst(type) + 'Path']();
  }
  // get dot style grid path
  _getDotPath() {
    const graph = this.graph;
    const width = graph.getWidth();
    const height = graph.getHeight();
    const tl = graph.getPoint({
      x: 0,
      y: 0
    });
    const br = graph.getPoint({
      x: width,
      y: height
    });
    const cell = this.cell;
    const flooX = Math.ceil(tl.x / cell) * cell;
    const flooY = Math.ceil(tl.y / cell) * cell;
    const matrix = graph.getMatrix();
    const detalx = 2 / matrix[0];
    const path = [];
    for (let i = 0; i <= br.x - tl.x; i += cell) {
      const x = flooX + i;
      for (let j = 0; j <= br.y - tl.y; j += cell) {
        const y = flooY + j;
        path.push([ 'M', x, y ]);
        path.push([ 'L', x + detalx, y ]);
      }
    }
    return path;
  }
  show() {
    this.gridEl.show();
    this.visible = true;
  }
  hide() {
    this.gridEl.hide();
    this.visible = false;
  }
  getCell() {
    const cell = this.cell;
    const graph = this.graph;
    const matrix = graph.getMatrix();
    const scale = matrix[0];
    if (cell * scale < 9.6) {
      return 9.6 / scale;
    }
    return cell;
  }
  update(cfg) {
    const gridEl = this.gridEl;
    if (!gridEl) {
      return;
    }
    cfg && Util.mix(this, cfg);
    const path = this._getPath();
    const graph = this.graph;
    const zoom = graph.getZoom();
    const type = this.type;
    const lineWidth = type === 'line' ? 1 / zoom : 2 / zoom;
    if (this.cell * zoom < 8 || this.cell * zoom > 32) {
      this.cell = 16 / zoom;
    }
    gridEl.attr('lineWidth', lineWidth);
    gridEl.attr('path', path);
  }
  destroy() {
    const gridEl = this.gridEl;
    gridEl && gridEl.remove();
  }
}

G6.Plugins['tool.grid'] = Plugin;

module.exports = Plugin;
<|endoftext|>


<commit_before>import {observable, computed} from 'mobx';
import BusinessModel from '../models/BusinessModel';
import OfferStore from '../stores/OfferStore';
import CouponModel from '../models/CouponModel'
import ClientStore from '../stores/ClientStore';
import CouponStore from '../stores/CouponStore';
import {hashHistory } from 'react-router'
import * as firebase from 'firebase';

const LOGIN_PROVIDERS = {
	FACEBOOK: 'facebook',
	GOOGLE: 'google'
}

export default class BuisnessStore {
	@observable business = null;
	@observable initialize = false;
	offerStore = null;
	clientStore = null;
	couponStore = null;

	constructor() {
		this.offerStore = new OfferStore();
		this.clientStore = new ClientStore();
		this.couponStore = new CouponStore();
		this.startObserve()

	}

	init(business){
		this.business = business;
		this.offerStore.init(this.business);
		this.clientStore.init(this.business);
		this.couponStore.init(this.business);
		this.initialize = true;

	}

	startObserve(){

		firebase.auth().onAuthStateChanged((user) => {
			if(!this.disableAuthObserver) {
				if (user && !this.business) {
					return this.login(user, user.refreshToken)
				} else {
					this.initialize = true;

				}
			}
		})
	}

	@computed get isLoggedIn(){
		return !!this.business ;
	}

	@computed get isInitialized(){
		return !!this.initialize ;
	}

	getProviderData(accessToken){

		return FB.api('/me', 'get', { access_token: accessToken, fields: 'id,last_name,first_name,gender,picture,email' }, (response) => {
			return response;
		});

	}

	handleLoginSuccess(result) {
		var { user, credential } = result;
		this.disableAuthObserver = true
		return Promise.resolve()
		.then(() => {
			if(credential) {
				return FB.api('/me', 'get', { access_token: credential.accessToken, fields: 'id,last_name,first_name,gender,picture,email' }, (providerData) => {
					return this.login(user, providerData)
				});
			}
		})
		.then(() => {
			this.disableAuthObserver = false
		})

	}

	login(currentUser, providerData){
		var isFirstTime = null
		return this.getBusiness(currentUser.uid)
			.then((business) => {
				if(!business) {
					this.addNewBusiness(currentUser, providerData)
						.then((business) => {
							this.init(business)
                             hashHistory.push('/settings');
						})

				}
				else {
					var businessModel = new BusinessModel();
					businessModel.convertFromDB(business);
					businessModel.store = this;
					this.init(businessModel);
                    hashHistory.push('/offers');

				}
			})
	}

	logout(){
		return firebase.auth().signOut().then(() =>  {
            this.business = null;
            this.offerStore = new OfferStore();
            this.clientStore = new ClientStore();
            this.couponStore = new CouponStore();
			hashHistory.push('/');

			return;
		})

	}

	getBusiness(id){
		return firebase.database().ref('/business/' + id).once('value').then(function(snapshot) {
			return  snapshot.val();
		});

	}

	save(businessModel){

        var businessModelDB = businessModel.convertToDB();
        return Promise.all([
            firebase.database().ref('/business').child(businessModelDB.id).child('address').set(businessModelDB.address || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('businessType').set(businessModelDB.businessType || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('description').set(businessModelDB.description || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('email').set(businessModelDB.email || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('facebook').set(businessModelDB.facebook || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('firstName').set(businessModelDB.firstName || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('imageUrl').set(businessModelDB.imageUrl || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('phone').set(businessModelDB.phone || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('picture').set(businessModelDB.picture || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('title').set(businessModelDB.title || "")]

        ).then(() => {
            return firebase.database().ref('coupons').orderByChild("businessId").equalTo(businessModel.id).once("value").then((snapshot) => {
                    var couponsObj = snapshot.val();
                    if(couponsObj) {
                        for (var key in couponsObj) {
                            businessModelDB = businessModel.convertToDB();
                            if (couponsObj.hasOwnProperty(key)) {
                                var coupon = couponsObj[key];
                                firebase.database().ref('coupons').child(coupon.id).child('bussineData').set(businessModelDB)

                            }
                        }
                    }
                })
            })

	}

	addNewBusiness(currentUser, providerData) {
		var business = new BusinessModel(currentUser);
		business.picture = providerData.picture || ""
		business.firstName = providerData.first_name || ""
		business.lastName = providerData.last_name || ""
		business.email = providerData.email || ""
		var businessModelDB = business.convertToDB();
		return firebase.database().ref('/business').child(currentUser.uid).set(businessModelDB)
			.then(() => {
				business.store = this;
				return business;
			})
	}

	toJS() {
		return this.clients.map(client => client.toJS());
	}

	static fromJS(array) {
		// store.clients = array.map(item => ClientModel.fromJS(clientStore, item));
		return store;
	}
}

<commit_msg>fix bussines saving<commit_after>import {observable, computed} from 'mobx';
import BusinessModel from '../models/BusinessModel';
import OfferStore from '../stores/OfferStore';
import CouponModel from '../models/CouponModel'
import ClientStore from '../stores/ClientStore';
import CouponStore from '../stores/CouponStore';
import {hashHistory } from 'react-router'
import * as firebase from 'firebase';

const LOGIN_PROVIDERS = {
	FACEBOOK: 'facebook',
	GOOGLE: 'google'
}

export default class BuisnessStore {
	@observable business = null;
	@observable initialize = false;
	offerStore = null;
	clientStore = null;
	couponStore = null;

	constructor() {
		this.offerStore = new OfferStore();
		this.clientStore = new ClientStore();
		this.couponStore = new CouponStore();
		this.startObserve()

	}

	init(business){
		this.business = business;
		this.offerStore.init(this.business);
		this.clientStore.init(this.business);
		this.couponStore.init(this.business);
		this.initialize = true;

	}

	startObserve(){

		firebase.auth().onAuthStateChanged((user) => {
			if(!this.disableAuthObserver) {
				if (user && !this.business) {
					return this.login(user, user.refreshToken)
				} else {
					this.initialize = true;

				}
			}
		})
	}

	@computed get isLoggedIn(){
		return !!this.business ;
	}

	@computed get isInitialized(){
		return !!this.initialize ;
	}

	getProviderData(accessToken){

		return FB.api('/me', 'get', { access_token: accessToken, fields: 'id,last_name,first_name,gender,picture,email' }, (response) => {
			return response;
		});

	}

	handleLoginSuccess(result) {
		var { user, credential } = result;
		this.disableAuthObserver = true
		return Promise.resolve()
		.then(() => {
			if(credential) {
				return FB.api('/me', 'get', { access_token: credential.accessToken, fields: 'id,last_name,first_name,gender,picture,email' }, (providerData) => {
					return this.login(user, providerData)
				});
			}
		})
		.then(() => {
			this.disableAuthObserver = false
		})

	}

	login(currentUser, providerData){
		var isFirstTime = null
		return this.getBusiness(currentUser.uid)
			.then((business) => {
				if(!business) {
					this.addNewBusiness(currentUser, providerData)
						.then((business) => {
							this.init(business)
                             hashHistory.push('/settings');
						})

				}
				else {
					var businessModel = new BusinessModel();
					businessModel.convertFromDB(business);
					businessModel.store = this;
					this.init(businessModel);
                    hashHistory.push('/offers');

				}
			})
	}

	logout(){
		return firebase.auth().signOut().then(() =>  {
            this.business = null;
            this.offerStore = new OfferStore();
            this.clientStore = new ClientStore();
            this.couponStore = new CouponStore();
			hashHistory.push('/');

			return;
		})

	}

	getBusiness(id){
		return firebase.database().ref('/business/' + id).once('value').then(function(snapshot) {
			return  snapshot.val();
		});

	}

	save(businessModel){

        var businessModelDB = businessModel.convertToDB();
        return Promise.all([
            firebase.database().ref('/business').child(businessModelDB.id).child('address').set(businessModelDB.address || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('businessType').set(businessModelDB.businessType || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('description').set(businessModelDB.description || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('email').set(businessModelDB.email || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('facebook').set(businessModelDB.facebook || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('firstName').set(businessModelDB.firstName || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('imageUrl').set(businessModelDB.imageUrl || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('phone').set(businessModelDB.phone || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('picture').set(businessModelDB.picture || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('title').set(businessModelDB.title || ""),
            firebase.database().ref('/business').child(businessModelDB.id).child('website').set(businessModelDB.title || "")]

        ).then(() => {
            return firebase.database().ref('coupons').orderByChild("businessId").equalTo(businessModel.id).once("value").then((snapshot) => {
                    var couponsObj = snapshot.val();
                    if(couponsObj) {
                        for (var key in couponsObj) {
                            businessModelDB = businessModel.convertToDB();
                            if (couponsObj.hasOwnProperty(key)) {
                                var coupon = couponsObj[key];
                                firebase.database().ref('coupons').child(coupon.id).child('bussineData').set(businessModelDB)

                            }
                        }
                    }
                })
            })

	}

	addNewBusiness(currentUser, providerData) {
		var business = new BusinessModel(currentUser);
		business.picture = providerData.picture || ""
		business.firstName = providerData.first_name || ""
		business.lastName = providerData.last_name || ""
		business.email = providerData.email || ""
		var businessModelDB = business.convertToDB();
		return firebase.database().ref('/business').child(currentUser.uid).set(businessModelDB)
			.then(() => {
				business.store = this;
				return business;
			})
	}

	toJS() {
		return this.clients.map(client => client.toJS());
	}

	static fromJS(array) {
		// store.clients = array.map(item => ClientModel.fromJS(clientStore, item));
		return store;
	}
}

<|endoftext|>


<commit_before>var http = require('http');
var https = require('https');
var url = require('url');
var extend = require('extend');
var logger = require('./logger');

var cache = {};
var listeners = [];
var newUrls;
var TIMEOUT = 10000;
var MAX_RULES_LEN = 1024 * 64;
var MAX_INTERVAL = 1000 * 30;
var MIN_INTERVAL = 1000 * 10;
var EEXCEED = 'EEXCEED';
var queue = [];
var queueTimer;
var pending;

function getInterval() {
  var len = Object.keys(cache).length || 1;
  return Math.max(MIN_INTERVAL, Math.ceil(MAX_INTERVAL / len));
}

function triggerChange() {
  if (!pending) {
    pending = true;
    newUrls = {};
    listeners.forEach(function(l) {
      l();
    });
    Object.keys(newUrls).forEach(function(url) {
      newUrls[url] = cache[url];
    });
    cache = newUrls;
    newUrls = null;
    pending = false;
  }
}

function parseOptions(options) {
  var fullUrl = options.url || options.uri || options;
  if (typeof fullUrl === 'string') {
    options = extend(options, url.parse(fullUrl));
  }
  var maxLength = options.maxLength;
  if (!(maxLength > 0)) {
    options.maxLength = 0;
  }
  options.agent = false;
  options.rejectUnauthorized = false;
  return options;
}

function request(options, callback) {
  options = parseOptions(options);
  var isHttps = options.protocol === 'https:';
  var httpModule = isHttps ? https : http;
  var done, timer, res;
  var body = '';
  var callbackHandler = function(err) {
    clearTimeout(timer);
    err && client.abort();
    if (!done) {
      done = true;
      callback(err, body, res || '');
    }
  };
  var addTimeout = function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      callbackHandler(new Error('Timeout'));
    }, TIMEOUT);
  };
  addTimeout();
  var maxLength = options.maxLength;
  var client = httpModule.get(options, function(r) {
    res = r;
    res.on('error', callbackHandler);
    res.setEncoding('utf8');
    res.on('data', function(data) {
      body += data;
      addTimeout();
      if (maxLength && body.length > maxLength) {
        var err;
        if (!options.ignoreExceedError) {
          err = new Error('The response body exceeded length limit');
          err.code = EEXCEED;
        }
        callbackHandler(err);
      }
    });
    res.on('end', callbackHandler);
  });
  client.on('error', callbackHandler);
  client.end();
  return client;
}

exports.request = request;

function addQueue(url) {
  if (cache[url] && queue.indexOf(url) === -1) {
    queue.push(url);
  }
  var data;
  while(!queueTimer && !data) {
    url = queue.shift();
    if (!url) {
      return;
    }
    data = cache[url];
    if (data) {
      queueTimer = setTimeout(function() {
        queueTimer = null;
        updateBody(url, addQueue);
      }, getInterval());
      return;
    }
  }
}

function updateBody(url, callback, init) {
  var data = cache[url];
  if (!data) {
    return callback && callback();
  }
  request({
    url: url,
    maxLength: MAX_RULES_LEN,
    ignoreExceedError: true
  }, function(err, body, res) {
    data = cache[url];
    callback && callback(url);
    if (!data) {
      return;
    }
    if (!err) {
      if (res.statusCode >= 400 && res.statusCode < 500) {
        body = '';
      } else if (res.statusCode !== 200) {
        err = new Error('Response ' + res.statusCode);
      }
    } else if (err.code === 'ECONNREFUSED') {
      body = '';
      err = null;
    }
    if (err) {
      logger.error(url, err.message);
      if (init) {
        updateBody(url);
        return;
      }
    }
    addQueue(url);
    body = body && body.trim();
    if (err || data.body === body) {
      return;
    }
    data.body = body;
    triggerChange();
  });
  return true;
}

exports.addChangeListener = function(l) {
  listeners.push(l);
};

exports.add = function(url) {
  var data = cache[url];
  if (!data) {
    cache[url] = data = {body: ''};
    updateBody(url, null, true);
  }
  if (newUrls) {
    newUrls[url] = 1;
  }
  return data.body;
};

exports.clean = function() {
  if (!pending && Object.keys(cache).length) {
    triggerChange();
  }
};
<commit_msg>refactor: get remote rules<commit_after>var http = require('http');
var https = require('https');
var url = require('url');
var extend = require('extend');
var logger = require('./logger');

var cache = {};
var listeners = [];
var newUrls;
var TIMEOUT = 10000;
var MAX_RULES_LEN = 1024 * 64;
var MAX_INTERVAL = 1000 * 30;
var MIN_INTERVAL = 1000 * 10;
var EEXCEED = 'EEXCEED';
var queue = [];
var queueTimer;
var pending;

function getInterval() {
  var len = Object.keys(cache).length || 1;
  return Math.max(MIN_INTERVAL, Math.ceil(MAX_INTERVAL / len));
}

function triggerChange() {
  if (!pending) {
    pending = true;
    newUrls = {};
    listeners.forEach(function(l) {
      l();
    });
    Object.keys(newUrls).forEach(function(url) {
      newUrls[url] = cache[url];
    });
    cache = newUrls;
    newUrls = null;
    pending = false;
  }
}

function parseOptions(options) {
  var fullUrl = options.url || options.uri || options;
  if (typeof fullUrl === 'string') {
    options = extend(options, url.parse(fullUrl));
  }
  var maxLength = options.maxLength;
  if (!(maxLength > 0)) {
    options.maxLength = 0;
  }
  options.agent = false;
  options.rejectUnauthorized = false;
  return options;
}

function request(options, callback) {
  options = parseOptions(options);
  var isHttps = options.protocol === 'https:';
  var httpModule = isHttps ? https : http;
  var done, timer, res;
  var body = '';
  var callbackHandler = function(err) {
    clearTimeout(timer);
    err && client.abort();
    if (!done) {
      done = true;
      callback(err, body, res || '');
    }
  };
  var addTimeout = function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      callbackHandler(new Error('Timeout'));
    }, TIMEOUT);
  };
  addTimeout();
  var maxLength = options.maxLength;
  var client = httpModule.get(options, function(r) {
    res = r;
    res.on('error', callbackHandler);
    res.setEncoding('utf8');
    res.on('data', function(data) {
      body += data;
      addTimeout();
      if (maxLength && body.length > maxLength) {
        var err;
        if (!options.ignoreExceedError) {
          err = new Error('The response body exceeded length limit');
          err.code = EEXCEED;
        }
        callbackHandler(err);
      }
    });
    res.on('end', callbackHandler);
  });
  client.on('error', callbackHandler);
  client.end();
  return client;
}

exports.request = request;

function addQueue(url) {
  if (cache[url] && queue.indexOf(url) === -1) {
    queue.push(url);
  }
  var data;
  while(!queueTimer && !data) {
    url = queue.shift();
    if (!url) {
      return;
    }
    data = cache[url];
    if (data) {
      queueTimer = setTimeout(function() {
        queueTimer = null;
        updateBody(url, addQueue);
      }, getInterval());
      return;
    }
  }
}

function updateBody(url, callback, init) {
  var data = cache[url];
  if (!data) {
    return callback && callback();
  }
  request({
    url: url,
    maxLength: MAX_RULES_LEN,
    ignoreExceedError: true
  }, function(err, body, res) {
    data = cache[url];
    callback && callback(url);
    if (!data) {
      return;
    }
    if (!err) {
      var code = res.statusCode;
      if (code >= 400 && code < 500) {
        body = '';
        logger.warn(url, code);
      } else if (code !== 200) {
        err = new Error('Response ' + code);
      }
    }
    if (err) {
      logger.error(url, err.message);
      if (init) {
        updateBody(url);
        return;
      }
    }
    addQueue(url);
    body = body && body.trim();
    if (err || data.body === body) {
      return;
    }
    data.body = body;
    triggerChange();
  });
  return true;
}

exports.addChangeListener = function(l) {
  listeners.push(l);
};

exports.add = function(url) {
  var data = cache[url];
  if (!data) {
    cache[url] = data = {body: ''};
    updateBody(url, null, true);
  }
  if (newUrls) {
    newUrls[url] = 1;
  }
  return data.body;
};

exports.clean = function() {
  if (!pending && Object.keys(cache).length) {
    triggerChange();
  }
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var assets = require('../assets');

module.exports = {
    clean: {
        all: 'bin',
        views: 'bin/views',
        js: 'bin/public/js',
        css: 'bin/public/css',
        images: ['bin/public/img', 'bin/public/favicon.ico'],
        tmp_sprite: 'bin/.tmp/sprite',
        after_uglify: ['bin/public/js/**/*.js', '!bin/public/js/all.js']
    },
    csslint: {
        client: {
            options: {
                csslintrc: 'src/client/css/.csslintrc',
            },
            src: ['bin/.tmp/csslint/*.css']
        }
    },
    stylus: {
        all: {
            options: {
                'include css': true,
                paths: ['bower_components']
            },
            files: {
                'bin/public/css/all.css': ['src/client/css/vendor.styl', 'src/client/css/all.styl', 'bin/.tmp/sprite/*.css'],
                'bin/.tmp/csslint/compiled.css': ['src/client/css/all.styl']
            }
        }
    },
    jade: {
        debug: assets.jade(false),
        release: assets.jade(true)
    },
    copy: _.assign(assets.img.copy, assets.js.copy, assets.other.copy),
    json2css: {
        all: {
            src: 'bin/.tmp/sprite/*.json',
            format: 'pseudo_class_css'
        }
    },
    sprite: {
        houses: assets.img.sprite('houses', 'ho'),
        icons: assets.img.sprite('icons', 'ic')
    },
    imagemin: {
        all: {
            files: [{
                expand: true,
                src: 'bin/public/img/**/*.{png,jpg,gif}'
            }],
            options: {
                progressive: true,
                interlaced: true
            }
        }
    },
    cssmin: {
        release: {
            files: { 'bin/public/css/all.css': 'bin/public/css/all.css' },
            options: {
                keepSpecialComments: 0
            }
        }
    },
    uglify: {
        js: {
            files: { 'bin/public/js/all.js': 'bin/public/js/**/*.js' },
            options: {
                preserveComments: false
            }
        }
    }
};
<commit_msg>removed unused task<commit_after>'use strict';

var _ = require('lodash');
var assets = require('../assets');

module.exports = {
    clean: {
        all: 'bin',
        views: 'bin/views',
        js: 'bin/public/js',
        css: 'bin/public/css',
        images: ['bin/public/img', 'bin/public/favicon.ico'],
        tmp_sprite: 'bin/.tmp/sprite',
        after_uglify: ['bin/public/js/**/*.js', '!bin/public/js/all.js']
    },
    csslint: {
        client: {
            options: {
                csslintrc: 'src/client/css/.csslintrc',
            },
            src: ['bin/.tmp/csslint/*.css']
        }
    },
    stylus: {
        all: {
            options: {
                'include css': true,
                paths: ['bower_components']
            },
            files: {
                'bin/public/css/all.css': ['src/client/css/vendor.styl', 'src/client/css/all.styl', 'bin/.tmp/sprite/*.css'],
                'bin/.tmp/csslint/compiled.css': ['src/client/css/all.styl']
            }
        }
    },
    jade: {
        debug: assets.jade(false),
        release: assets.jade(true)
    },
    copy: _.assign(assets.img.copy, assets.js.copy, assets.other.copy),
    sprite: {
        houses: assets.img.sprite('houses', 'ho'),
        icons: assets.img.sprite('icons', 'ic')
    },
    imagemin: {
        all: {
            files: [{
                expand: true,
                src: 'bin/public/img/**/*.{png,jpg,gif}'
            }],
            options: {
                progressive: true,
                interlaced: true
            }
        }
    },
    cssmin: {
        release: {
            files: { 'bin/public/css/all.css': 'bin/public/css/all.css' },
            options: {
                keepSpecialComments: 0
            }
        }
    },
    uglify: {
        js: {
            files: { 'bin/public/js/all.js': 'bin/public/js/**/*.js' },
            options: {
                preserveComments: false
            }
        }
    }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*!
 * Script to update version number references in the project.
 * Copyright 2017-2021 The Bootstrap Authors
 * Copyright 2017-2021 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
 */

'use strict'

const fs = require('fs')
const path = require('path')
const sh = require('shelljs')

sh.config.fatal = true

// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
function regExpQuote(string) {
  return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&')
}

function regExpQuoteReplacement(string) {
  return string.replace(/\$/g, '$$')
}

const DRY_RUN = false

function walkAsync(directory, excludedDirectories, fileCallback, errback) {
  if (excludedDirectories.has(path.parse(directory).base)) {
    return
  }

  fs.readdir(directory, (err, names) => {
    if (err) {
      errback(err)
      return
    }

    names.forEach(name => {
      const filepath = path.join(directory, name)
      fs.lstat(filepath, (err, stats) => {
        if (err) {
          process.nextTick(errback, err)
          return
        }

        if (stats.isDirectory()) {
          process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback)
        } else if (stats.isFile()) {
          process.nextTick(fileCallback, filepath)
        }
      })
    })
  })
}

function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) {
  original = new RegExp(regExpQuote(original), 'g')
  replacement = regExpQuoteReplacement(replacement)
  const updateFile = DRY_RUN ?
    filepath => {
      if (allowedExtensions.has(path.parse(filepath).ext)) {
        console.log(`FILE: ${filepath}`)
      } else {
        console.log(`EXCLUDED:${filepath}`)
      }
    } :
    filepath => {
      if (allowedExtensions.has(path.parse(filepath).ext)) {
        sh.sed('-i', original, replacement, filepath)
      }
    }

  walkAsync(directory, excludedDirectories, updateFile, err => {
    console.error('ERROR while traversing directory!:')
    console.error(err)
    process.exit(1)
  })
}

function main(args) {
  if (args.length !== 2) {
    console.error('USAGE: change-version old_version new_version')
    console.error('Got arguments:', args)
    process.exit(1)
  }

  const oldVersion = args[0]
  const newVersion = args[1]
  const EXCLUDED_DIRS = new Set([
    '.git',
    '_site',
    'node_modules',
    'resources'
  ])
  const INCLUDED_EXTENSIONS = new Set([
    // This extension allowlist is how we avoid modifying binary files
    '',
    '.css',
    '.html',
    '.js',
    '.json',
    '.md',
    '.scss',
    '.txt',
    '.yml'
  ])
  replaceRecursively('.', EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion)
}

main(process.argv.slice(2))
<commit_msg>Tweak change-version.js<commit_after>#!/usr/bin/env node

/*!
 * Script to update version number references in the project.
 * Copyright 2017-2021 The Bootstrap Authors
 * Copyright 2017-2021 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
 */

'use strict'

const fs = require('fs')
const path = require('path')
const sh = require('shelljs')

sh.config.fatal = true

const VERBOSE = process.argv.includes('--verbose')
const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run')

const ROOT_DIR = path.join(__dirname, '..')

// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
function regExpQuote(string) {
  return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&')
}

function regExpQuoteReplacement(string) {
  return string.replace(/\$/g, '$$')
}

function walkAsync(directory, excludedDirectories, fileCallback, errback) {
  if (excludedDirectories.has(path.parse(directory).base)) {
    return
  }

  fs.readdir(directory, (err, names) => {
    if (err) {
      errback(err)
      return
    }

    names.forEach(name => {
      const filepath = path.join(directory, name)
      fs.lstat(filepath, (err, stats) => {
        if (err) {
          process.nextTick(errback, err)
          return
        }

        if (stats.isDirectory()) {
          process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback)
        } else if (stats.isFile()) {
          process.nextTick(fileCallback, filepath)
        }
      })
    })
  })
}

function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) {
  const updateFile = filepath => {
    if (allowedExtensions.has(path.parse(filepath).ext)) {
      if (VERBOSE) {
        console.log(`FILE: ${filepath}`)
      }

      if (DRY_RUN) {
        return
      }

      sh.sed('-i', new RegExp(regExpQuote(original), 'g'), regExpQuoteReplacement(replacement), filepath)
    } else if (VERBOSE) {
      console.log(`EXCLUDED: ${filepath}`)
    }
  }

  walkAsync(directory, excludedDirectories, updateFile, err => {
    console.error('ERROR while traversing directory!:')
    console.error(err)
    process.exit(1)
  })
}

function main(args) {
  const [oldVersion, newVersion] = args

  if (!oldVersion || !newVersion) {
    console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]')
    console.error('Got arguments:', args)
    process.exit(1)
  }

  const EXCLUDED_DIRS = new Set([
    '.git',
    '_site',
    'node_modules',
    'resources'
  ])
  const INCLUDED_EXTENSIONS = new Set([
    // This extensions list is how we avoid modifying binary files
    '',
    '.css',
    '.html',
    '.js',
    '.json',
    '.md',
    '.scss',
    '.txt',
    '.yml'
  ])

  replaceRecursively(ROOT_DIR, EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion)
}

main(process.argv.slice(2))
<|endoftext|>


<commit_before>/**
 * Creates a delayed version of the provided function. This is used to guarantee
 * ansynchronous behavior for potentially synchronous operations.
 */
function delayed(fn) {
  return function() {
    var args = arguments;
    var self = this;
    var fnWithArgs = function() {
      return fn.apply(self, args);
    };
    setTimeout(fnWithArgs, 0);
  };
};

module.exports = delayed;
<commit_msg>Remove unnecessary return<commit_after>/**
 * Creates a delayed version of the provided function. This is used to guarantee
 * ansynchronous behavior for potentially synchronous operations.
 */
function delayed(fn) {
  return function() {
    var args = arguments;
    var self = this;
    var fnWithArgs = function() {
      fn.apply(self, args);
    };
    setTimeout(fnWithArgs, 0);
  };
};

module.exports = delayed;
<|endoftext|>


<commit_before>function validateRules(harvested, report, next){

    if (harvested['pasties_position_css']){
        var wrapCSS = harvested['pasties_position_css'].wrapperElement;
        var bannerCSS = harvested['pasties_position_css'].firstChild;

        if (wrapCSS.css.position !== 'static' || wrapCSS.css.visability !== ''){
            report.error('Do not style outside bannercontainer');
        }
        if (bannerCSS.found === false){
            report.warn('Bannercontainer not found/identified');
        }
        if (bannerCSS.found && bannerCSS.css.position !== 'static'){
            report.error('Bannercontainer should have position: "static", but instead it has position: "'+bannerCSS.css.position+'". Please use a inner container if position relative or absolute is needed.', {});
        }
    }

    next();
}

/*
    225px høyde
    max 100kb gzipped
*/

module.exports = {
    validate: function (harvested, report, next) {
        if (harvested && harvested.har_input){
            validateRules(harvested, report, next);
        } else {
            next();
        }
    }
};
<commit_msg>fix ref error<commit_after>function validateRules(harvested, report, next){

    if (harvested['pasties_position_css']){
        var wrapCSS = harvested['pasties_position_css'].wrapperElement;
        var bannerCSS = harvested['pasties_position_css'].firstChild;

        if (wrapCSS.css.position !== 'static' || wrapCSS.css.visability !== ''){
            report.error('Do not style outside bannercontainer');
        }
        if (bannerCSS.found === false){
            report.warn('Bannercontainer not found/identified');
        } else if (bannerCSS.found === true && bannerCSS.name) {
            report.info('Bannercontainer found/identified');
        }
        if (bannerCSS.found && bannerCSS.css.position !== 'static'){
            report.error('Bannercontainer should have position: "static", but instead it has position: "'+bannerCSS.css.position+'". Please use a inner container if position relative or absolute is needed.', {});
        }
    }

    next();
}

/*
    225px høyde
*/

module.exports = {
    validate: function (harvested, report, next) {
        if (harvested && harvested.har_input){
            validateRules(harvested, report, next);
        } else {
            next();
        }
    }
};
<|endoftext|>


<commit_before>import { Transform } from 'readable-stream'
import { EbmlStreamDecoder, EbmlTagId } from 'ebml-stream'

const SSA_TYPES = new Set(['ssa', 'ass'])
const SSA_KEYS = ['readOrder', 'layer', 'style', 'name', 'marginL', 'marginR', 'marginV', 'effect', 'text']

function getData (chunk, id) {
  const el = chunk.Children.find(c => c.id === id)
  return el ? el.data : undefined
}

export class SubtitleParserBase extends Transform {
  constructor () {
    super()

    this.subtitleTracks = new Map()
    this.timecodeScale = 1

    this._currentClusterTimecode = null

    this.decoder = new EbmlStreamDecoder({
      bufferTagIds: [
        EbmlTagId.TimecodeScale,
        EbmlTagId.Tracks,
        EbmlTagId.BlockGroup,
        EbmlTagId.AttachedFile
      ]
    })

    this.decoder.on('data', this.parseEbmlSubtitles.bind(this))
  }

  parseEbmlSubtitles (chunk) {
    // Segment Information
    if (chunk.id === EbmlTagId.TimecodeScale) {
      this.timecodeScale = chunk.data / 1000000
    }

    // Assumption: This is a Cluster `Timecode`
    if (chunk.id === EbmlTagId.Timecode) {
      this._currentClusterTimecode = chunk.data
    }

    if (chunk.id === EbmlTagId.Tracks) {
      for (const entry of chunk.Children.filter(c => c.id === EbmlTagId.TrackEntry)) {
        // Skip non subtitle tracks
        if (getData(entry, EbmlTagId.TrackType) !== 0x11) continue

        const codecID = getData(entry, EbmlTagId.CodecID) || ''
        if (codecID.startsWith('S_TEXT')) {
          const track = {
            number: getData(entry, EbmlTagId.TrackNumber),
            language: getData(entry, EbmlTagId.Language),
            type: codecID.substring(7).toLowerCase()
          }

          const name = getData(entry, EbmlTagId.Name)
          if (name) {
            track.name = name
          }

          const header = getData(entry, EbmlTagId.CodecPrivate)
          if (header && SSA_TYPES.has(track.type)) {
            track.header = header.toString()
          }

          this.subtitleTracks.set(track.number, track)
        }
      }

      this.emit('tracks', Array.from(this.subtitleTracks.values()))
    }

    if (chunk.id === EbmlTagId.BlockGroup) {
      const block = chunk.Children.find(c => c.id === EbmlTagId.Block)

      if (this.subtitleTracks.has(block.track)) {
        const blockDuration = getData(chunk, EbmlTagId.BlockDuration)
        const type = this.subtitleTracks.get(block.track).type

        const subtitle = {
          text: block.payload.toString('utf8'),
          time: (block.value + this._currentClusterTimecode) * this.timecodeScale,
          duration: blockDuration * this.timecodeScale
        }

        if (SSA_TYPES.has(type)) {
          // extract SSA/ASS keys
          const values = subtitle.text.split(',')

          // ignore read-order, and skip layer if ssa
          for (let i = type === 'ssa' ? 2 : 1; i < 8; i++) {
            subtitle[SSA_KEYS[i]] = values[i]
          }

          subtitle.text = values.slice(8).join(',')
        }

        this.emit('subtitle', subtitle, block.track)
      }
    }

    // Parse attached files, mainly to allow extracting subtitle font files.
    if (chunk.id === EbmlTagId.AttachedFile) {
      this.emit('file', {
        filename: getData(chunk, EbmlTagId.FileName),
        mimetype: getData(chunk, EbmlTagId.FileMimeType),
        data: getData(chunk, EbmlTagId.FileData)
      })
    }
  }
}
<commit_msg>Ensure block exists in group<commit_after>import { Transform } from 'readable-stream'
import { EbmlStreamDecoder, EbmlTagId } from 'ebml-stream'

const SSA_TYPES = new Set(['ssa', 'ass'])
const SSA_KEYS = ['readOrder', 'layer', 'style', 'name', 'marginL', 'marginR', 'marginV', 'effect', 'text']

function getData (chunk, id) {
  const el = chunk.Children.find(c => c.id === id)
  return el ? el.data : undefined
}

export class SubtitleParserBase extends Transform {
  constructor () {
    super()

    this.subtitleTracks = new Map()
    this.timecodeScale = 1

    this._currentClusterTimecode = null

    this.decoder = new EbmlStreamDecoder({
      bufferTagIds: [
        EbmlTagId.TimecodeScale,
        EbmlTagId.Tracks,
        EbmlTagId.BlockGroup,
        EbmlTagId.AttachedFile
      ]
    })

    this.decoder.on('data', this.parseEbmlSubtitles.bind(this))
  }

  parseEbmlSubtitles (chunk) {
    // Segment Information
    if (chunk.id === EbmlTagId.TimecodeScale) {
      this.timecodeScale = chunk.data / 1000000
    }

    // Assumption: This is a Cluster `Timecode`
    if (chunk.id === EbmlTagId.Timecode) {
      this._currentClusterTimecode = chunk.data
    }

    if (chunk.id === EbmlTagId.Tracks) {
      for (const entry of chunk.Children.filter(c => c.id === EbmlTagId.TrackEntry)) {
        // Skip non subtitle tracks
        if (getData(entry, EbmlTagId.TrackType) !== 0x11) continue

        const codecID = getData(entry, EbmlTagId.CodecID) || ''
        if (codecID.startsWith('S_TEXT')) {
          const track = {
            number: getData(entry, EbmlTagId.TrackNumber),
            language: getData(entry, EbmlTagId.Language),
            type: codecID.substring(7).toLowerCase()
          }

          const name = getData(entry, EbmlTagId.Name)
          if (name) {
            track.name = name
          }

          const header = getData(entry, EbmlTagId.CodecPrivate)
          if (header && SSA_TYPES.has(track.type)) {
            track.header = header.toString()
          }

          this.subtitleTracks.set(track.number, track)
        }
      }

      this.emit('tracks', Array.from(this.subtitleTracks.values()))
    }

    if (chunk.id === EbmlTagId.BlockGroup) {
      const block = chunk.Children.find(c => c.id === EbmlTagId.Block)

      if (block && this.subtitleTracks.has(block.track)) {
        const blockDuration = getData(chunk, EbmlTagId.BlockDuration)
        const type = this.subtitleTracks.get(block.track).type

        const subtitle = {
          text: block.payload.toString('utf8'),
          time: (block.value + this._currentClusterTimecode) * this.timecodeScale,
          duration: blockDuration * this.timecodeScale
        }

        if (SSA_TYPES.has(type)) {
          // extract SSA/ASS keys
          const values = subtitle.text.split(',')

          // ignore read-order, and skip layer if ssa
          for (let i = type === 'ssa' ? 2 : 1; i < 8; i++) {
            subtitle[SSA_KEYS[i]] = values[i]
          }

          subtitle.text = values.slice(8).join(',')
        }

        this.emit('subtitle', subtitle, block.track)
      }
    }

    // Parse attached files, mainly to allow extracting subtitle font files.
    if (chunk.id === EbmlTagId.AttachedFile) {
      this.emit('file', {
        filename: getData(chunk, EbmlTagId.FileName),
        mimetype: getData(chunk, EbmlTagId.FileMimeType),
        data: getData(chunk, EbmlTagId.FileData)
      })
    }
  }
}
<|endoftext|>


<commit_before>/* eslint-disable max-classes-per-file */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/* eslint-disable quote-props */
/* eslint-disable max-classes-per-file */

import { NAME_TYPE_KEYS } from '../database/utilities/constants';

export const INTERNAL_TO_EXTERNAL = 0;
export const EXTERNAL_TO_INTERNAL = 1;

class SyncTranslator {
  constructor(internalToExternal) {
    this.internalToExternal = internalToExternal;
    this.externalToInternal = {};
    // TODO: replace generators with explicit loops.
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of Object.entries(internalToExternal)) {
      this.externalToInternal[value] = key;
    }
  }

  translate(key, direction) {
    switch (direction) {
      case INTERNAL_TO_EXTERNAL:
      default:
        return this.internalToExternal[key];
      case EXTERNAL_TO_INTERNAL:
        return this.externalToInternal[key];
    }
  }
}

// Map of internal database object types to external record types.
export const RECORD_TYPES = new SyncTranslator({
  IndicatorAttribute: 'indicator_attribute',
  IndicatorValue: 'indicator_value',
  Item: 'item',
  ItemStoreJoin: 'item_store_join',
  ItemBatch: 'item_line',
  ItemDepartment: 'item_department',
  ItemCategory: 'item_category',
  LocalListItem: 'list_local_line',
  MasterList: 'list_master',
  MasterListItem: 'list_master_line',
  MasterListNameJoin: 'list_master_name_join',
  Message: 'message',
  Name: 'name',
  NameStoreJoin: 'name_store_join',
  NameTag: 'name_tag',
  NameTagJoin: 'name_tag_join',
  NumberSequence: 'number',
  NumberToReuse: 'number_reuse',
  Options: 'options',
  PaymentType: 'paymentType',
  Period: 'period',
  PeriodSchedule: 'periodSchedule',
  ProgramIndicator: 'program_indicator',
  Report: 'dashboard_store_report',
  Requisition: 'requisition',
  RequisitionItem: 'requisition_line',
  Stocktake: 'Stock_take',
  StocktakeBatch: 'Stock_take_lines',
  Store: 'store',
  Transaction: 'transact',
  TransactionCategory: 'transaction_category',
  TransactionBatch: 'trans_line',
  User: 'user',
  Unit: 'unit',
  Preference: 'pref',
  Prescriber: 'clinician',
  ItemDirection: 'item_direction',
  Abbreviation: 'abbreviation',
  InsuranceProvider: 'insuranceProvider',
  InsurancePolicy: 'nameInsuranceJoin',
  Currency: 'currency',
  VaccineVialMonitorStatus: 'vaccine_vial_monitor_status',
  VaccineVialMonitorStatusLog: 'vaccine_vial_monitor_status_log',
  Sensor: 'sensor',
  Location: 'Location',
  LocationType: 'Location_type',
  LocationMovement: 'location_movement',
  TemperatureLog: 'temperature_log',
  TemperatureBreach: 'temperature_breach',
  TemperatureBreachConfiguration: 'temperature_breach_config',
});

export const REQUISITION_TYPES = new SyncTranslator({
  imprest: 'im',
  forecast: 'sh',
  request: 'request',
  response: 'response',
});

// Map of internal database change types to external sync types.
export const SYNC_TYPES = new SyncTranslator({
  create: 'I', // For 'insert'
  update: 'U',
  delete: 'D',
  merge: 'M',
});

export const TRANSACTION_TYPES = new SyncTranslator({
  customer_invoice: 'ci',
  customer_credit: 'cc',
  supplier_invoice: 'si',
  supplier_credit: 'sc',
  inventory_adjustment: 'in',
  prescription: 'pi',
  receipt: 'rc',
  payment: 'ps',
  // Following types provided for sync purposes, not actually used by mobile.
  build: 'bu',
  repack: 'sr',
});

export const NAME_TYPES = new SyncTranslator({
  [NAME_TYPE_KEYS.INVENTORY_ADJUSTMENT]: 'invad',
  [NAME_TYPE_KEYS.FACILITY]: 'facility',
  [NAME_TYPE_KEYS.PATIENT]: 'patient',
  [NAME_TYPE_KEYS.BUILD]: 'build',
  [NAME_TYPE_KEYS.STORE]: 'store',
  [NAME_TYPE_KEYS.REPACK]: 'repack',
});

/**
 * Translates requisition statuses, which will be changed by the supplying store
 * once finalised in the mobile store. Despite the supplying store's requisition
 * going through 'sg', 'cn', and 'fn' statuses, it should remain finalised in the
 * mobile store.
 */
class RequisitionStatusTranslator extends SyncTranslator {
  translate(status, direction) {
    if (['cn', 'wf'].includes(status)) return 'finalised';
    return super.translate(status, direction);
  }
}
export const REQUISITION_STATUSES = new RequisitionStatusTranslator({
  new: 'wp', // 'wp', 'wf', 'cn' should never be returned in api/v3.
  suggested: 'sg',
  finalised: 'fn',
});

/**
 * Translates statuses of transactions, stocktakes, etc., which include 'wp' and 'wf'
 * on legacy systems.
 */
class StatusTranslator extends SyncTranslator {
  translate(status, direction) {
    switch (status) {
      case 'wp':
        return 'new';
      case 'wf':
        return 'finalised';
      default:
        return super.translate(status, direction);
    }
  }
}
// Map of internal statuses to external statuses (of transactions, stocktakes, etc.).
export const STATUSES = new StatusTranslator({
  confirmed: 'cn',
  finalised: 'fn',
  suggested: 'sg',
  new: 'nw',
});

/**
 * Translates number sequence keys from internal to external formats, and vice versa.
 * If translating external to internal, will return null if it is a sequence key
 * not used by mobile, or if it relates to a different store.
 */
class SequenceKeyTranslator extends SyncTranslator {
  translate(sequenceKey, direction, thisStoreId) {
    let key = sequenceKey;
    if (direction === EXTERNAL_TO_INTERNAL) {
      if (key.length < thisStoreId.length) return null; // Not a key used here.
      // Relevamt mSupply sequence keys end with the store id they relate to.
      const storeId = key.substring(key.length - thisStoreId.length);
      // If the sequence doesn't relate to this store, ignore.
      if (storeId !== thisStoreId) return null;
      key = key.substring(0, key.length - thisStoreId.length);
    }
    let translatedKey = super.translate(key, direction);
    if (direction === INTERNAL_TO_EXTERNAL) translatedKey += thisStoreId;
    return translatedKey;
  }
}
export const SEQUENCE_KEYS = new SequenceKeyTranslator({
  customer_invoice_serial_number: 'customer_invoice_number_for_store_',
  inventory_adjustment_serial_number: 'inventory_adjustment_serial_number_for_store_',
  requisition_serial_number: 'requisition_serial_number_for_store_',
  requisition_requester_reference: 'requisition_requester_reference_for_store_',
  stocktake_serial_number: 'stock_take_number_for_store_',
  supplier_invoice_serial_number: 'supplier_invoice_number_for_store_',
});
<commit_msg>Add tables to sync translators<commit_after>/* eslint-disable max-classes-per-file */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/* eslint-disable quote-props */
/* eslint-disable max-classes-per-file */

import { NAME_TYPE_KEYS } from '../database/utilities/constants';

export const INTERNAL_TO_EXTERNAL = 0;
export const EXTERNAL_TO_INTERNAL = 1;

class SyncTranslator {
  constructor(internalToExternal) {
    this.internalToExternal = internalToExternal;
    this.externalToInternal = {};
    // TODO: replace generators with explicit loops.
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of Object.entries(internalToExternal)) {
      this.externalToInternal[value] = key;
    }
  }

  translate(key, direction) {
    switch (direction) {
      case INTERNAL_TO_EXTERNAL:
      default:
        return this.internalToExternal[key];
      case EXTERNAL_TO_INTERNAL:
        return this.externalToInternal[key];
    }
  }
}

// Map of internal database object types to external record types.
export const RECORD_TYPES = new SyncTranslator({
  Abbreviation: 'abbreviation',
  Currency: 'currency',
  Ethnicity: 'Ethnicity',
  IndicatorAttribute: 'indicator_attribute',
  IndicatorValue: 'indicator_value',
  InsurancePolicy: 'nameInsuranceJoin',
  InsuranceProvider: 'insuranceProvider',
  Item: 'item',
  ItemBatch: 'item_line',
  ItemCategory: 'item_category',
  ItemDepartment: 'item_department',
  ItemDirection: 'item_direction',
  ItemStoreJoin: 'item_store_join',
  LocalListItem: 'list_local_line',
  Location: 'Location',
  LocationMovement: 'location_movement',
  LocationType: 'Location_type',
  MasterList: 'list_master',
  MasterListItem: 'list_master_line',
  MasterListNameJoin: 'list_master_name_join',
  Message: 'message',
  Name: 'name',
  NameStoreJoin: 'name_store_join',
  NameTag: 'name_tag',
  NameTagJoin: 'name_tag_join',
  Nationality: 'nationality',
  NumberSequence: 'number',
  NumberToReuse: 'number_reuse',
  Occupation: 'Occupation',
  Options: 'options',
  PaymentType: 'paymentType',
  Period: 'period',
  PeriodSchedule: 'periodSchedule',
  Preference: 'pref',
  Prescriber: 'clinician',
  ProgramIndicator: 'program_indicator',
  Report: 'dashboard_store_report',
  Requisition: 'requisition',
  RequisitionItem: 'requisition_line',
  Sensor: 'sensor',
  Stocktake: 'Stock_take',
  StocktakeBatch: 'Stock_take_lines',
  Store: 'store',
  TemperatureBreach: 'temperature_breach',
  TemperatureBreachConfiguration: 'temperature_breach_config',
  TemperatureLog: 'temperature_log',
  Transaction: 'transact',
  TransactionBatch: 'trans_line',
  TransactionCategory: 'transaction_category',
  Unit: 'unit',
  User: 'user',
  VaccineVialMonitorStatus: 'vaccine_vial_monitor_status',
  VaccineVialMonitorStatusLog: 'vaccine_vial_monitor_status_log',
});

export const REQUISITION_TYPES = new SyncTranslator({
  imprest: 'im',
  forecast: 'sh',
  request: 'request',
  response: 'response',
});

// Map of internal database change types to external sync types.
export const SYNC_TYPES = new SyncTranslator({
  create: 'I', // For 'insert'
  update: 'U',
  delete: 'D',
  merge: 'M',
});

export const TRANSACTION_TYPES = new SyncTranslator({
  customer_invoice: 'ci',
  customer_credit: 'cc',
  supplier_invoice: 'si',
  supplier_credit: 'sc',
  inventory_adjustment: 'in',
  prescription: 'pi',
  receipt: 'rc',
  payment: 'ps',
  // Following types provided for sync purposes, not actually used by mobile.
  build: 'bu',
  repack: 'sr',
});

export const NAME_TYPES = new SyncTranslator({
  [NAME_TYPE_KEYS.INVENTORY_ADJUSTMENT]: 'invad',
  [NAME_TYPE_KEYS.FACILITY]: 'facility',
  [NAME_TYPE_KEYS.PATIENT]: 'patient',
  [NAME_TYPE_KEYS.BUILD]: 'build',
  [NAME_TYPE_KEYS.STORE]: 'store',
  [NAME_TYPE_KEYS.REPACK]: 'repack',
});

/**
 * Translates requisition statuses, which will be changed by the supplying store
 * once finalised in the mobile store. Despite the supplying store's requisition
 * going through 'sg', 'cn', and 'fn' statuses, it should remain finalised in the
 * mobile store.
 */
class RequisitionStatusTranslator extends SyncTranslator {
  translate(status, direction) {
    if (['cn', 'wf'].includes(status)) return 'finalised';
    return super.translate(status, direction);
  }
}
export const REQUISITION_STATUSES = new RequisitionStatusTranslator({
  new: 'wp', // 'wp', 'wf', 'cn' should never be returned in api/v3.
  suggested: 'sg',
  finalised: 'fn',
});

/**
 * Translates statuses of transactions, stocktakes, etc., which include 'wp' and 'wf'
 * on legacy systems.
 */
class StatusTranslator extends SyncTranslator {
  translate(status, direction) {
    switch (status) {
      case 'wp':
        return 'new';
      case 'wf':
        return 'finalised';
      default:
        return super.translate(status, direction);
    }
  }
}
// Map of internal statuses to external statuses (of transactions, stocktakes, etc.).
export const STATUSES = new StatusTranslator({
  confirmed: 'cn',
  finalised: 'fn',
  suggested: 'sg',
  new: 'nw',
});

/**
 * Translates number sequence keys from internal to external formats, and vice versa.
 * If translating external to internal, will return null if it is a sequence key
 * not used by mobile, or if it relates to a different store.
 */
class SequenceKeyTranslator extends SyncTranslator {
  translate(sequenceKey, direction, thisStoreId) {
    let key = sequenceKey;
    if (direction === EXTERNAL_TO_INTERNAL) {
      if (key.length < thisStoreId.length) return null; // Not a key used here.
      // Relevamt mSupply sequence keys end with the store id they relate to.
      const storeId = key.substring(key.length - thisStoreId.length);
      // If the sequence doesn't relate to this store, ignore.
      if (storeId !== thisStoreId) return null;
      key = key.substring(0, key.length - thisStoreId.length);
    }
    let translatedKey = super.translate(key, direction);
    if (direction === INTERNAL_TO_EXTERNAL) translatedKey += thisStoreId;
    return translatedKey;
  }
}
export const SEQUENCE_KEYS = new SequenceKeyTranslator({
  customer_invoice_serial_number: 'customer_invoice_number_for_store_',
  inventory_adjustment_serial_number: 'inventory_adjustment_serial_number_for_store_',
  requisition_serial_number: 'requisition_serial_number_for_store_',
  requisition_requester_reference: 'requisition_requester_reference_for_store_',
  stocktake_serial_number: 'stock_take_number_for_store_',
  supplier_invoice_serial_number: 'supplier_invoice_number_for_store_',
});
<|endoftext|>


<commit_before>'use strict';
/* global describe, it, beforeEach */
/* eslint react/jsx-boolean-value: 0 */

// Copied from Async-test verbatim; may need to be reevaluated later.
var jsdomHelper = require('../testHelpers/jsdomHelper');
jsdomHelper();
var unexpected = require('unexpected');
var unexpectedDom = require('unexpected-dom');
var unexpectedReact = require('unexpected-react');
var expect = unexpected
	.clone()
	.installPlugin(unexpectedDom)
	.installPlugin(unexpectedReact);

var React = require('react');
var ReactDOM = require('react-dom');
var TestUtils = require('react-addons-test-utils');
var Select = require('../src/Select');

describe('Creatable', () => {
	let creatableInstance, creatableNode, filterInputNode, innserSelectInstance, renderer;

	beforeEach(() => renderer = TestUtils.createRenderer());

	const defaultOptions = [
		{ value: 'one', label: 'One' },
		{ value: 'two', label: '222' },
		{ value: 'three', label: 'Three' },
		{ value: 'four', label: 'AbcDef' }
	];

	function createControl (props = {}) {
		props.options = props.options || defaultOptions;
		creatableInstance = TestUtils.renderIntoDocument(
			<Select.Creatable {...props} />
		);
		creatableNode = ReactDOM.findDOMNode(creatableInstance);
		innserSelectInstance = creatableInstance.select;
		findAndFocusInputControl();
	};

	function findAndFocusInputControl () {
		filterInputNode = creatableNode.querySelector('input');
		if (filterInputNode) {
			TestUtils.Simulate.focus(filterInputNode);
		}
	};

	function typeSearchText (text) {
		TestUtils.Simulate.change(filterInputNode, { target: { value: text } });
	};

	it('should render a decorated Select (with passed through properties)', () => {
		createControl({
			inputProps: {
				className: 'foo'
			}
		});
		expect(creatableNode.querySelector('.Select-input'), 'to have attributes', {
			class: ['foo']
		});
	});

	it('should add a placeholder "create..." prompt when filter text is entered that does not match any existing options', () => {
		createControl();
		typeSearchText('foo');
		expect(creatableNode.querySelector('.Select-create-option-placeholder'), 'to have text', Select.Creatable.promptTextCreator('foo'));
	});

	it('should not show a "create..." prompt if current filter text is an exact match for an existing option', () => {
		createControl({
			isOptionUnique: () => false
		});
		typeSearchText('existing');
		expect(creatableNode.querySelector('.Select-menu-outer').textContent, 'not to equal', Select.Creatable.promptTextCreator('existing'));
	});

	it('should not show a "create..." prompt if current filter text is not a valid option (as determined by :isValidNewOption prop)', () => {
		createControl({
			isValidNewOption: () => false
		});
		typeSearchText('invalid');
		expect(creatableNode.querySelector('.Select-menu-outer').textContent, 'not to equal', Select.Creatable.promptTextCreator('invalid'));
	});

	it('should create (and auto-select) a new option when placeholder option is clicked', () => {
		let selectedOption;
		const options = [];
		createControl({
			onChange: (option) => selectedOption = option,
			options
		});
		typeSearchText('foo');
		TestUtils.Simulate.mouseDown(creatableNode.querySelector('.Select-create-option-placeholder'));
		expect(options, 'to have length', 1);
		expect(options[0].label, 'to equal', 'foo');
		expect(selectedOption, 'to be', options[0]);
	});

	it('should create (and auto-select) a new option when ENTER is pressed while placeholder option is selected', () => {
		let selectedOption;
		const options = [];
		createControl({
			onChange: (option) => selectedOption = option,
			options,
			shouldKeyDownEventCreateNewOption: () => true
		});
		typeSearchText('foo');
		TestUtils.Simulate.keyDown(filterInputNode, { keyCode: 13 });
		expect(options, 'to have length', 1);
		expect(options[0].label, 'to equal', 'foo');
		expect(selectedOption, 'to be', options[0]);
	});

	it('should not create a new option if the placeholder option is not selected but should select the focused option', () => {
		const options = [{ label: 'One', value: 1 }];
		createControl({
			options,
			shouldKeyDownEventCreateNewOption: ({ keyCode }) => keyCode === 13
		});
		typeSearchText('on'); // ['Create option "on"', 'One']
		TestUtils.Simulate.keyDown(filterInputNode, { keyCode: 40, key: 'ArrowDown' }); // Select 'One'
		TestUtils.Simulate.keyDown(filterInputNode, { keyCode: 13 });
		expect(options, 'to have length', 1);
	});

	it('should allow a custom select type to be rendered via the :children property', () => {
		let childProps;
		createControl({
			children: (props) => {
				childProps = props;
				return
faux select
;
			}
		});
		expect(creatableNode.textContent, 'to equal', 'faux select');
		expect(childProps.allowCreate, 'to equal', true);
	});

	it('default :children function renders a Select component', () => {
		createControl();
		expect(creatableNode.className, 'to contain', 'Select');
	});

	it('default :isOptionUnique function should do a simple equality check for value and label', () => {
		const options = [
			newOption('foo', 1),
			newOption('bar', 2),
			newOption('baz', 3)
		];

		function newOption (label, value) {
			return { label, value };
		};

		function test (option) {
			return Select.Creatable.isOptionUnique({
				labelKey: 'label',
				option,
				options,
				valueKey: 'value'
			});
		};

		expect(test(newOption('foo', 0)), 'to be', false);
		expect(test(newOption('qux', 1)), 'to be', false);
		expect(test(newOption('qux', 4)), 'to be', true);
		expect(test(newOption('Foo', 11)), 'to be', true);
	});

	it('default :isValidNewOption function should just ensure a non-empty string is provided', () => {
		function test (label) {
			return Select.Creatable.isValidNewOption({ label });
		};

		expect(test(''), 'to be', false);
		expect(test('a'), 'to be', true);
		expect(test(' '), 'to be', true);
	});

	it('default :newOptionCreator function should create an option with a :label and :value equal to the label string', () => {
		const option = Select.Creatable.newOptionCreator({
			label: 'foo',
			labelKey: 'label',
			valueKey: 'value'
		});
		expect(option.className, 'to equal', 'Select-create-option-placeholder');
		expect(option.label, 'to equal', 'foo');
		expect(option.value, 'to equal', 'foo');
	});

	it('default :shouldKeyDownEventCreateNewOption function should accept TAB, ENTER, and comma keys', () => {
		function test (keyCode) {
			return Select.Creatable.shouldKeyDownEventCreateNewOption({ keyCode });
		};

		expect(test(9), 'to be', true);
		expect(test(13), 'to be', true);
		expect(test(188), 'to be', true);
		expect(test(1), 'to be', false);
	});
});
<commit_msg>Added a test for updated filterOptions<commit_after>'use strict';
/* global describe, it, beforeEach */
/* eslint react/jsx-boolean-value: 0 */

// Copied from Async-test verbatim; may need to be reevaluated later.
var jsdomHelper = require('../testHelpers/jsdomHelper');
jsdomHelper();
var unexpected = require('unexpected');
var unexpectedDom = require('unexpected-dom');
var unexpectedReact = require('unexpected-react');
var expect = unexpected
	.clone()
	.installPlugin(unexpectedDom)
	.installPlugin(unexpectedReact);

var React = require('react');
var ReactDOM = require('react-dom');
var TestUtils = require('react-addons-test-utils');
var Select = require('../src/Select');

describe('Creatable', () => {
	let creatableInstance, creatableNode, filterInputNode, innserSelectInstance, renderer;

	beforeEach(() => renderer = TestUtils.createRenderer());

	const defaultOptions = [
		{ value: 'one', label: 'One' },
		{ value: 'two', label: '222' },
		{ value: 'three', label: 'Three' },
		{ value: 'four', label: 'AbcDef' }
	];

	function createControl (props = {}) {
		props.options = props.options || defaultOptions;
		creatableInstance = TestUtils.renderIntoDocument(
			<Select.Creatable {...props} />
		);
		creatableNode = ReactDOM.findDOMNode(creatableInstance);
		innserSelectInstance = creatableInstance.select;
		findAndFocusInputControl();
	};

	function findAndFocusInputControl () {
		filterInputNode = creatableNode.querySelector('input');
		if (filterInputNode) {
			TestUtils.Simulate.focus(filterInputNode);
		}
	};

	function typeSearchText (text) {
		TestUtils.Simulate.change(filterInputNode, { target: { value: text } });
	};

	it('should render a decorated Select (with passed through properties)', () => {
		createControl({
			inputProps: {
				className: 'foo'
			}
		});
		expect(creatableNode.querySelector('.Select-input'), 'to have attributes', {
			class: ['foo']
		});
	});

	it('should add a placeholder "create..." prompt when filter text is entered that does not match any existing options', () => {
		createControl();
		typeSearchText('foo');
		expect(creatableNode.querySelector('.Select-create-option-placeholder'), 'to have text', Select.Creatable.promptTextCreator('foo'));
	});

	it('should not show a "create..." prompt if current filter text is an exact match for an existing option', () => {
		createControl({
			isOptionUnique: () => false
		});
		typeSearchText('existing');
		expect(creatableNode.querySelector('.Select-menu-outer').textContent, 'not to equal', Select.Creatable.promptTextCreator('existing'));
	});

	it('should filter the "create..." prompt using both filtered options and currently-selected options', () => {
		let isOptionUniqueParams;
		createControl({
			filterOptions: () => [
				{ value: 'one', label: 'One' }
			],
			isOptionUnique: (params) => {
				isOptionUniqueParams = params;
			},
			multi: true,
			options: [
				{ value: 'one', label: 'One' },
				{ value: 'two', label: 'Two' }
			],
			value: [
				{ value: 'three', label: 'Three' }
			]
		});
		typeSearchText('test');
		const { options } = isOptionUniqueParams;
		const values = options.map(option => option.value);
		expect(values, 'to have length', 2);
		expect(values, 'to contain', 'one');
		expect(values, 'to contain', 'three');
	});

	it('should not show a "create..." prompt if current filter text is not a valid option (as determined by :isValidNewOption prop)', () => {
		createControl({
			isValidNewOption: () => false
		});
		typeSearchText('invalid');
		expect(creatableNode.querySelector('.Select-menu-outer').textContent, 'not to equal', Select.Creatable.promptTextCreator('invalid'));
	});

	it('should create (and auto-select) a new option when placeholder option is clicked', () => {
		let selectedOption;
		const options = [];
		createControl({
			onChange: (option) => selectedOption = option,
			options
		});
		typeSearchText('foo');
		TestUtils.Simulate.mouseDown(creatableNode.querySelector('.Select-create-option-placeholder'));
		expect(options, 'to have length', 1);
		expect(options[0].label, 'to equal', 'foo');
		expect(selectedOption, 'to be', options[0]);
	});

	it('should create (and auto-select) a new option when ENTER is pressed while placeholder option is selected', () => {
		let selectedOption;
		const options = [];
		createControl({
			onChange: (option) => selectedOption = option,
			options,
			shouldKeyDownEventCreateNewOption: () => true
		});
		typeSearchText('foo');
		TestUtils.Simulate.keyDown(filterInputNode, { keyCode: 13 });
		expect(options, 'to have length', 1);
		expect(options[0].label, 'to equal', 'foo');
		expect(selectedOption, 'to be', options[0]);
	});

	it('should not create a new option if the placeholder option is not selected but should select the focused option', () => {
		const options = [{ label: 'One', value: 1 }];
		createControl({
			options,
			shouldKeyDownEventCreateNewOption: ({ keyCode }) => keyCode === 13
		});
		typeSearchText('on'); // ['Create option "on"', 'One']
		TestUtils.Simulate.keyDown(filterInputNode, { keyCode: 40, key: 'ArrowDown' }); // Select 'One'
		TestUtils.Simulate.keyDown(filterInputNode, { keyCode: 13 });
		expect(options, 'to have length', 1);
	});

	it('should allow a custom select type to be rendered via the :children property', () => {
		let childProps;
		createControl({
			children: (props) => {
				childProps = props;
				return
faux select
;
			}
		});
		expect(creatableNode.textContent, 'to equal', 'faux select');
		expect(childProps.allowCreate, 'to equal', true);
	});

	it('default :children function renders a Select component', () => {
		createControl();
		expect(creatableNode.className, 'to contain', 'Select');
	});

	it('default :isOptionUnique function should do a simple equality check for value and label', () => {
		const options = [
			newOption('foo', 1),
			newOption('bar', 2),
			newOption('baz', 3)
		];

		function newOption (label, value) {
			return { label, value };
		};

		function test (option) {
			return Select.Creatable.isOptionUnique({
				labelKey: 'label',
				option,
				options,
				valueKey: 'value'
			});
		};

		expect(test(newOption('foo', 0)), 'to be', false);
		expect(test(newOption('qux', 1)), 'to be', false);
		expect(test(newOption('qux', 4)), 'to be', true);
		expect(test(newOption('Foo', 11)), 'to be', true);
	});

	it('default :isValidNewOption function should just ensure a non-empty string is provided', () => {
		function test (label) {
			return Select.Creatable.isValidNewOption({ label });
		};

		expect(test(''), 'to be', false);
		expect(test('a'), 'to be', true);
		expect(test(' '), 'to be', true);
	});

	it('default :newOptionCreator function should create an option with a :label and :value equal to the label string', () => {
		const option = Select.Creatable.newOptionCreator({
			label: 'foo',
			labelKey: 'label',
			valueKey: 'value'
		});
		expect(option.className, 'to equal', 'Select-create-option-placeholder');
		expect(option.label, 'to equal', 'foo');
		expect(option.value, 'to equal', 'foo');
	});

	it('default :shouldKeyDownEventCreateNewOption function should accept TAB, ENTER, and comma keys', () => {
		function test (keyCode) {
			return Select.Creatable.shouldKeyDownEventCreateNewOption({ keyCode });
		};

		expect(test(9), 'to be', true);
		expect(test(13), 'to be', true);
		expect(test(188), 'to be', true);
		expect(test(1), 'to be', false);
	});
});
<|endoftext|>