<commit_before>'use strict';

/** @module mutators */

const _ = require('lodash');

const castTimestamp = (value) => {
  if(_.isDate(value)) {
    return '::timestamptz';
  }
  return '';
};

/**
 * Build a BETWEEN (a, b) predicate.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.buildBetween = condition => {
  condition.params = condition.value;
  condition.value = `$${condition.offset}${castTimestamp(condition.value[0])} AND $${condition.offset + 1}${castTimestamp(condition.value[1])}`;
  condition.offset += 2;

  return condition;
};

/**
 * Build an IN (x, y, z) predicate.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.buildIn = condition => {
  condition.appended.operator = condition.appended.operator === '=' ? 'IN' : 'NOT IN';

  const inList = _.reduce(condition.value, (list, v) => {
    condition.params.push(v);

    return list.concat([`$${condition.offset++}${castTimestamp(v)}`]);
  }, []);

  condition.value = `(${inList.join(',')})`;

  return condition;
};

/**
 * Interpolate values into a predicate with IS/IS NOT.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.buildIs = function (condition) {
  if (condition.appended.operator === '=' || condition.appended.operator === 'IS') {
    condition.appended.operator = 'IS';
  } else { condition.appended.operator = 'IS NOT'; }

  return condition;
};

/**
 * Handle the overloads for equality tests: interpolating null and boolean
 * values and building IN lists.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.equality = function (condition) {
  if (condition.value === null || _.isBoolean(condition.value)) {
    return exports.buildIs(condition);
  } else if (_.isArray(condition.value)) {
    return exports.buildIn(condition);
  }

  condition.params.push(condition.value);

  condition.value = `$${condition.offset}${castTimestamp(condition.value)}`;

  return condition;
};

/**
 * Transform an array into a safe comma-delimited string literal.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.literalizeArray = condition => {
  if (_.isArray(condition.value)) {
    const sanitizedValues = condition.value.map(function (v) {
      if (_.isString(v) && (v === '' || v === 'null' || v.search(/[,{}\s\\"]/) !== -1)) {
        return `"${v.replace(/([\\"])/g, '\\$1')}"`;
      } else if (v === null) {
        return 'null';
      }

      return v;
    });

    condition.params.push(`{${sanitizedValues.join(',')}}`);
  } else {
    condition.params.push(condition.value);
  }

  condition.value = `$${condition.offset}${castTimestamp(condition.value)}`;

  return condition;
};
<commit_msg>style: spacing<commit_after>'use strict';

/** @module mutators */

const _ = require('lodash');

const castTimestamp = (value) => {
  if (_.isDate(value)) {
    return '::timestamptz';
  }

  return '';
};

/**
 * Build a BETWEEN (a, b) predicate.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.buildBetween = condition => {
  condition.params = condition.value;
  condition.value = `$${condition.offset}${castTimestamp(condition.value[0])} AND $${condition.offset + 1}${castTimestamp(condition.value[1])}`;
  condition.offset += 2;

  return condition;
};

/**
 * Build an IN (x, y, z) predicate.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.buildIn = condition => {
  condition.appended.operator = condition.appended.operator === '=' ? 'IN' : 'NOT IN';

  const inList = _.reduce(condition.value, (list, v) => {
    condition.params.push(v);

    return list.concat([`$${condition.offset++}${castTimestamp(v)}`]);
  }, []);

  condition.value = `(${inList.join(',')})`;

  return condition;
};

/**
 * Interpolate values into a predicate with IS/IS NOT.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.buildIs = function (condition) {
  if (condition.appended.operator === '=' || condition.appended.operator === 'IS') {
    condition.appended.operator = 'IS';
  } else { condition.appended.operator = 'IS NOT'; }

  return condition;
};

/**
 * Handle the overloads for equality tests: interpolating null and boolean
 * values and building IN lists.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.equality = function (condition) {
  if (condition.value === null || _.isBoolean(condition.value)) {
    return exports.buildIs(condition);
  } else if (_.isArray(condition.value)) {
    return exports.buildIn(condition);
  }

  condition.params.push(condition.value);

  condition.value = `$${condition.offset}${castTimestamp(condition.value)}`;

  return condition;
};

/**
 * Transform an array into a safe comma-delimited string literal.
 *
 * @param {Object} condition - A condition object from {@link module:where~getCondition}.
 * @return {Object} The modified condition.
 */
exports.literalizeArray = condition => {
  if (_.isArray(condition.value)) {
    const sanitizedValues = condition.value.map(function (v) {
      if (_.isString(v) && (v === '' || v === 'null' || v.search(/[,{}\s\\"]/) !== -1)) {
        return `"${v.replace(/([\\"])/g, '\\$1')}"`;
      } else if (v === null) {
        return 'null';
      }

      return v;
    });

    condition.params.push(`{${sanitizedValues.join(',')}}`);
  } else {
    condition.params.push(condition.value);
  }

  condition.value = `$${condition.offset}${castTimestamp(condition.value)}`;

  return condition;
};
<|endoftext|>


<commit_before>/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  let min = 999999, max = -1;
  let res = 0;

  for (let index = 0; index < prices.length; index++) {
    const element = prices[index];

    if (min > element) {
      min = element;
      max = -1;
    } else if (max < element) {
      max = element;
    }

    if (min !== 999999 && max !== -1) {
      res = Math.max(res, max - min);
    }
  }

  return res;
};<commit_msg>update: DP method<commit_after>/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  let min = 999999, max = -1;
  let res = 0;

  for (let index = 0; index < prices.length; index++) {
    const element = prices[index];

    if (min > element) {
      min = element;
      max = -1;
    } else if (max < element) {
      max = element;
    }

    if (min !== 999999 && max !== -1) {
      res = Math.max(res, max - min);
    }
  }

  return res;
};

/**
 * DP 解法
 * @param {*} prices
 */
var maxProfit_2 = (prices) => {
  if (prices.length < 2) return 0;

  let last = 0, max = 0;

  for (let i = 1; i < prices.length; i++) {
    last = Math.max(0, last + prices[i] - prices[i-1]);
    max = Math.max(last, max);
  }

  return max;
}<|endoftext|>


<commit_before>import { stringify } from 'jsan';
import configureStore from '../../../app/store/configureStore';
import { isAllowed } from '../options/syncOptions';
import notifyErrors from '../utils/notifyErrors';

window.devToolsExtension = function(config = {}) {
  let store = {};
  if (!window.devToolsOptions) window.devToolsOptions = {};
  let shouldSerialize = false;
  let shouldInit = true;
  let lastAction;
  let errorOccurred = false;

  function relaySerialized(message) {
    message.payload = stringify(message.payload);
    if (message.action !== '') message.action = stringify(message.action);
    window.postMessage(message, '*');
  }

  function relay(type, state, action, nextActionId) {
    setTimeout(() => {
      const message = {
        payload: state,
        action: action || '',
        nextActionId: nextActionId || '',
        type: type,
        source: 'redux-page',
        name: config.name || document.title,
        init: shouldInit
      };
      if (shouldInit) shouldInit = false;
      if (shouldSerialize || window.devToolsOptions.serialize) {
        relaySerialized(message);
      } else {
        try {
          window.postMessage(message, '*');
        } catch (err) {
          relaySerialized(message);
          shouldSerialize = true;
        }
      }
    }, 0);
  }

  function onMessage(event) {
    if (!event || event.source !== window) {
      return;
    }

    const message = event.data;

    if (!message || message.source !== 'redux-cs') {
      return;
    }

    if (message.type === 'DISPATCH') {
      store.liftedStore.dispatch(message.payload);
    } else if (message.type === 'UPDATE') {
      relay('STATE', store.liftedStore.getState());
    }
  }

  function isFiltered(action) {
    if (!window.devToolsOptions.filter) return false;
    const { whitelist, blacklist } = window.devToolsOptions;
    return (
      whitelist && whitelist.indexOf(action.type) === -1 ||
      blacklist && blacklist.indexOf(action.type) !== -1
    );
  }

  function addFilter(state) {
    if (window.devToolsOptions.filter) {
      if (window.devToolsOptions.whitelist) state.whitelist = window.devToolsOptions.whitelist;
      else if (window.devToolsOptions.blacklist) state.blacklist = window.devToolsOptions.blacklist;
    }
  }

  function isLimit(nextActionId) {
    if (
      window.devToolsOptions.limit && window.devToolsOptions.limit !== '0'
      && nextActionId - 1 > window.devToolsOptions.limit
    ) {
      store.liftedStore.dispatch({type: 'COMMIT', timestamp: Date.now()});
      return true;
    }
    return false;
  }

  function init() {
    window.addEventListener('message', onMessage, false);
    relay('STATE', store.liftedStore.getState());
    notifyErrors(() => {
      errorOccurred = true;
      const state = store.liftedStore.getState();
      if (state.computedStates[state.currentStateIndex].error) {
        relay('STATE', state);
        return false;
      }
      return true;
    });

    // Detect when the tab is reactivated
    document.addEventListener('visibilitychange', function() {
      if (document.visibilityState === 'visible') {
        shouldInit = true;
        relay('STATE', store.liftedStore.getState());
      }
    }, false);
  }

  function monitorReducer(state = {}, action) {
    lastAction = action.type;
    return state;
  }

  function handleChange(state, liftedState) {
    const nextActionId = liftedState.nextActionId;
    const liftedAction = liftedState.actionsById[nextActionId - 1];
    const action = liftedAction.action;
    if (action.type === '@@INIT') {
      relay('INIT', state, { timestamp: Date.now() });
    } else if (!errorOccurred && lastAction !== 'TOGGLE_ACTION' && lastAction !== 'SWEEP') {
      if (lastAction === 'JUMP_TO_STATE' || isLimit(nextActionId) || isFiltered(action)) return;
      relay('ACTION', state, liftedAction, nextActionId);
    } else {
      if (errorOccurred && !liftedState.computedStates[liftedState.currentStateIndex].error) errorOccurred = false;
      addFilter(liftedState);
      relay('STATE', liftedState);
    }
  }

  return (next) => {
    return (reducer, initialState, enhancer) => {
      if (!isAllowed(window.devToolsOptions)) return next(reducer, initialState, enhancer);

      store = configureStore(next, monitorReducer)(reducer, initialState, enhancer);
      init();
      store.subscribe(() => { handleChange(store.getState(), store.liftedStore.getState()); });
      return store;
    };
  };
};

window.devToolsExtension.open = function(position) {
  window.postMessage({
    source: 'redux-page',
    type: 'OPEN',
    position: position || ''
  }, '*');
};

window.devToolsExtension.notifyErrors = notifyErrors;
<commit_msg>Send new lifted state on hot-reloading<commit_after>import { stringify } from 'jsan';
import configureStore from '../../../app/store/configureStore';
import { isAllowed } from '../options/syncOptions';
import notifyErrors from '../utils/notifyErrors';

window.devToolsExtension = function(config = {}) {
  let store = {};
  if (!window.devToolsOptions) window.devToolsOptions = {};
  let shouldSerialize = false;
  let shouldInit = true;
  let lastAction;
  let errorOccurred = false;

  function relaySerialized(message) {
    message.payload = stringify(message.payload);
    if (message.action !== '') message.action = stringify(message.action);
    window.postMessage(message, '*');
  }

  function relay(type, state, action, nextActionId) {
    setTimeout(() => {
      const message = {
        payload: state,
        action: action || '',
        nextActionId: nextActionId || '',
        type: type,
        source: 'redux-page',
        name: config.name || document.title,
        init: shouldInit
      };
      if (shouldInit) shouldInit = false;
      if (shouldSerialize || window.devToolsOptions.serialize) {
        relaySerialized(message);
      } else {
        try {
          window.postMessage(message, '*');
        } catch (err) {
          relaySerialized(message);
          shouldSerialize = true;
        }
      }
    }, 0);
  }

  function onMessage(event) {
    if (!event || event.source !== window) {
      return;
    }

    const message = event.data;

    if (!message || message.source !== 'redux-cs') {
      return;
    }

    if (message.type === 'DISPATCH') {
      store.liftedStore.dispatch(message.payload);
    } else if (message.type === 'UPDATE') {
      relay('STATE', store.liftedStore.getState());
    }
  }

  function isFiltered(action) {
    if (!window.devToolsOptions.filter) return false;
    const { whitelist, blacklist } = window.devToolsOptions;
    return (
      whitelist && whitelist.indexOf(action.type) === -1 ||
      blacklist && blacklist.indexOf(action.type) !== -1
    );
  }

  function addFilter(state) {
    if (window.devToolsOptions.filter) {
      if (window.devToolsOptions.whitelist) state.whitelist = window.devToolsOptions.whitelist;
      else if (window.devToolsOptions.blacklist) state.blacklist = window.devToolsOptions.blacklist;
    }
  }

  function isLimit(nextActionId) {
    if (
      window.devToolsOptions.limit && window.devToolsOptions.limit !== '0'
      && nextActionId - 1 > window.devToolsOptions.limit
    ) {
      store.liftedStore.dispatch({type: 'COMMIT', timestamp: Date.now()});
      return true;
    }
    return false;
  }

  function init() {
    window.addEventListener('message', onMessage, false);
    relay('STATE', store.liftedStore.getState());
    notifyErrors(() => {
      errorOccurred = true;
      const state = store.liftedStore.getState();
      if (state.computedStates[state.currentStateIndex].error) {
        relay('STATE', state);
        return false;
      }
      return true;
    });

    // Detect when the tab is reactivated
    document.addEventListener('visibilitychange', function() {
      if (document.visibilityState === 'visible') {
        shouldInit = true;
        relay('STATE', store.liftedStore.getState());
      }
    }, false);
  }

  function monitorReducer(state = {}, action) {
    lastAction = action.type;
    if (lastAction === '@@redux/INIT' && store.liftedStore) {
      // Send new lifted state on hot-reloading
      setTimeout(() => {
        relay('STATE', store.liftedStore.getState());
      }, 0);
    }
    return state;
  }

  function handleChange(state, liftedState) {
    const nextActionId = liftedState.nextActionId;
    const liftedAction = liftedState.actionsById[nextActionId - 1];
    const action = liftedAction.action;
    if (action.type === '@@INIT') {
      relay('INIT', state, { timestamp: Date.now() });
    } else if (!errorOccurred && lastAction !== 'TOGGLE_ACTION' && lastAction !== 'SWEEP') {
      if (lastAction === 'JUMP_TO_STATE' || isLimit(nextActionId) || isFiltered(action)) return;
      relay('ACTION', state, liftedAction, nextActionId);
    } else {
      if (errorOccurred && !liftedState.computedStates[liftedState.currentStateIndex].error) errorOccurred = false;
      addFilter(liftedState);
      relay('STATE', liftedState);
    }
  }

  return (next) => {
    return (reducer, initialState, enhancer) => {
      if (!isAllowed(window.devToolsOptions)) return next(reducer, initialState, enhancer);

      store = configureStore(next, monitorReducer)(reducer, initialState, enhancer);
      init();
      store.subscribe(() => { handleChange(store.getState(), store.liftedStore.getState()); });
      return store;
    };
  };
};

window.devToolsExtension.open = function(position) {
  window.postMessage({
    source: 'redux-page',
    type: 'OPEN',
    position: position || ''
  }, '*');
};

window.devToolsExtension.notifyErrors = notifyErrors;
<|endoftext|>


<commit_before>/**
 * Created by GUY on 2017/2/8.
 *
 * @class BI.BubblePopupView
 * @extends BI.PopupView
 */
BI.BubblePopupView = BI.inherit(BI.PopupView, {
    _defaultConfig: function () {
        var config = BI.BubblePopupView.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(config, {
            baseCls: config.baseCls + " bi-bubble-popup-view",
            minWidth: 70,
            maxWidth: 300,
            minHeight: 50,
            showArrow: true,
        });
    }
});

BI.shortcut("bi.bubble_popup_view", BI.BubblePopupView);

/**
 * Created by GUY on 2017/2/8.
 *
 * @class BI.BubblePopupBarView
 * @extends BI.BubblePopupView
 */
BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, {
    _defaultConfig: function () {
        return BI.extend(BI.BubblePopupBarView.superclass._defaultConfig.apply(this, arguments), {
            extraCls: "bi-bubble-bar-popup-view",
            buttons: [{
                value: false,
                text: BI.i18nText("BI-Basic_Cancel"),
                level: "ignore"
            }, {
                text: BI.i18nText(BI.i18nText("BI-Basic_OK")),
                value: true
            }]
        });
    },
    _init: function () {
        BI.BubblePopupBarView.superclass._init.apply(this, arguments);
    },
    _createToolBar: function () {
        var o = this.options, self = this;

        var items = [];
        BI.each(o.buttons, function (i, buttonOpt) {
            if (BI.isWidget(buttonOpt)) {
                items.push({
                    el: buttonOpt,
                    lgap: i === 0 ? 20 : 15,
                    rgap: i === o.buttons.length - 1 ? 20 : 0
                });
            } else {
                items.push({
                    el: BI.extend({
                        type: "bi.button",
                        height: 24,
                        handler: function (v) {
                            self.fireEvent(BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON, v);
                        }
                    }, buttonOpt),
                    lgap: i === 0 ? 20 : 15,
                    rgap: i === o.buttons.length - 1 ? 20 : 0
                });
            }
        });
        return BI.createWidget({
            type: "bi.right_vertical_adapt",
            height: 54,
            items: items
        });
    },

    _createView: function () {
        var o = this.options;

        var button = BI.createWidget({
            type: "bi.button_group",
            items: [o.el],
            layouts: [{
                type: "bi.vertical",
                cls: "bar-popup-container",
                hgap: BI.SIZE_CONSANTS.H_GAP_SIZE,
                tgap: BI.SIZE_CONSANTS.V_GAP_SIZE
            }]
        });

        button.element.css("min-height", o.minHeight - 54);

        return button;
    }
});
BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON";
BI.shortcut("bi.bubble_bar_popup_view", BI.BubblePopupBarView);

/**
 * Created by Windy on 2018/2/2.
 *
 * @class BI.TextBubblePopupBarView
 * @extends BI.BubblePopupView
 */
BI.TextBubblePopupBarView = BI.inherit(BI.Widget, {

    props: function () {
        return {
            baseCls: "bi-text-bubble-bar-popup-view",
            text: "",
            buttons: [{
                level: "ignore",
                value: false,
                stopPropagation: true,
                text: BI.i18nText("BI-Basic_Cancel")
            }, {
                value: true,
                stopPropagation: true,
                text: BI.i18nText("BI-Basic_OK")
            }]
        };
    },

    render: function () {
        var self = this, o = this.options;
        var buttons = BI.map(o.buttons, function (index, buttonOpt) {
            if (BI.isWidget(buttonOpt)) {
                return buttonOpt;
            }
            return BI.extend({
                type: "bi.button",
                height: 24,
                handler: function (v) {
                    self.fireEvent(BI.TextBubblePopupBarView.EVENT_CHANGE, v);
                }
            }, buttonOpt);

        });
        return {
            type: "bi.bubble_bar_popup_view",
            primary: o.primary,
            showArrow: o.showArrow,
            minWidth: o.minWidth,
            maxWidth: o.maxWidth,
            minHeight: o.minHeight,
            ref: function () {
                self.popup = this;
            },
            el: {
                type: "bi.label",
                text: o.text,
                whiteSpace: "normal",
                textAlign: "left",
                ref: function () {
                    self.text = this;
                }
            },
            buttons: buttons
        };
    },

    setDirection: function (direction, position) {
        this.popup.setDirection(direction, position);
    },
    populate: function (v) {
        this.text.setText(v || this.options.text);
    }
});
BI.TextBubblePopupBarView.EVENT_CHANGE = "EVENT_CLICK_TOOLBAR_BUTTON";
BI.shortcut("bi.text_bubble_bar_popup_view", BI.TextBubblePopupBarView);
<commit_msg>chore： 优化一下<commit_after>/**
 * Created by GUY on 2017/2/8.
 *
 * @class BI.BubblePopupView
 * @extends BI.PopupView
 */
BI.BubblePopupView = BI.inherit(BI.PopupView, {
    _defaultConfig: function () {
        var config = BI.BubblePopupView.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(config, {
            baseCls: config.baseCls + " bi-bubble-popup-view",
            minWidth: 70,
            maxWidth: 300,
            minHeight: 50,
            showArrow: true,
        });
    }
});

BI.shortcut("bi.bubble_popup_view", BI.BubblePopupView);

/**
 * Created by GUY on 2017/2/8.
 *
 * @class BI.BubblePopupBarView
 * @extends BI.BubblePopupView
 */
BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, {
    _defaultConfig: function () {
        return BI.extend(BI.BubblePopupBarView.superclass._defaultConfig.apply(this, arguments), {
            extraCls: "bi-bubble-bar-popup-view",
            buttons: [{
                value: false,
                text: BI.i18nText("BI-Basic_Cancel"),
                level: "ignore"
            }, {
                text: BI.i18nText(BI.i18nText("BI-Basic_OK")),
                value: true
            }]
        });
    },

    _createToolBar: function () {
        var o = this.options, self = this;

        var items = [];
        BI.each(o.buttons, function (i, buttonOpt) {
            if (BI.isWidget(buttonOpt)) {
                items.push({
                    el: buttonOpt,
                    lgap: i === 0 ? 20 : 15,
                    rgap: i === o.buttons.length - 1 ? 20 : 0
                });
            } else {
                items.push({
                    el: BI.extend({
                        type: "bi.button",
                        height: 24,
                        handler: function (v) {
                            self.fireEvent(BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON, v);
                        }
                    }, buttonOpt),
                    lgap: i === 0 ? 20 : 15,
                    rgap: i === o.buttons.length - 1 ? 20 : 0
                });
            }
        });
        return BI.createWidget({
            type: "bi.right_vertical_adapt",
            height: 54,
            items: items
        });
    },

    _createContent: function () {
        return this.options.el;
    },

    _createView: function () {
        var o = this.options;

        var button = BI.createWidget({
            type: "bi.button_group",
            items: [this._createContent()],
            layouts: [{
                type: "bi.vertical",
                cls: "bar-popup-container",
                hgap: BI.SIZE_CONSANTS.H_GAP_SIZE,
                tgap: BI.SIZE_CONSANTS.V_GAP_SIZE
            }]
        });

        button.element.css("min-height", o.minHeight - 54);

        return button;
    }
});
BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON";
BI.shortcut("bi.bubble_bar_popup_view", BI.BubblePopupBarView);

/**
 * Created by Windy on 2018/2/2.
 *
 * @class BI.TextBubblePopupBarView
 * @extends BI.BubblePopupView
 */
BI.TextBubblePopupBarView = BI.inherit(BI.BubblePopupBarView, {

    props: function () {
        return {
            baseCls: "bi-text-bubble-bar-popup-view",
            text: "",
        };
    },

    _createContent: function () {
        var self = this, o = this.options;
        return {
            type: "bi.label",
            text: o.text,
            whiteSpace: "normal",
            textAlign: "left",
            ref: function () {
                self.text = this;
            }
        };
    },

    populate: function (v) {
        this.text.setText(v || this.options.text);
    }
});
BI.TextBubblePopupBarView.EVENT_CHANGE = "EVENT_CLICK_TOOLBAR_BUTTON";
BI.shortcut("bi.text_bubble_bar_popup_view", BI.TextBubblePopupBarView);
<|endoftext|>


<commit_before>"use strict";

var regexDefeatureUtils = require('./regex_defeature_utils');
var logger = null;

var _defeature = function( mimosaConfig, options, next ) {
  if ( options.files && options.files.length ) {
    options.files.forEach( function( file ) {
      // remove ranges from source
      var finalSource = "";
      var source = file.outputFileText;
      var start = 0;
      var opts = {
        source:                   source,
        includedFeatures:         mimosaConfig.defeature.includedFeatures,
        excludedFeatures:         mimosaConfig.defeature.excludedFeatures,
        startCommentText:         "/\\*",
        endCommentText:           "\\*/",
        logger:                   logger,
        allowEntireFileDefeature: false
      };
      var rangesToRemove = regexDefeatureUtils.mergeOverlappingRanges(regexDefeatureUtils.getRangesToRemove(opts));
      if(rangesToRemove.length > 0) {
        rangesToRemove.forEach(function(range) {
          finalSource += source.slice(start, range[0]);
          start = range[1];
        });
        finalSource += source.slice(start, source.length);
        file.outputFileText = finalSource;
      }
    });
  }

  next();
};

exports.registration = function( mimosaConfig, register ) {
  logger = mimosaConfig.log;
  var exts = mimosaConfig.extensions.css;
  register( ['add', 'update', 'remove', 'buildExtension'], 'afterCompile', _defeature, exts );
};<commit_msg>Replace unwanted feature code with new lines in css<commit_after>"use strict";

var regexDefeatureUtils = require('./regex_defeature_utils');
var logger = null;

var _defeature = function( mimosaConfig, options, next ) {
  if ( options.files && options.files.length ) {
    options.files.forEach( function( file ) {
      // remove ranges from source
      var finalSource = "";
      var source = file.outputFileText;
      var start = 0;
      var opts = {
        source:                   source,
        includedFeatures:         mimosaConfig.defeature.includedFeatures,
        excludedFeatures:         mimosaConfig.defeature.excludedFeatures,
        startCommentText:         "/\\*",
        endCommentText:           "\\*/",
        logger:                   logger,
        allowEntireFileDefeature: false
      };
      var rangesToRemove = regexDefeatureUtils.mergeOverlappingRanges(regexDefeatureUtils.getRangesToRemove(opts));
      if(rangesToRemove.length > 0) {
        rangesToRemove.forEach(function(range) {
          var sourceToDelete = source.substring(range[0], range[1]);
          var linesToDelete = sourceToDelete.split('\n');
          var newLineSource = linesToDelete.reduce(function(previous) {
            return previous + "\n";
          }, '');

          finalSource += source.slice(start, range[0]) + newLineSource;
          start = range[1];
        });
        finalSource += source.slice(start, source.length);
        file.outputFileText = finalSource;
      }
    });
  }

  next();
};

exports.registration = function( mimosaConfig, register ) {
  logger = mimosaConfig.log;
  var exts = mimosaConfig.extensions.css;
  register( ['add', 'update', 'remove', 'buildExtension'], 'afterCompile', _defeature, exts );
};<|endoftext|>


<commit_before>/**
 * Version: 0.5
 * Author: Riccardo Marton <marton.riccardo@gmail.com>
 *
 * License: Licensed under The MIT License. See LICENSE file
 */

var lightly = function() {

	/*
	 * Private properties
	 */
	var appname = "new App";
	var container = document.body;
	var pages = {};
	var history = [];
	var actions = {
		"navigate": {
			id: "navigate",
			callback: navigate,
			history: true
		},
		"back": {
			id: "back",
			callback: back,
			history: false
		}
	};

	/*
	 * Set a node as main container. lightly will not operate outside of the node
	 * provided
	 */
	function setContainer(node) {

		if (!inDOM(node))
			throw {
				name: "lightly-container-invalid",
				message: "Object provided is not a DOM element"
			}

		container = node;
	}

	/*
	 * Add a page to the pages object
	 */
	function addPage(page) {

		if( !page || typeof page.id != "string" ) {
			throw {
				name: "lightly-page-noid",
				message: "No id specified for new page"
			}
		}

		var new_page = {
			id: page.id,
			title: page.title || "New page",
			contents: page.contents || {},
			callback: page.callback || function() {}
		}

		pages[page.id] = new_page;

		triggerEvent(container, "lightly-page-added", {page: new_page});

	}

	/*
	 * Load and display a page
	 */
	function newPageElement(page_id, vars) {
		if (typeof pages[page_id] == "undefined")
			throw {
				name: "lightly-page-nonexistant",
				message: "Page "+page_id+" does not exist"
			}

		var page = pages[page_id];

		document.title = page.title;

		var div = document.createElement('div');
		div.innerHTML = container.innerHTML;

		for (id in page.contents) {

			var elem = div.getElementsByClassName(id)[0];
			if (elem == null)
				continue;

			if (typeof page.contents[id] == "function") {
				elem.innerHTML = page.contents[id](vars);
			} else {
				elem.innerHTML = page.contents[id];
			}

		}

		if (typeof page.callback == "function")
			page.callback(vars);

		triggerEvent(container, "lightly-page-load", {page: page});

		return div;
	}

	function navigate(page_id, vars) {
		//main function, rebuilds DOM

		div = newPageElement(page_id, vars);

		container.innerHTML = div.innerHTML;

		var page = pages[page_id];

		triggerEvent(container, "lightly-page-shown", {page: page});

	}

	/*
	 * Add an action to the actions object
	 */
	function addAction(action) {

		if( !action || typeof action.id != "string" )
			throw {
				name: "lightly-action-noid",
				message: "No id specified for new action"
			}

		if (action.id == "navigate" || action.id == "back")
			throw {
				name: "lightly-action-forbidden",
				message: "Cannot overwrite built-in actions"
			}

		var new_action = {
			id: action.id,
			callback: action.callback || function() {},
			history: action.history || true
		}

		actions[action.id] = new_action;

		triggerEvent(container, "lightly-action-added", {action: new_action});

	}

	/*
	 * Execute one of the assigned actions
	 */
	function executeAction(action_id) {

		if (typeof actions[action_id] == "undefined")
			throw {
				name: "lightly-action-nonexistant",
				message: "Action "+action_id+" does not exist"
			}

		var params = Array.prototype.slice.call(arguments,1);

		if (typeof actions[action_id].callback == "function")
			actions[action_id].callback.apply(null, params);

		var history_action = {
			action_id: action_id,
			params: params
		}

		if (actions[action_id].history)
			history.push(history_action);

		triggerEvent(container, "lightly-action-executed", {action: actions[action_id]});
	}

	/*
	 * Go back in the history
	 */
	function back() {

		if (history.length < 2)
			return;

		history.pop();

		// var i = history.length - 1;

		var action = history.pop();

		var params = action.params.slice(0);
		params.unshift(action.action_id);

		executeAction.apply(null, params);

		triggerEvent(container, "lightly-action-back", {action: action});

	}

	/*
	 * Utilities functions
	 */

	/*
	 * Check if elem is a valid DOM element
	 */
	function inDOM(elem) {
		do {
			if (elem == document.documentElement) {
				return true;
			}
		} while (elem = elem.parentNode);

		return false;
	}

	/*
	 * Trigger a custom event
	 */
	function triggerEvent(element, eventname, vars) {
		var event; // The custom event that will be created

		if (document.createEvent) {
			event = document.createEvent("HTMLEvents");
			event.initEvent(eventname, true, true);
		} else {
			event = document.createEventObject();
			event.eventType = eventname;
		}

		event.eventName = eventname;
		event.vars = vars;

		if (document.createEvent) {
			element.dispatchEvent(event);
		} else {
			element.fireEvent("on" + event.eventType, event);
		}
	}

	/*
	 * Expose public methods
	 */
	return {

		/*
		 * App name and general infos
		 */
		setAppName: function(new_name) {
			appname = new_name;
		},
		getAppName: function() {
			return appname;
		},
		setContainer: setContainer,

		/*
		 * Pages management
		 */
		addPage: addPage,
		getPages: function() {
			return pages;
		},
		navigate: navigate,
		newPageElement: newPageElement,

		/*
		 * Actions management
		 */
		addAction: addAction,
		getActions: function() {
			return actions;
		},
		executeAction: executeAction,
		do: executeAction,
		getHistory: function() {
			return history;
		},
	}

}<commit_msg>Fixed a bug when adding a new action<commit_after>/**
 * lightly.js
 * a lightweight js app platform
 *
 * Version: 0.6
 * Author: Riccardo Marton <marton.riccardo@gmail.com>
 *
 * License: Licensed under The MIT License. See LICENSE file
 */

var lightly = function() {

	/*
	 * Private properties
	 */
	var appname = "new App";
	var container = document.body;
	var pages = {};
	var history = [];
	var actions = {
		"navigate": {
			id: "navigate",
			callback: navigate,
			history: true
		},
		"back": {
			id: "back",
			callback: back,
			history: false
		}
	};

	/*
	 * Set a node as main container. lightly will not operate outside of the node
	 * provided
	 */
	function setContainer(node) {

		if (!inDOM(node))
			throw {
				name: "lightly-container-invalid",
				message: "Object provided is not a DOM element"
			}

		container = node;
	}

	/*
	 * Add a page to the pages object
	 */
	function addPage(page) {

		if( !page || typeof page.id != "string" ) {
			throw {
				name: "lightly-page-noid",
				message: "No id specified for new page"
			}
		}

		var new_page = {
			id: page.id,
			title: page.title || "New page",
			contents: page.contents || {},
			callback: page.callback || function() {}
		}

		pages[page.id] = new_page;

		triggerEvent(container, "lightly-page-added", {page: new_page});

	}

	/*
	 * Load and display a page
	 */
	function newPageElement(page_id, vars) {
		if (typeof pages[page_id] == "undefined")
			throw {
				name: "lightly-page-nonexistant",
				message: "Page "+page_id+" does not exist"
			}

		var page = pages[page_id];

		document.title = page.title;

		var div = document.createElement('div');
		div.innerHTML = container.innerHTML;

		for (id in page.contents) {

			var elem = div.getElementsByClassName(id)[0];
			if (elem == null)
				continue;

			if (typeof page.contents[id] == "function") {
				elem.innerHTML = page.contents[id](vars);
			} else {
				elem.innerHTML = page.contents[id];
			}

		}

		if (typeof page.callback == "function")
			page.callback(vars);

		triggerEvent(container, "lightly-page-load", {page: page});

		return div;
	}

	function navigate(page_id, vars) {
		//main function, rebuilds DOM

		div = newPageElement(page_id, vars);

		container.innerHTML = div.innerHTML;

		var page = pages[page_id];

		triggerEvent(container, "lightly-page-shown", {page: page});

	}

	/*
	 * Add an action to the actions object
	 */
	function addAction(action) {

		if( !action || typeof action.id != "string" )
			throw {
				name: "lightly-action-noid",
				message: "No id specified for new action"
			}

		if (action.id == "navigate" || action.id == "back")
			throw {
				name: "lightly-action-forbidden",
				message: "Cannot overwrite built-in actions"
			}

		var history = true;
		if (typeof action.history == 'boolean' )
			history = action.history;

		var new_action = {
			id: action.id,
			callback: action.callback || function() {},
			history: history
		}

		actions[action.id] = new_action;

		triggerEvent(container, "lightly-action-added", {action: new_action});

	}

	/*
	 * Execute one of the assigned actions
	 */
	function executeAction(action_id) {

		if (typeof actions[action_id] == "undefined")
			throw {
				name: "lightly-action-nonexistant",
				message: "Action "+action_id+" does not exist"
			}

		var params = Array.prototype.slice.call(arguments,1);

		if (typeof actions[action_id].callback == "function")
			actions[action_id].callback.apply(null, params);

		var history_action = {
			action_id: action_id,
			params: params
		}

		if (actions[action_id].history)
			history.push(history_action);

		triggerEvent(container, "lightly-action-executed", {action: actions[action_id]});
	}

	/*
	 * Go back in the history
	 */
	function back() {

		if (history.length < 2)
			return;

		history.pop();

		// var i = history.length - 1;

		var action = history.pop();

		var params = action.params.slice(0);
		params.unshift(action.action_id);

		executeAction.apply(null, params);

		triggerEvent(container, "lightly-action-back", {action: action});

	}

	/*
	 * Utilities functions
	 */

	/*
	 * Check if elem is a valid DOM element
	 */
	function inDOM(elem) {
		do {
			if (elem == document.documentElement) {
				return true;
			}
		} while (elem = elem.parentNode);

		return false;
	}

	/*
	 * Trigger a custom event
	 */
	function triggerEvent(element, eventname, vars) {
		var event; // The custom event that will be created

		if (document.createEvent) {
			event = document.createEvent("HTMLEvents");
			event.initEvent(eventname, true, true);
		} else {
			event = document.createEventObject();
			event.eventType = eventname;
		}

		event.eventName = eventname;
		event.vars = vars;

		if (document.createEvent) {
			element.dispatchEvent(event);
		} else {
			element.fireEvent("on" + event.eventType, event);
		}
	}

	/*
	 * Expose public methods
	 */
	return {

		/*
		 * App name and general infos
		 */
		setAppName: function(new_name) {
			appname = new_name;
		},
		getAppName: function() {
			return appname;
		},
		setContainer: setContainer,

		/*
		 * Pages management
		 */
		addPage: addPage,
		getPages: function() {
			return pages;
		},
		navigate: navigate,
		newPageElement: newPageElement,

		/*
		 * Actions management
		 */
		addAction: addAction,
		getActions: function() {
			return actions;
		},
		executeAction: executeAction,
		do: executeAction,
		getHistory: function() {
			return history;
		},
	}

}<|endoftext|>


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

  var assert = require('assert');
  var acl = require('../');
  var helper = require('../lib/helpers');

  describe('Express Access Control List Module', function() {
    var res, rules, data;

    /**
     * [Load config file]
     * @param  {[json]} )
     * this tests check whether the modules loads
     * the config file, and gives all the neccesary warnings when neccesary
     */

    describe('Loading the config file (config.json', function() {

      it('should load config jsonfile when path is specifyed', function() {

        rules = acl.config({
          filename: 'config/config.json',
          path: './tests',
          encoding: 'base64'
        });

        assert(Array.isArray(rules), true);
        assert(rules.length, 1);

      });

      it('Should load the config.json from the root folder', function() {
        rules = acl.config();

        assert(Array.isArray(rules), true);
        assert(rules.length, 1);

      });

      it('Log error when no policy is defined', function() {

        res = '\u001b[33mPolicy not set, All traffic will be denied\u001b[39m';

        rules = acl.config({
          path: './tests/config',
          filename: 'empty-policy.json'
        });

        assert(typeof rules, 'string');
        assert.deepEqual(rules, res);

      });

      it('should add the rules to the "opt" object ', function() {
        acl.config();

        data = acl.utils.allRules();

        assert(Array.isArray(data), true);
        assert(data.length, 1);

      });
    });

    describe('No BaseUrl', function() {

      it('Should be able to locate the location of the resource', function() {

        var url = '/users/45gg4hht6';

        var next = function() {
          return true;
        };

        var resource = helper.resource(next, url);
        assert.deepEqual(resource, 'users');

      });

    });

    describe('With  BaseUrl', function() {
      it('Should be able to locate the location of the resource', function() {

        var url = 'developer/v1/users/45gg4hht6';

        var next = function() {
          return true;
        };

        var config = {
          baseUrl: 'developer/v1/'
        };

        var resource = helper.resource(next, url, config.baseUrl);
        assert.deepEqual(resource, 'users');

      });
    });

  });
})();
<commit_msg>Fix failing test<commit_after>(function() {
  'use strict';

  var assert = require('assert');
  var acl = require('../');
  var helper = require('../lib/helpers');

  describe('Express Access Control List Module', function() {
    var res, rules, data;

    /**
     * [Load config file]
     * @param  {[json]} )
     * this tests check whether the modules loads
     * the config file, and gives all the neccesary warnings when neccesary
     */

    describe('Loading the config file (config.json', function() {

      it('should load config jsonfile when path is specifyed', function() {

        rules = acl.config({
          filename: 'config/config.json',
          path: './tests',
          encoding: 'base64'
        });

        assert(Array.isArray(rules), true);
        assert(rules.length, 1);

      });

      it('Should load the config.json from the root folder', function() {
        rules = acl.config();

        assert(Array.isArray(rules), true);
        assert(rules.length, 1);

      });

      it('Log error when no policy is defined', function() {

        res = '\u001b[33mPolicy not set, All traffic will be denied\u001b[39m';

        rules = acl.config({
          path: './tests/config',
          filename: 'empty-policy.json'
        });

        assert(typeof rules, 'string');
        assert.deepEqual(rules, res);

      });
    });

    describe('No BaseUrl', function() {

      it('Should be able to locate the location of the resource', function() {

        var url = '/users/45gg4hht6';

        var next = function() {
          return true;
        };

        var resource = helper.resource(next, url);
        assert.deepEqual(resource, 'users');

      });

    });

    describe('With  BaseUrl', function() {
      it('Should be able to locate the location of the resource', function() {

        var url = 'developer/v1/users/45gg4hht6';

        var next = function() {
          return true;
        };

        var config = {
          baseUrl: 'developer/v1/'
        };

        var resource = helper.resource(next, url, config.baseUrl);
        assert.deepEqual(resource, 'users');

      });
    });

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


<commit_before>var suite = require('suite.js');
var partial = require('funkit/functional/partial');
var g = require('generators.js');
var f = require('funkit/operators');

suite(f.equals, suite.generate(1000,
    [g.structure],
    function(op, a) {
        return op(a, a);
    }
));

suite(partial(f.equals, [1, 2, 3]), [
    [[1, 2, 3]], true,
    [[1, 2, 3, 5]], false
]);

suite(partial(f.equals, [{name: 'rofl'}, {name: 'lol'}]), [
    [[{name: 'rofl'}, {name: 'lol'}]], true,
    [[{name: 'rofl'}]], false,
    [[{}]], false,
    [[]], false
]);
<commit_msg>Add extra check<commit_after>var suite = require('suite.js');
var partial = require('funkit/functional/partial');
var g = require('generators.js');
var f = require('funkit/operators');

suite(f.equals, suite.generate(1000,
    [g.structure],
    function(op, a) {
        return op(a, a);
    }
));

suite(partial(f.equals, []), [
    [[]], true,
    [[3]], false
]);

suite(partial(f.equals, [1, 2, 3]), [
    [[1, 2, 3]], true,
    [[1, 2, 3, 5]], false
]);

suite(partial(f.equals, [{name: 'rofl'}, {name: 'lol'}]), [
    [[{name: 'rofl'}, {name: 'lol'}]], true,
    [[{name: 'rofl'}]], false,
    [[{}]], false,
    [[]], false
]);
<|endoftext|>


<commit_before>if (typeof user === 'undefined') user = "highfidelity/";
if (typeof repository === 'undefined') repository = "hifi_tests/";
if (typeof branch === 'undefined') branch = "master/";

var currentTestName = "";
var currentSteps = [];
var currentStepIndex = 0;

var testCases = [];
var currentlyExecutingTest = 0;

var testMode = "manual";      // can be "auto"
var isRecursive = false;
var runningRecursive = false;

var snapshotPrefix = "";
var snapshotIndex = 0;

var advanceKey = "n";
var pathSeparator = ".";

var previousCameraMode;

var downloadInProgress = false;
var loadingContentIsStillDisplayed = false;

// This will be set when each test case begins
var originFrame;

// origin is located 1m below avatar centre
// avatar eyes are set to 1.76 cm above the origin
const ORIGIN_FRAME_OFFSET = { x: 0.0, y: -1.0, z: 0.0 };
const VALIDATION_CAMERA_OFFSET = { x: 0.0, y: 1.76, z: 0.0 };

var spectatorCameraConfig;

TestCase = function (name, path, func, usePrimaryCamera) {
    this.name = name;
    this.path = path;
    this.func = func;
    this.usePrimaryCamera = usePrimaryCamera;
}

var currentTestCase = null;
var currentRecursiveTestCompleted = false;

//returns n as a string, padded to length characters with the character ch
function pad(n, length, ch) {
    ch = ch || '0';  // default is '0'
    n += '';         // convert n to string

    // returns n as is, if it is too long
    return (n.length >= length) ? n : new Array(length - n.length + 1).join(ch) + n;
}

function onDownloadInfoChanged(info) {
    // After download is complete, the "LOADING CONTENT..." message is still displayed for a short time
    if (info.downloading.length == 0 && info.pending == 0) {
        downloadInProgress = false;
        loadingContentIsStillDisplayed = true;
    }
}

var runOneStep = function (stepFunctor, stepIndex) {
    print("Running step " + (stepIndex + 1) + "/" + (currentSteps.length) +": " + stepFunctor.name);

    if (isManualMode()) {
        Window.displayAnnouncement("Running step " + (stepIndex + 1) + "/" + (currentSteps.length) +": " + stepFunctor.name);
    }

    if (stepFunctor.func !== undefined) {
        stepFunctor.func();
    }

    // Not quite sure this is the definitive solution here because of the snapshot bug latency issue.
    // but this seems to work ok if the snapshot is a separate step
    if ((stepFunctor.snap !== undefined) && stepFunctor.snap) {
        print("Taking snapshot for step " + (stepIndex + 1));

        // Image numbers are padded to 5 digits
        // Changing this number requires changing the auto-tester C++ code!
        var NUM_DIGITS = 5;
        var currentSnapshotName = snapshotPrefix + pad(snapshotIndex, NUM_DIGITS, '0');;

        currentTestCase.usePrimaryCamera
            ? Window.takeSnapshot(isManualMode(), false, 0.0, currentSnapshotName)
            : Window.takeSecondaryCameraSnapshot(isManualMode(), currentSnapshotName);

        ++snapshotIndex;
    }
}

var runNextStep = function () {
    // Run next step and increment only if there is one more
    if (currentStepIndex < currentSteps.length) {
        runOneStep(currentSteps[currentStepIndex], currentStepIndex);
        currentStepIndex++;
    }

    // Return true to go on or false if done
    return (currentStepIndex < currentSteps.length);
}

var autoTimeStep = 2000;

var onRunAutoNext = function() {
    var timeStep = autoTimeStep;

    // If not downloading then run the next step...
    if (!downloadInProgress  && !loadingContentIsStillDisplayed) {
        if (!runNextStep()) {
            tearDownTest();
            return;
        }
    } else if (!downloadInProgress) {
        // This assumes the message is displayed for not more than 4 seconds
        print("Waiting for 'LOADING CONTENT...' message to be removed");
        timeStep = 4000;
        loadingContentIsStillDisplayed = false;
    } else {
        print("Waiting for download to complete");
    }

    // and call itself after next timer
    Script.setTimeout(
        onRunAutoNext,
        timeStep
    );
}

var onKeyPressEventNextStep = function (event) {
    if (String.fromCharCode(event.key) == advanceKey.toUpperCase()) {
        if (!runNextStep()) {
            tearDownTest();
        }
    }
}

var onRunManual = function() {
    Window.displayAnnouncement(
        "Ready to run test " + currentTestName + "\n" +
        currentSteps.length + " steps\nPress " + "'" + advanceKey + "'" + " for next steps");

    Controller.keyPressEvent.connect(onKeyPressEventNextStep);
}

function isManualMode() {
    return (testMode === "manual");
}

var onRunAuto = function() {
    // run the next step after next timer
    Script.setTimeout(
        onRunAutoNext,
        autoTimeStep
    );
}

// Add Steps to the test case
var doAddStep = function (name, stepFunction, snapshot) {
    currentSteps.push({"index": currentSteps.length, "name": name, "func": stepFunction, "snap": snapshot })
    print("PUSHING STEP" + currentSteps.length);
}

runOneTestCase = function(testCase, testType) {
    setUpTest(testCase);
    testCase.func(testType);
}

setUpTest = function(testCase) {
    // Setup origin
    originFrame = Vec3.sum(MyAvatar.position, ORIGIN_FRAME_OFFSET);

    currentStepIndex = 0;
    currentTestName = testCase.name;

    // resolvePath(".") returns a string that looks like "file:/" + <current folder>
    // We need the current folder
    var path = testCase.path.substring(testCase.path.indexOf(":") + 4);
    var pathParts = path.split("/");

    // Snapshots are saved in the user-selected folder
    // For a test running from D:/GitHub/hifi-tests/tests/content/entity/zone/create/tests.js
    // the tests are named tests.content.entity.zone.create.00000.jpg and so on
    // (assuming pathSeparator is ".")
    // Date and time are not used as part of the name, to keep the path lengths to a minimum
    // (the Windows API limit is 260 characters).
    //
    // Find location of "tests"
    var testsIndex;
    for (testsIndex = pathParts.length - 1; testsIndex > 0; --testsIndex) {
        if (pathParts[testsIndex] === "tests") {
            break;
        }
    }

    snapshotPrefix = pathParts[testsIndex];
    for (var i = testsIndex + 1; i < pathParts.length; ++i) {
        snapshotPrefix += pathSeparator + pathParts[i];
    }

    snapshotIndex = 0;

    // Setup validation camera
    var p0 = Vec3.sum(VALIDATION_CAMERA_OFFSET, Vec3.sum(MyAvatar.position, ORIGIN_FRAME_OFFSET));
    var q0 = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);

    if (testCase.usePrimaryCamera) {
    // Set the camera mode to independent
    if (testCase.usePrimaryCamera) {
        previousCameraMode = Camera.mode;
        Camera.mode = "independent";
        Camera.setOrientation(q0);
        Camera.setPosition(p0);

        // The avatar is also pointed down the Z axis, so the test can be seen on-screen
        MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);
        MyAvatar.headYaw =   0.0;
        MyAvatar.headPitch = 0.0;
        MyAvatar.headRoll =  0.0;
    } else {
        spectatorCameraConfig = Render.getConfig("SecondaryCamera");
        spectatorCameraConfig.enableSecondaryCameraRenderConfigs(true);
        spectatorCameraConfig.resetSizeSpectatorCamera(1920, 1080);
        spectatorCameraConfig.vFoV = 45;
        Render.getConfig("SecondaryCameraJob.ToneMapping").curve = 0;
        Render.getConfig("SecondaryCameraJob.DrawHighlight").enabled = false;

        spectatorCameraConfig.orientation = q0;
        spectatorCameraConfig.position = p0;
    }

    // Hide the avatar
    MyAvatar.setEnableMeshVisible(false);

    if (typeof Test !== 'undefined') {
        // In command line mode, maximize window size
        // (so that primary camera snapshots will have the correct size)
        Test.showMaximized();
    }

    if (!isManualMode()) {
        // Also, remove 2D overlays and mouse from the window, so that they won't appear in snapshots
        Menu.setIsOptionChecked("Show Overlays", false);
        Reticle.visible = false;
        Reticle.allowMouseCapture = false;
    }

    // Set callback for changes in download status.  This is used so we don't advance steps when data is downloading
    AccountServices.downloadInfoChanged.connect(onDownloadInfoChanged);
    AccountServices.updateDownloadInfo();
}

tearDownTest = function() {
    // Clear the test case steps
    currentSteps = [];

   // Reset camera mode
    Camera.mode = previousCameraMode;

    if (isManualMode()) {
        // Disconnect key event
        Controller.keyPressEvent.disconnect(onKeyPressEventNextStep);
        Window.displayAnnouncement("Test " + currentTestName + " have been completed");
    }

    if (!isManualMode()) {
        //Restore 2D overlays and mouse from the window
        Menu.setIsOptionChecked("Show Overlays", true);
        Reticle.visible = true;
        Reticle.allowMouseCapture = true;
    }

    // Show the avatar
    MyAvatar.setEnableMeshVisible(true);

    if (isRecursive) {
        currentRecursiveTestCompleted = true;
    } else {
        // Just stop the script
        Script.stop();
    }

    // Disconnect callback
    AccountServices.downloadInfoChanged.disconnect(onDownloadInfoChanged);
}

validationCamera_setTranslation = function(position) {
    // The camera position is the sum of the origin frame, position (relative to that frame) and the eye (i.e. camera) offset
    var cameraPosition = Vec3.sum(originFrame, Vec3.sum(position, VALIDATION_CAMERA_OFFSET));

    if (currentTestCase.usePrimaryCamera) {
        Camera.setPosition(cameraPosition);
    } else {
        spectatorCameraConfig.position = cameraPosition;
    }
}

validationCamera_translate = function (offset) {
    if (currentTestCase.usePrimaryCamera) {
        Camera.setPosition(Vec3.sum(Camera.getPosition(), offset));
    } else {
        spectatorCameraConfig.position = Vec3.sum(spectatorCameraConfig.position, offset);
    }
}

validationCamera_setRotation = function (rotation) {
    var orientation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
    if (currentTestCase.usePrimaryCamera) {
        Camera.setOrientation(orientation);
    } else {
        spectatorCameraConfig.orientation = orientation;
    }
}

// The following are exported methods, accessible to test scripts

// Perform is the main method of a test
//      testName - name of the test
//      testPath - path the test is executing in
//      testMain - a function that creates the test
//
// The method creates a test case in currentTestCase.
// If the test mode is manual or auto then its execution is started
module.exports.perform = function (testName, testPath, validationCamera, testMain) {
    var usePrimaryCamera = (validationCamera === "primary");
    currentTestCase = new TestCase(testName, testPath, testMain, usePrimaryCamera);

    // Manual and auto tests are run immediately, recursive tests are stored in a queue
    if (isRecursive) {
        print("Not running yet - in recursive mode");
        testCases.push(currentTestCase);
    } else if (isManualMode()) {
        print("Begin manual test:" + testName);
        runOneTestCase(currentTestCase, "manual");
    } else { // testMode === "auto"
        print("Begin auto test:" + testName);
        runOneTestCase(currentTestCase, "auto");
    }
}

// Add steps to the test case, take snapshot if 3rd parameter is true
module.exports.addStep = function (name, stepFunction) {
    doAddStep(name, stepFunction, false);
}

// Add steps to the test case, take snapshot
module.exports.addStepSnapshot = function (name, stepFunction) {
    doAddStep(name, stepFunction, true);
}

// The default mode is manual
// The default time between test steps may be modified through these methods
module.exports.enableAuto = function (timeStep) {
    testMode = "auto";

    if (timeStep) {
        autoTimeStep = timeStep;
    }

    print("TEST MODE AUTO SELECTED");
}

module.exports.enableRecursive = function (timeStep) {
    isRecursive = true;
    if (timeStep) {
        autoTimeStep = timeStep;
    }

    print("TEST MODE RECURSIVE SELECTED");
}

// Steps is an array of functions; each function being a test step
module.exports.runTest = function (testType) {
    // In recursive mode, this call is ignored during script load
    if (isRecursive && !runningRecursive) {
        return;
    }

    if (testType  === "auto") {
        onRunAuto();
    } else { // testType === "manual"
        onRunManual();
    }
}

module.exports.runRecursive = function () {
    print("Starting recursive tests");
    runningRecursive = true;

    currentRecursiveTestCompleted = true;
    Script.setInterval(
        function () {
            if (currentRecursiveTestCompleted) {
                currentRecursiveTestCompleted = false;
                if (testCases.length > 0) {
                    currentTestCase = testCases.pop();
                    runOneTestCase(currentTestCase, testMode);
                } else {
                    print("Recursive tests complete");
                    Script.stop();
                }
            }
        },
        1000
    );
}<commit_msg>Set camera to independent before moving.<commit_after>if (typeof user === 'undefined') user = "highfidelity/";
if (typeof repository === 'undefined') repository = "hifi_tests/";
if (typeof branch === 'undefined') branch = "master/";

var currentTestName = "";
var currentSteps = [];
var currentStepIndex = 0;

var testCases = [];
var currentlyExecutingTest = 0;

var testMode = "manual";      // can be "auto"
var isRecursive = false;
var runningRecursive = false;

var snapshotPrefix = "";
var snapshotIndex = 0;

var advanceKey = "n";
var pathSeparator = ".";

var previousCameraMode;

var downloadInProgress = false;
var loadingContentIsStillDisplayed = false;

// This will be set when each test case begins
var originFrame;

// origin is located 1m below avatar centre
// avatar eyes are set to 1.76 cm above the origin
const ORIGIN_FRAME_OFFSET = { x: 0.0, y: -1.0, z: 0.0 };
const VALIDATION_CAMERA_OFFSET = { x: 0.0, y: 1.76, z: 0.0 };

var spectatorCameraConfig;

TestCase = function (name, path, func, usePrimaryCamera) {
    this.name = name;
    this.path = path;
    this.func = func;
    this.usePrimaryCamera = usePrimaryCamera;
}

var currentTestCase = null;
var currentRecursiveTestCompleted = false;

//returns n as a string, padded to length characters with the character ch
function pad(n, length, ch) {
    ch = ch || '0';  // default is '0'
    n += '';         // convert n to string

    // returns n as is, if it is too long
    return (n.length >= length) ? n : new Array(length - n.length + 1).join(ch) + n;
}

function onDownloadInfoChanged(info) {
    // After download is complete, the "LOADING CONTENT..." message is still displayed for a short time
    if (info.downloading.length == 0 && info.pending == 0) {
        downloadInProgress = false;
        loadingContentIsStillDisplayed = true;
    }
}

var runOneStep = function (stepFunctor, stepIndex) {
    print("Running step " + (stepIndex + 1) + "/" + (currentSteps.length) +": " + stepFunctor.name);

    if (isManualMode()) {
        Window.displayAnnouncement("Running step " + (stepIndex + 1) + "/" + (currentSteps.length) +": " + stepFunctor.name);
    }

    if (stepFunctor.func !== undefined) {
        stepFunctor.func();
    }

    // Not quite sure this is the definitive solution here because of the snapshot bug latency issue.
    // but this seems to work ok if the snapshot is a separate step
    if ((stepFunctor.snap !== undefined) && stepFunctor.snap) {
        print("Taking snapshot for step " + (stepIndex + 1));

        // Image numbers are padded to 5 digits
        // Changing this number requires changing the auto-tester C++ code!
        var NUM_DIGITS = 5;
        var currentSnapshotName = snapshotPrefix + pad(snapshotIndex, NUM_DIGITS, '0');;

        currentTestCase.usePrimaryCamera
            ? Window.takeSnapshot(isManualMode(), false, 0.0, currentSnapshotName)
            : Window.takeSecondaryCameraSnapshot(isManualMode(), currentSnapshotName);

        ++snapshotIndex;
    }
}

var runNextStep = function () {
    // Run next step and increment only if there is one more
    if (currentStepIndex < currentSteps.length) {
        runOneStep(currentSteps[currentStepIndex], currentStepIndex);
        currentStepIndex++;
    }

    // Return true to go on or false if done
    return (currentStepIndex < currentSteps.length);
}

var autoTimeStep = 2000;

var onRunAutoNext = function() {
    var timeStep = autoTimeStep;

    // If not downloading then run the next step...
    if (!downloadInProgress  && !loadingContentIsStillDisplayed) {
        if (!runNextStep()) {
            tearDownTest();
            return;
        }
    } else if (!downloadInProgress) {
        // This assumes the message is displayed for not more than 4 seconds
        print("Waiting for 'LOADING CONTENT...' message to be removed");
        timeStep = 4000;
        loadingContentIsStillDisplayed = false;
    } else {
        print("Waiting for download to complete");
    }

    // and call itself after next timer
    Script.setTimeout(
        onRunAutoNext,
        timeStep
    );
}

var onKeyPressEventNextStep = function (event) {
    if (String.fromCharCode(event.key) == advanceKey.toUpperCase()) {
        if (!runNextStep()) {
            tearDownTest();
        }
    }
}

var onRunManual = function() {
    Window.displayAnnouncement(
        "Ready to run test " + currentTestName + "\n" +
        currentSteps.length + " steps\nPress " + "'" + advanceKey + "'" + " for next steps");

    Controller.keyPressEvent.connect(onKeyPressEventNextStep);
}

function isManualMode() {
    return (testMode === "manual");
}

var onRunAuto = function() {
    // run the next step after next timer
    Script.setTimeout(
        onRunAutoNext,
        autoTimeStep
    );
}

// Add Steps to the test case
var doAddStep = function (name, stepFunction, snapshot) {
    currentSteps.push({"index": currentSteps.length, "name": name, "func": stepFunction, "snap": snapshot })
    print("PUSHING STEP" + currentSteps.length);
}

runOneTestCase = function(testCase, testType) {
    setUpTest(testCase);
    testCase.func(testType);
}

setUpTest = function(testCase) {
    // Setup origin
    originFrame = Vec3.sum(MyAvatar.position, ORIGIN_FRAME_OFFSET);

    currentStepIndex = 0;
    currentTestName = testCase.name;

    // resolvePath(".") returns a string that looks like "file:/" + <current folder>
    // We need the current folder
    var path = testCase.path.substring(testCase.path.indexOf(":") + 4);
    var pathParts = path.split("/");

    // Snapshots are saved in the user-selected folder
    // For a test running from D:/GitHub/hifi-tests/tests/content/entity/zone/create/tests.js
    // the tests are named tests.content.entity.zone.create.00000.jpg and so on
    // (assuming pathSeparator is ".")
    // Date and time are not used as part of the name, to keep the path lengths to a minimum
    // (the Windows API limit is 260 characters).
    //
    // Find location of "tests"
    var testsIndex;
    for (testsIndex = pathParts.length - 1; testsIndex > 0; --testsIndex) {
        if (pathParts[testsIndex] === "tests") {
            break;
        }
    }

    snapshotPrefix = pathParts[testsIndex];
    for (var i = testsIndex + 1; i < pathParts.length; ++i) {
        snapshotPrefix += pathSeparator + pathParts[i];
    }

    snapshotIndex = 0;

    // Setup validation camera
    var p0 = Vec3.sum(VALIDATION_CAMERA_OFFSET, Vec3.sum(MyAvatar.position, ORIGIN_FRAME_OFFSET));
    var q0 = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);

    // Set the camera mode to independent
    if (testCase.usePrimaryCamera) {
        previousCameraMode = Camera.mode;
        Camera.mode = "independent";
        Camera.setOrientation(q0);
        Camera.setPosition(p0);

        // The avatar is also pointed down the Z axis, so the test can be seen on-screen
        MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);
        MyAvatar.headYaw =   0.0;
        MyAvatar.headPitch = 0.0;
        MyAvatar.headRoll =  0.0;
    } else {
        spectatorCameraConfig = Render.getConfig("SecondaryCamera");
        spectatorCameraConfig.enableSecondaryCameraRenderConfigs(true);
        spectatorCameraConfig.resetSizeSpectatorCamera(1920, 1080);
        spectatorCameraConfig.vFoV = 45;
        Render.getConfig("SecondaryCameraJob.ToneMapping").curve = 0;
        Render.getConfig("SecondaryCameraJob.DrawHighlight").enabled = false;

        spectatorCameraConfig.orientation = q0;
        spectatorCameraConfig.position = p0;
    }

    // Hide the avatar
    MyAvatar.setEnableMeshVisible(false);

    if (typeof Test !== 'undefined') {
        // In command line mode, maximize window size
        // (so that primary camera snapshots will have the correct size)
        Test.showMaximized();
    }

    if (!isManualMode()) {
        // Also, remove 2D overlays and mouse from the window, so that they won't appear in snapshots
        Menu.setIsOptionChecked("Show Overlays", false);
        Reticle.visible = false;
        Reticle.allowMouseCapture = false;
    }

    // Set callback for changes in download status.  This is used so we don't advance steps when data is downloading
    AccountServices.downloadInfoChanged.connect(onDownloadInfoChanged);
    AccountServices.updateDownloadInfo();
}

tearDownTest = function() {
    // Clear the test case steps
    currentSteps = [];

   // Reset camera mode
    Camera.mode = previousCameraMode;

    if (isManualMode()) {
        // Disconnect key event
        Controller.keyPressEvent.disconnect(onKeyPressEventNextStep);
        Window.displayAnnouncement("Test " + currentTestName + " have been completed");
    }

    if (!isManualMode()) {
        //Restore 2D overlays and mouse from the window
        Menu.setIsOptionChecked("Show Overlays", true);
        Reticle.visible = true;
        Reticle.allowMouseCapture = true;
    }

    // Show the avatar
    MyAvatar.setEnableMeshVisible(true);

    if (isRecursive) {
        currentRecursiveTestCompleted = true;
    } else {
        // Just stop the script
        Script.stop();
    }

    // Disconnect callback
    AccountServices.downloadInfoChanged.disconnect(onDownloadInfoChanged);
}

validationCamera_setTranslation = function(position) {
    // The camera position is the sum of the origin frame, position (relative to that frame) and the eye (i.e. camera) offset
    var cameraPosition = Vec3.sum(originFrame, Vec3.sum(position, VALIDATION_CAMERA_OFFSET));

    if (currentTestCase.usePrimaryCamera) {
        Camera.setPosition(cameraPosition);
    } else {
        spectatorCameraConfig.position = cameraPosition;
    }
}

validationCamera_translate = function (offset) {
    if (currentTestCase.usePrimaryCamera) {
        Camera.setPosition(Vec3.sum(Camera.getPosition(), offset));
    } else {
        spectatorCameraConfig.position = Vec3.sum(spectatorCameraConfig.position, offset);
    }
}

validationCamera_setRotation = function (rotation) {
    var orientation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
    if (currentTestCase.usePrimaryCamera) {
        Camera.setOrientation(orientation);
    } else {
        spectatorCameraConfig.orientation = orientation;
    }
}

// The following are exported methods, accessible to test scripts

// Perform is the main method of a test
//      testName - name of the test
//      testPath - path the test is executing in
//      testMain - a function that creates the test
//
// The method creates a test case in currentTestCase.
// If the test mode is manual or auto then its execution is started
module.exports.perform = function (testName, testPath, validationCamera, testMain) {
    var usePrimaryCamera = (validationCamera === "primary");
    currentTestCase = new TestCase(testName, testPath, testMain, usePrimaryCamera);

    // Manual and auto tests are run immediately, recursive tests are stored in a queue
    if (isRecursive) {
        print("Not running yet - in recursive mode");
        testCases.push(currentTestCase);
    } else if (isManualMode()) {
        print("Begin manual test:" + testName);
        runOneTestCase(currentTestCase, "manual");
    } else { // testMode === "auto"
        print("Begin auto test:" + testName);
        runOneTestCase(currentTestCase, "auto");
    }
}

// Add steps to the test case, take snapshot if 3rd parameter is true
module.exports.addStep = function (name, stepFunction) {
    doAddStep(name, stepFunction, false);
}

// Add steps to the test case, take snapshot
module.exports.addStepSnapshot = function (name, stepFunction) {
    doAddStep(name, stepFunction, true);
}

// The default mode is manual
// The default time between test steps may be modified through these methods
module.exports.enableAuto = function (timeStep) {
    testMode = "auto";

    if (timeStep) {
        autoTimeStep = timeStep;
    }

    print("TEST MODE AUTO SELECTED");
}

module.exports.enableRecursive = function (timeStep) {
    isRecursive = true;
    if (timeStep) {
        autoTimeStep = timeStep;
    }

    print("TEST MODE RECURSIVE SELECTED");
}

// Steps is an array of functions; each function being a test step
module.exports.runTest = function (testType) {
    // In recursive mode, this call is ignored during script load
    if (isRecursive && !runningRecursive) {
        return;
    }

    if (testType  === "auto") {
        onRunAuto();
    } else { // testType === "manual"
        onRunManual();
    }
}

module.exports.runRecursive = function () {
    print("Starting recursive tests");
    runningRecursive = true;

    currentRecursiveTestCompleted = true;
    Script.setInterval(
        function () {
            if (currentRecursiveTestCompleted) {
                currentRecursiveTestCompleted = false;
                if (testCases.length > 0) {
                    currentTestCase = testCases.pop();
                    runOneTestCase(currentTestCase, testMode);
                } else {
                    print("Recursive tests complete");
                    Script.stop();
                }
            }
        },
        1000
    );
}<|endoftext|>


<commit_before><commit_msg>Moved setup to the beginning (time-wise) of each test case.<commit_after><|endoftext|>


<commit_before><commit_msg>Use PNG Start in Desktop mode.<commit_after><|endoftext|>