<commit_before>import debugModule from "debug";
const debug = debugModule("debugger:evm:reducers");

import { combineReducers } from "redux";

import * as actions from "./actions";
import { keccak256, extractPrimarySource } from "lib/helpers";
import * as DecodeUtils from "@truffle/decode-utils";

import BN from "bn.js";

const DEFAULT_CONTEXTS = {
  byContext: {}
};

function contexts(state = DEFAULT_CONTEXTS, action) {
  switch (action.type) {
    /*
     * Adding a new context
     */
    case actions.ADD_CONTEXT:
      const {
        contractName,
        binary,
        sourceMap,
        compiler,
        abi,
        contractId,
        contractKind,
        isConstructor
      } = action;
      debug("action %O", action);
      //NOTE: we take hash as *string*, not as bytes, because the binary may
      //contain link references!
      const context = keccak256({ type: "string", value: binary });
      let primarySource;
      if (sourceMap !== undefined) {
        primarySource = extractPrimarySource(sourceMap);
      }
      //otherwise leave it undefined

      return {
        ...state,
        byContext: {
          ...state.byContext,
          [context]: {
            contractName,
            context,
            binary,
            sourceMap,
            primarySource,
            compiler,
            abi,
            contractId,
            contractKind,
            isConstructor
          }
        }
      };

    case actions.NORMALIZE_CONTEXTS:
      return {
        byContext: DecodeUtils.Contexts.normalizeContexts(state.byContext)
      };

    /*
     * Default case
     */
    default:
      return state;
  }
}

const info = combineReducers({
  contexts
});

const DEFAULT_TX = {
  gasprice: new BN(0),
  origin: DecodeUtils.EVM.ZERO_ADDRESS
};

function tx(state = DEFAULT_TX, action) {
  switch (action.type) {
    case actions.SAVE_GLOBALS:
      let { gasprice, origin } = action;
      return { gasprice, origin };
    case actions.UNLOAD_TRANSACTION:
      return DEFAULT_TX;
    default:
      return state;
  }
}

const DEFAULT_BLOCK = {
  coinbase: DecodeUtils.EVM.ZERO_ADDRESS,
  difficulty: new BN(0),
  gaslimit: new BN(0),
  number: new BN(0),
  timestamp: new BN(0)
};

function block(state = DEFAULT_BLOCK, action) {
  switch (action.type) {
    case actions.SAVE_GLOBALS:
      return action.block;
    case actions.UNLOAD_TRANSACTION:
      return DEFAULT_BLOCK;
    default:
      return state;
  }
}

const globals = combineReducers({
  tx,
  block
});

function status(state = null, action) {
  switch (action.type) {
    case actions.SAVE_STATUS:
      return action.status;
    case actions.UNLOAD_TRANSACTION:
      return null;
    default:
      return state;
  }
}

function initialCall(state = null, action) {
  switch (action.type) {
    case actions.CALL:
    case actions.CREATE:
      //we only want to save the initial call, so return
      //the current state if it's not null
      if (state !== null) {
        return state;
      } else {
        //we'll just store the action itself in the state
        return action;
      }
    case actions.UNLOAD_TRANSACTION:
      return null;
    default:
      return state;
  }
}

const transaction = combineReducers({
  globals,
  status,
  initialCall
});

function callstack(state = [], action) {
  switch (action.type) {
    case actions.CALL: {
      const { address, data, storageAddress, sender, value } = action;
      return state.concat([{ address, data, storageAddress, sender, value }]);
    }

    case actions.CREATE: {
      const { binary, storageAddress, sender, value } = action;
      return state.concat(
        [{ binary, data: "0x", storageAddress, sender, value }]
        //the empty data field is to make msg.data and msg.sig come out right
      );
    }

    case actions.RETURN_CALL:
    case actions.RETURN_CREATE:
    case actions.FAIL:
      //pop the stack... unless (HACK) that would leave it empty (this will
      //only happen at the end when we want to keep the last one around)
      return state.length > 1 ? state.slice(0, -1) : state;

    case actions.RESET:
    case actions.UNLOAD_TRANSACTION:
      return [];

    default:
      return state;
  }
}

const DEFAULT_CODEX = [
  {
    accounts: {}
    //will be more here in the future!
  }
];

function codex(state = DEFAULT_CODEX, action) {
  let newState, topCodex;

  const updateFrameStorage = (frame, address, slot, value) => ({
    ...frame,
    accounts: {
      ...frame.accounts,
      [address]: {
        ...frame.accounts[address],
        storage: {
          ...frame.accounts[address].storage,
          [slot]: value
        }
      }
    }
  });

  const updateFrameCode = (frame, address, code, context) => {
    let existingPage = frame.accounts[address] || { storage: {} };
    return {
      ...frame,
      accounts: {
        ...frame.accounts,
        [address]: {
          ...existingPage,
          code: code,
          context: context
        }
      }
    };
  };

  //later: will add "force" parameter
  const safePop = array => (array.length > 2 ? array.slice(0, -1) : array);

  //later: will add "force" parameter
  const safeSave = array =>
    array.length > 2
      ? array.slice(0, -2).concat([array[array.length - 1]])
      : array;

  switch (action.type) {
    case actions.CALL:
      debug("call action");
      debug("codex: %O", state);
      //on a call, we can just make a new stackframe by cloning the top
      //stackframe; there should already be an account for the address we're
      //calling into, so we don't need to make one
      return [...state, state[state.length - 1]];

    case actions.CREATE:
      //on a create, make a new stackframe, then add a new pages to the
      //codex if necessary; don't add a zero page though (or pages that already
      //exist)

      //first, add a new stackframe by cloning the top one
      newState = [...state, state[state.length - 1]];
      topCodex = newState[newState.length - 1];
      //now, do we need to add a new address to this stackframe?
      if (
        topCodex.accounts[action.storageAddress] !== undefined ||
        action.storageAddress === DecodeUtils.EVM.ZERO_ADDRESS
      ) {
        //if we don't
        return newState;
      }
      //if we do
      newState[newState.length - 1] = {
        ...topCodex,
        accounts: {
          ...topCodex.accounts,
          [action.storageAddress]: {
            storage: {},
            code: "0x",
            context: null
            //there will be more here in the future!
          }
        }
      };
      return newState;

    case actions.STORE: {
      //on a store, the relevant page should already exist, so we can just
      //add or update the needed slot
      const { address, slot, value } = action;
      if (address === DecodeUtils.EVM.ZERO_ADDRESS) {
        //as always, we do not maintain a zero page
        return state;
      }
      newState = state.slice(); //clone the state
      topCodex = newState[newState.length - 1];
      newState[newState.length - 1] = updateFrameStorage(
        topCodex,
        address,
        slot,
        value
      );
      return newState;
    }

    case actions.LOAD: {
      //loads are a little more complicated -- usually we do nothing, but if
      //it's an external load (there was nothing already there), then we want
      //to update *every* stackframe
      const { address, slot, value } = action;
      if (address === DecodeUtils.EVM.ZERO_ADDRESS) {
        //as always, we do not maintain a zero page
        return state;
      }
      topCodex = state[state.length - 1];
      if (topCodex.accounts[address].storage[slot] !== undefined) {
        //if we already have a value in the *top* stackframe, update *no*
        //stackframes; don't update the top (no need, it's just a load, not a
        //store), don't update the rest (that would be wrong, you might be
        //loading a value that will get reverted later)
        return state;
      } else {
        //if we *don't* already have a value in the top stackframe, that means
        //we're loading a value from a previous transaction!  That's not a
        //value that will get reverted if this call fails, so update *every*
        //stackframe
        return state.map(frame =>
          updateFrameStorage(frame, address, slot, value)
        );
      }
    }

    case actions.RETURN_CALL:
      //we want to pop the top while making the new top a copy of the old top;
      //that is to say, we want to drop just the element *second* from the top
      //NOTE: we don't ever go down to 1 element!
      return safeSave(state);

    case actions.RETURN_CREATE: {
      //we're going to do the same things in this case as in the usual return
      //case, but first we need to record the code that was returned
      const { address, code, context } = action;
      newState = state.slice(); //clone the state
      //NOTE: since this is only for RETURN_CREATE, and not FAIL, we shouldn't
      //have to worry about accidentally getting a zero address here
      newState[newState.length - 1] = updateFrameCode(
        newState[newState.length - 1],
        address,
        code,
        context
      );
      debug("newState: %O", newState);
      return safeSave(newState);
    }

    case actions.FAIL:
      //pop the stack
      //NOTE: we don't ever go down to 1 element!
      return safePop(state);

    case actions.RESET:
      return [state[0]]; //leave the -1 frame on the stack

    case actions.UNLOAD_TRANSACTION:
      return DEFAULT_CODEX;

    case actions.ADD_INSTANCE: {
      //add the instance to every frame
      //(this is a little HACKy, but it *should* be fine)
      debug("adding instance");
      const { address, binary, context } = action;
      return state.map(frame =>
        updateFrameCode(frame, address, binary, context)
      );
    }

    default:
      return state;
  }
}

const proc = combineReducers({
  callstack,
  codex
});

const reducer = combineReducers({
  info,
  transaction,
  proc
});

export default reducer;
<commit_msg>Fix updateFrameStorage<commit_after>import debugModule from "debug";
const debug = debugModule("debugger:evm:reducers");

import { combineReducers } from "redux";

import * as actions from "./actions";
import { keccak256, extractPrimarySource } from "lib/helpers";
import * as DecodeUtils from "@truffle/decode-utils";

import BN from "bn.js";

const DEFAULT_CONTEXTS = {
  byContext: {}
};

function contexts(state = DEFAULT_CONTEXTS, action) {
  switch (action.type) {
    /*
     * Adding a new context
     */
    case actions.ADD_CONTEXT:
      const {
        contractName,
        binary,
        sourceMap,
        compiler,
        abi,
        contractId,
        contractKind,
        isConstructor
      } = action;
      debug("action %O", action);
      //NOTE: we take hash as *string*, not as bytes, because the binary may
      //contain link references!
      const context = keccak256({ type: "string", value: binary });
      let primarySource;
      if (sourceMap !== undefined) {
        primarySource = extractPrimarySource(sourceMap);
      }
      //otherwise leave it undefined

      return {
        ...state,
        byContext: {
          ...state.byContext,
          [context]: {
            contractName,
            context,
            binary,
            sourceMap,
            primarySource,
            compiler,
            abi,
            contractId,
            contractKind,
            isConstructor
          }
        }
      };

    case actions.NORMALIZE_CONTEXTS:
      return {
        byContext: DecodeUtils.Contexts.normalizeContexts(state.byContext)
      };

    /*
     * Default case
     */
    default:
      return state;
  }
}

const info = combineReducers({
  contexts
});

const DEFAULT_TX = {
  gasprice: new BN(0),
  origin: DecodeUtils.EVM.ZERO_ADDRESS
};

function tx(state = DEFAULT_TX, action) {
  switch (action.type) {
    case actions.SAVE_GLOBALS:
      let { gasprice, origin } = action;
      return { gasprice, origin };
    case actions.UNLOAD_TRANSACTION:
      return DEFAULT_TX;
    default:
      return state;
  }
}

const DEFAULT_BLOCK = {
  coinbase: DecodeUtils.EVM.ZERO_ADDRESS,
  difficulty: new BN(0),
  gaslimit: new BN(0),
  number: new BN(0),
  timestamp: new BN(0)
};

function block(state = DEFAULT_BLOCK, action) {
  switch (action.type) {
    case actions.SAVE_GLOBALS:
      return action.block;
    case actions.UNLOAD_TRANSACTION:
      return DEFAULT_BLOCK;
    default:
      return state;
  }
}

const globals = combineReducers({
  tx,
  block
});

function status(state = null, action) {
  switch (action.type) {
    case actions.SAVE_STATUS:
      return action.status;
    case actions.UNLOAD_TRANSACTION:
      return null;
    default:
      return state;
  }
}

function initialCall(state = null, action) {
  switch (action.type) {
    case actions.CALL:
    case actions.CREATE:
      //we only want to save the initial call, so return
      //the current state if it's not null
      if (state !== null) {
        return state;
      } else {
        //we'll just store the action itself in the state
        return action;
      }
    case actions.UNLOAD_TRANSACTION:
      return null;
    default:
      return state;
  }
}

const transaction = combineReducers({
  globals,
  status,
  initialCall
});

function callstack(state = [], action) {
  switch (action.type) {
    case actions.CALL: {
      const { address, data, storageAddress, sender, value } = action;
      return state.concat([{ address, data, storageAddress, sender, value }]);
    }

    case actions.CREATE: {
      const { binary, storageAddress, sender, value } = action;
      return state.concat(
        [{ binary, data: "0x", storageAddress, sender, value }]
        //the empty data field is to make msg.data and msg.sig come out right
      );
    }

    case actions.RETURN_CALL:
    case actions.RETURN_CREATE:
    case actions.FAIL:
      //pop the stack... unless (HACK) that would leave it empty (this will
      //only happen at the end when we want to keep the last one around)
      return state.length > 1 ? state.slice(0, -1) : state;

    case actions.RESET:
    case actions.UNLOAD_TRANSACTION:
      return [];

    default:
      return state;
  }
}

const DEFAULT_CODEX = [
  {
    accounts: {}
    //will be more here in the future!
  }
];

function codex(state = DEFAULT_CODEX, action) {
  let newState, topCodex;

  const updateFrameStorage = (frame, address, slot, value) => ({
    ...frame,
    accounts: {
      ...frame.accounts,
      [address]: {
        code: "0x", //this will get overridden if it already exists!
        context: null, //similarly!
        ...frame.accounts[address], //may be undefined
        storage: {
          ...(frame.accounts[address] || {}).storage, //may be undefined
          [slot]: value
        }
      }
    }
  });
  //(note that {...undefined} just expands to {} and is OK)

  const updateFrameCode = (frame, address, code, context) => {
    let existingPage = frame.accounts[address] || { storage: {} };
    return {
      ...frame,
      accounts: {
        ...frame.accounts,
        [address]: {
          ...existingPage,
          code: code,
          context: context
        }
      }
    };
  };

  //later: will add "force" parameter
  const safePop = array => (array.length > 2 ? array.slice(0, -1) : array);

  //later: will add "force" parameter
  const safeSave = array =>
    array.length > 2
      ? array.slice(0, -2).concat([array[array.length - 1]])
      : array;

  switch (action.type) {
    case actions.CALL:
      debug("call action");
      debug("codex: %O", state);
      //on a call, we can just make a new stackframe by cloning the top
      //stackframe; there should already be an account for the address we're
      //calling into, so we don't need to make one
      return [...state, state[state.length - 1]];

    case actions.CREATE:
      debug("create action");
      //on a create, make a new stackframe, then add a new pages to the
      //codex if necessary; don't add a zero page though (or pages that already
      //exist)

      //first, add a new stackframe by cloning the top one
      newState = [...state, state[state.length - 1]];
      topCodex = newState[newState.length - 1];
      //now, do we need to add a new address to this stackframe?
      if (
        topCodex.accounts[action.storageAddress] !== undefined ||
        action.storageAddress === DecodeUtils.EVM.ZERO_ADDRESS
      ) {
        //if we don't
        return newState;
      }
      //if we do
      newState[newState.length - 1] = {
        ...topCodex,
        accounts: {
          ...topCodex.accounts,
          [action.storageAddress]: {
            storage: {},
            code: "0x",
            context: null
            //there will be more here in the future!
          }
        }
      };
      return newState;

    case actions.STORE: {
      debug("store action");
      //on a store, the relevant page should already exist, so we can just
      //add or update the needed slot
      const { address, slot, value } = action;
      if (address === DecodeUtils.EVM.ZERO_ADDRESS) {
        //as always, we do not maintain a zero page
        return state;
      }
      newState = state.slice(); //clone the state
      topCodex = newState[newState.length - 1];
      newState[newState.length - 1] = updateFrameStorage(
        topCodex,
        address,
        slot,
        value
      );
      return newState;
    }

    case actions.LOAD: {
      debug("load action");
      //loads are a little more complicated -- usually we do nothing, but if
      //it's an external load (there was nothing already there), then we want
      //to update *every* stackframe
      const { address, slot, value } = action;
      if (address === DecodeUtils.EVM.ZERO_ADDRESS) {
        //as always, we do not maintain a zero page
        return state;
      }
      topCodex = state[state.length - 1];
      if (topCodex.accounts[address].storage[slot] !== undefined) {
        //if we already have a value in the *top* stackframe, update *no*
        //stackframes; don't update the top (no need, it's just a load, not a
        //store), don't update the rest (that would be wrong, you might be
        //loading a value that will get reverted later)
        return state;
      } else {
        //if we *don't* already have a value in the top stackframe, that means
        //we're loading a value from a previous transaction!  That's not a
        //value that will get reverted if this call fails, so update *every*
        //stackframe
        return state.map(frame =>
          updateFrameStorage(frame, address, slot, value)
        );
      }
    }

    case actions.RETURN_CALL:
      debug("return from call");
      //we want to pop the top while making the new top a copy of the old top;
      //that is to say, we want to drop just the element *second* from the top
      //NOTE: we don't ever go down to 1 element!
      return safeSave(state);

    case actions.RETURN_CREATE: {
      debug("return from create");
      //we're going to do the same things in this case as in the usual return
      //case, but first we need to record the code that was returned
      const { address, code, context } = action;
      newState = state.slice(); //clone the state
      //NOTE: since this is only for RETURN_CREATE, and not FAIL, we shouldn't
      //have to worry about accidentally getting a zero address here
      newState[newState.length - 1] = updateFrameCode(
        newState[newState.length - 1],
        address,
        code,
        context
      );
      debug("newState: %O", newState);
      return safeSave(newState);
    }

    case actions.FAIL:
      debug("fail action");
      //pop the stack
      //NOTE: we don't ever go down to 1 element!
      return safePop(state);

    case actions.RESET:
      debug("reset action");
      return [state[0]]; //leave the -1 frame on the stack

    case actions.UNLOAD_TRANSACTION:
      debug("unload action");
      return DEFAULT_CODEX;

    case actions.ADD_INSTANCE: {
      //add the instance to every frame
      //(this is a little HACKy, but it *should* be fine)
      debug("adding instance");
      const { address, binary, context } = action;
      return state.map(frame =>
        updateFrameCode(frame, address, binary, context)
      );
    }

    default:
      return state;
  }
}

const proc = combineReducers({
  callstack,
  codex
});

const reducer = combineReducers({
  info,
  transaction,
  proc
});

export default reducer;
<|endoftext|>


<commit_before>import Ticker from '../core/util/Ticker.js';

const SIDE_MOVEMENT_SPEED = .02;
const PADDING_RATIO = .1;

export default class RulerInputElement extends HTMLElement {
  static get observedAttributes() {
    return ['step', 'min', 'max', 'zoom', 'noscroll'];
  }

  constructor() {
    super();

    this.attachShadow({ mode: 'open' }).innerHTML = `

0.00

    `;

    this._tick = this.shadowRoot.querySelector('#tick');
    this._scroller = this.shadowRoot.querySelector('#scroller');
    this._scrollerContent = this.shadowRoot.querySelector('#content');

    this._scroller.addEventListener('scroll', (event) => {
      this.dispatchEvent(new Event('scroll', event));
    });

    this._zoom = 1;
    this._step = 1;
    this._min = 0;
    this._max = 100;
    this._width = 1;
    this.value = 0;

    let pointerOffsetX = 0;
    const updateValueFromInput = () => {
      let positionRatio = (pointerOffsetX + this.scrollLeft) / this.scrollWidth;
      const padding = this._width * PADDING_RATIO;
      const right = this._width - padding;
      let speed = 0;
      // if (pointerOffsetX > right && (this.scrollLeft + this._width < this.scrollWidth)) {
      //   speed = (pointerOffsetX - right) / padding * SIDE_MOVEMENT_SPEED;
      // } else if (pointerOffsetX < padding && this.scrollLeft) {
      //   speed = (pointerOffsetX - padding) / padding * SIDE_MOVEMENT_SPEED;
      // }
      // this.scrollLeft += speed * this.scrollWidth;
      positionRatio += speed;
      const value = this.value;
      this.value = positionRatio * (this.max - this.min) + this.min;
      if (value !== this.value) {
        this.dispatchEvent(new Event('input', { bubbles: true }));
      }
    };
    const pointerDown = (event) => {
      if (!(event.buttons & 1)) {
        return;
      }
      this.setPointerCapture(event.pointerId);
      this.addEventListener('pointermove', pointerMove);
      this.addEventListener('pointerup', pointerUp);
      this.addEventListener('pointerout', pointerUp);
      pointerMove(event);
      Ticker.add(updateValueFromInput);
    };
    const pointerMove = (event) => {
      pointerOffsetX = event.offsetX;
    };
    const pointerUp = (event) => {
      Ticker.delete(updateValueFromInput);
      this.releasePointerCapture(event.pointerId);
      this.removeEventListener('pointermove', pointerMove);
      this.removeEventListener('pointerup', pointerUp);
      this.removeEventListener('pointerout', pointerUp);
    };
    this.addEventListener('pointerdown', pointerDown);

    this._scroller.addEventListener('scroll', () => {
      this._update();
    });

    const resizeObserver = new ResizeObserver((entries) => {
      this._width = entries[0].contentRect.width;
      this._updateBackgroundSize();
      this._update();
    });
    resizeObserver.observe(this);
  }

  attributeChangedCallback(name, oldValue, newValue) {
    switch (name) {
      case 'noscroll':
        this._scroller.style.pointerEvents = newValue === null ? '' : 'none';
        break;
      default:
        this[name] = Number(newValue);
        break;
    }
  }

  _getLocalOffsetXFromValue() {
    const positionRatio = (this.value - this.min) / (this.max - this.min);
    const edgeX = positionRatio * this._width * this.zoom - this.scrollLeft;
    console.log(edgeX);
  }

  _updateBackgroundSize() {
    const ratio = this._step / (this.max - this.min) * this.zoom;
    this._scrollerContent.style.backgroundSize = `${ratio * this._width}px, ${10 * ratio * this._width}px`;
  }

  _update() {
    if (!this._width) {
      return;
    }
    const positionRatio = (this.value - this.min) / (this.max - this.min);
    const edgeX = positionRatio * this.scrollWidth - this.scrollLeft;

    const padding = this._width * PADDING_RATIO;
    const right = this._width - padding;
    // if (edgeX > right) {
    //   this.scrollLeft += (edgeX - right);
    // } else if (edgeX < padding) {
    //   this.scrollLeft += (edgeX - padding);
    // }
    let x = positionRatio * this.scrollWidth - this.scrollLeft;
    x = Math.min(this._width, Math.max(0, x));
    this._tick.style.transform = `translateX(${x}px) translateX(-50%)`;
  }

  get value() {
    return this._value;
  }

  set value(value) {
    value = Math.round(value / this.step) * this.step;
    value = Math.min(Math.max(this.min, value), this.max);
    if (value === this._value) {
      return;
    }
    this._value = value;
    this._tick.textContent = `${this._value.toFixed(this._decimals)}`;
    this._update();
    this.dispatchEvent(new Event('change', { bubbles: true }));
  }

  get zoom() {
    return this._zoom;
  }

  set zoom(value) {
    this._zoom = Math.max(value, 1);
    this.style.setProperty('--zoom', this._zoom);
    this._updateBackgroundSize();
    this._update();
  }

  get scrollLeft() {
    return this._scroller.scrollLeft;
  }

  set scrollLeft(value) {
    this._scroller.scrollLeft = value;
  }

  get scrollWidth() {
    return this._width * this.zoom;
  }

  get min() {
    return this._min;
  }

  set min(value) {
    value = Math.min(this.max, value);
    this._min = value;
    this.value = Math.max(this.min, this.value);
  }

  get max() {
    return this._max;
  }

  set max(value) {
    value = Math.max(this.min, value);
    this._max = value;
    this.value = Math.min(this.max, this.value);
  }

  get step() {
    return this._step;
  }

  set step(value) {
    this._step = value;
    this._decimals = this._step % 1 ? String(this.step).split('.')[1].length : 0;
    this._updateBackgroundSize();
    this._tick.textContent = `${this._value.toFixed(this._decimals)}`;
    this.value = Math.round(this.value / this.step) * this.step;
  }
}

customElements.define('damo-input-ruler', RulerInputElement);
<commit_msg>put zoom out main style<commit_after>import Ticker from '../core/util/Ticker.js';

const SIDE_MOVEMENT_SPEED = .02;
const PADDING_RATIO = .1;

export default class RulerInputElement extends HTMLElement {
  static get observedAttributes() {
    return ['step', 'min', 'max', 'zoom', 'noscroll'];
  }

  constructor() {
    super();

    this.attachShadow({ mode: 'open' }).innerHTML = `

0.00

    `;

    this._tick = this.shadowRoot.querySelector('#tick');
    this._scroller = this.shadowRoot.querySelector('#scroller');
    this._scrollerContent = this.shadowRoot.querySelector('#content');

    this._scroller.addEventListener('scroll', (event) => {
      this.dispatchEvent(new Event('scroll', event));
    });

    this._zoom = 1;
    this._step = 1;
    this._min = 0;
    this._max = 100;
    this._width = 1;
    this.value = 0;

    let pointerOffsetX = 0;
    const updateValueFromInput = () => {
      let positionRatio = (pointerOffsetX + this.scrollLeft) / this.scrollWidth;
      const padding = this._width * PADDING_RATIO;
      const right = this._width - padding;
      let speed = 0;
      // if (pointerOffsetX > right && (this.scrollLeft + this._width < this.scrollWidth)) {
      //   speed = (pointerOffsetX - right) / padding * SIDE_MOVEMENT_SPEED;
      // } else if (pointerOffsetX < padding && this.scrollLeft) {
      //   speed = (pointerOffsetX - padding) / padding * SIDE_MOVEMENT_SPEED;
      // }
      // this.scrollLeft += speed * this.scrollWidth;
      positionRatio += speed;
      const value = this.value;
      this.value = positionRatio * (this.max - this.min) + this.min;
      if (value !== this.value) {
        this.dispatchEvent(new Event('input', { bubbles: true }));
      }
    };
    const pointerDown = (event) => {
      if (!(event.buttons & 1)) {
        return;
      }
      this.setPointerCapture(event.pointerId);
      this.addEventListener('pointermove', pointerMove);
      this.addEventListener('pointerup', pointerUp);
      this.addEventListener('pointerout', pointerUp);
      pointerMove(event);
      Ticker.add(updateValueFromInput);
    };
    const pointerMove = (event) => {
      pointerOffsetX = event.offsetX;
    };
    const pointerUp = (event) => {
      Ticker.delete(updateValueFromInput);
      this.releasePointerCapture(event.pointerId);
      this.removeEventListener('pointermove', pointerMove);
      this.removeEventListener('pointerup', pointerUp);
      this.removeEventListener('pointerout', pointerUp);
    };
    this.addEventListener('pointerdown', pointerDown);

    this._scroller.addEventListener('scroll', () => {
      this._update();
    });

    const resizeObserver = new ResizeObserver((entries) => {
      this._width = entries[0].contentRect.width;
      this._updateBackgroundSize();
      this._update();
    });
    resizeObserver.observe(this);
  }

  attributeChangedCallback(name, oldValue, newValue) {
    switch (name) {
      case 'noscroll':
        this._scroller.style.pointerEvents = newValue === null ? '' : 'none';
        break;
      default:
        this[name] = Number(newValue);
        break;
    }
  }

  _getLocalOffsetXFromValue() {
    const positionRatio = (this.value - this.min) / (this.max - this.min);
    const edgeX = positionRatio * this._width * this.zoom - this.scrollLeft;
    console.log(edgeX);
  }

  _updateBackgroundSize() {
    const ratio = this._step / (this.max - this.min) * this.zoom;
    this._scrollerContent.style.backgroundSize = `${ratio * this._width}px, ${10 * ratio * this._width}px`;
  }

  _update() {
    if (!this._width) {
      return;
    }
    const positionRatio = (this.value - this.min) / (this.max - this.min);
    const edgeX = positionRatio * this.scrollWidth - this.scrollLeft;

    const padding = this._width * PADDING_RATIO;
    const right = this._width - padding;
    // if (edgeX > right) {
    //   this.scrollLeft += (edgeX - right);
    // } else if (edgeX < padding) {
    //   this.scrollLeft += (edgeX - padding);
    // }
    let x = positionRatio * this.scrollWidth - this.scrollLeft;
    x = Math.min(this._width, Math.max(0, x));
    this._tick.style.transform = `translateX(${x}px) translateX(-50%)`;
  }

  get value() {
    return this._value;
  }

  set value(value) {
    value = Math.round(value / this.step) * this.step;
    value = Math.min(Math.max(this.min, value), this.max);
    if (value === this._value) {
      return;
    }
    this._value = value;
    this._tick.textContent = `${this._value.toFixed(this._decimals)}`;
    this._update();
    this.dispatchEvent(new Event('change', { bubbles: true }));
  }

  get zoom() {
    return this._zoom;
  }

  set zoom(value) {
    this._zoom = Math.max(value, 1);
    this._scrollerContent.style.width = `${this._zoom * 100}%`;
    this._updateBackgroundSize();
    this._update();
  }

  get scrollLeft() {
    return this._scroller.scrollLeft;
  }

  set scrollLeft(value) {
    this._scroller.scrollLeft = value;
  }

  get scrollWidth() {
    return this._width * this.zoom;
  }

  get min() {
    return this._min;
  }

  set min(value) {
    value = Math.min(this.max, value);
    this._min = value;
    this.value = Math.max(this.min, this.value);
  }

  get max() {
    return this._max;
  }

  set max(value) {
    value = Math.max(this.min, value);
    this._max = value;
    this.value = Math.min(this.max, this.value);
  }

  get step() {
    return this._step;
  }

  set step(value) {
    this._step = value;
    this._decimals = this._step % 1 ? String(this.step).split('.')[1].length : 0;
    this._updateBackgroundSize();
    this._tick.textContent = `${this._value.toFixed(this._decimals)}`;
    this.value = Math.round(this.value / this.step) * this.step;
  }
}

customElements.define('damo-input-ruler', RulerInputElement);
<|endoftext|>


<commit_before>import EmberHandlebars from "ember-handlebars-compiler";
import Ember from "ember-metal/core"; // to add to globals

import { runLoadHooks } from "ember-runtime/system/lazy_load";
import bootstrap from "ember-handlebars/loader";

import {
  makeBoundHelper,
  registerBoundHelper,
  helperMissingHelper,
  blockHelperMissingHelper,
  handlebarsGet
} from "ember-handlebars/ext";

// side effect of extending StringUtils of htmlSafe
import "ember-handlebars/string";

import {
  bind,
  _triageMustacheHelper,
  resolveHelper,
  bindHelper
} from "ember-handlebars/helpers/binding";

import {
  ifHelper,
  boundIfHelper,
  unboundIfHelper,
  unlessHelper
} from "ember-handlebars/helpers/if_unless";

import withHelper from "ember-handlebars/helpers/with";

import {
  bindAttrHelper,
  bindAttrHelperDeprecated,
  bindClasses
} from "ember-handlebars/helpers/bind_attr";

import collectionHelper from "ember-handlebars/helpers/collection";
import {
  ViewHelper,
  viewHelper
} from "ember-handlebars/helpers/view";
import unboundHelper from "ember-handlebars/helpers/unbound";
import {
  logHelper,
  debuggerHelper
} from "ember-handlebars/helpers/debug";
import {
  eachHelper
} from "ember-handlebars/helpers/each";
import templateHelper from "ember-handlebars/helpers/template";
import partialHelper from "ember-handlebars/helpers/partial";
import yieldHelper from "ember-handlebars/helpers/yield";
import locHelper from "ember-handlebars/helpers/loc";
import EachView from "ember-views/views/each";

import {
  inputHelper,
  textareaHelper
} from "ember-handlebars/controls";

/**
Ember Handlebars

@module ember
@submodule ember-handlebars
@requires ember-views
*/

// Ember.Handlebars.Globals
EmberHandlebars.bootstrap = bootstrap;
EmberHandlebars.makeBoundHelper = makeBoundHelper;
EmberHandlebars.registerBoundHelper = registerBoundHelper;
EmberHandlebars.resolveHelper = resolveHelper;
EmberHandlebars.bind = bind;
EmberHandlebars.bindClasses = bindClasses;
EmberHandlebars.EachView = EachView;
EmberHandlebars.ViewHelper = ViewHelper;
EmberHandlebars.get = handlebarsGet;

// Ember Globals
Ember.Handlebars = EmberHandlebars;

// register helpers
EmberHandlebars.registerHelper('helperMissing', helperMissingHelper);
EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper);
EmberHandlebars.registerHelper('bind', bindHelper);
EmberHandlebars.registerHelper('boundIf', boundIfHelper);
EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper);
EmberHandlebars.registerHelper('unboundIf', unboundIfHelper);
EmberHandlebars.registerHelper('with', withHelper);
EmberHandlebars.registerHelper('if', ifHelper);
EmberHandlebars.registerHelper('unless', unlessHelper);
EmberHandlebars.registerHelper('bind-attr', bindAttrHelper);
EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated);
EmberHandlebars.registerHelper('collection', collectionHelper);
EmberHandlebars.registerHelper("log", logHelper);
EmberHandlebars.registerHelper("debugger", debuggerHelper);
EmberHandlebars.registerHelper("each", eachHelper);
EmberHandlebars.registerHelper("loc", locHelper);
EmberHandlebars.registerHelper("partial", partialHelper);
EmberHandlebars.registerHelper("template", templateHelper);
EmberHandlebars.registerHelper("yield", yieldHelper);
EmberHandlebars.registerHelper("view", viewHelper);
EmberHandlebars.registerHelper("unbound", unboundHelper);
EmberHandlebars.registerHelper("input", inputHelper);
EmberHandlebars.registerHelper("textarea", textareaHelper);

// run load hooks
runLoadHooks('Ember.Handlebars', EmberHandlebars);

export default EmberHandlebars;
<commit_msg>Convert to single-quotes<commit_after>import EmberHandlebars from 'ember-handlebars-compiler';
import Ember from 'ember-metal/core'; // to add to globals

import { runLoadHooks } from 'ember-runtime/system/lazy_load';
import bootstrap from 'ember-handlebars/loader';

import {
  makeBoundHelper,
  registerBoundHelper,
  helperMissingHelper,
  blockHelperMissingHelper,
  handlebarsGet
} from 'ember-handlebars/ext';

// side effect of extending StringUtils of htmlSafe
import 'ember-handlebars/string';

import {
  bind,
  _triageMustacheHelper,
  resolveHelper,
  bindHelper
} from 'ember-handlebars/helpers/binding';

import {
  ifHelper,
  boundIfHelper,
  unboundIfHelper,
  unlessHelper
} from 'ember-handlebars/helpers/if_unless';

import withHelper from 'ember-handlebars/helpers/with';

import {
  bindAttrHelper,
  bindAttrHelperDeprecated,
  bindClasses
} from 'ember-handlebars/helpers/bind_attr';

import collectionHelper from 'ember-handlebars/helpers/collection';
import {
  ViewHelper,
  viewHelper
} from 'ember-handlebars/helpers/view';
import unboundHelper from 'ember-handlebars/helpers/unbound';
import {
  logHelper,
  debuggerHelper
} from 'ember-handlebars/helpers/debug';
import {
  eachHelper
} from 'ember-handlebars/helpers/each';
import templateHelper from 'ember-handlebars/helpers/template';
import partialHelper from 'ember-handlebars/helpers/partial';
import yieldHelper from 'ember-handlebars/helpers/yield';
import locHelper from 'ember-handlebars/helpers/loc';
import EachView from 'ember-views/views/each';

import {
  inputHelper,
  textareaHelper
} from 'ember-handlebars/controls';

/**
Ember Handlebars

@module ember
@submodule ember-handlebars
@requires ember-views
*/

// Ember.Handlebars.Globals
EmberHandlebars.bootstrap = bootstrap;
EmberHandlebars.makeBoundHelper = makeBoundHelper;
EmberHandlebars.registerBoundHelper = registerBoundHelper;
EmberHandlebars.resolveHelper = resolveHelper;
EmberHandlebars.bind = bind;
EmberHandlebars.bindClasses = bindClasses;
EmberHandlebars.EachView = EachView;
EmberHandlebars.ViewHelper = ViewHelper;
EmberHandlebars.get = handlebarsGet;

// Ember Globals
Ember.Handlebars = EmberHandlebars;

// register helpers
EmberHandlebars.registerHelper('helperMissing', helperMissingHelper);
EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper);
EmberHandlebars.registerHelper('bind', bindHelper);
EmberHandlebars.registerHelper('boundIf', boundIfHelper);
EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper);
EmberHandlebars.registerHelper('unboundIf', unboundIfHelper);
EmberHandlebars.registerHelper('with', withHelper);
EmberHandlebars.registerHelper('if', ifHelper);
EmberHandlebars.registerHelper('unless', unlessHelper);
EmberHandlebars.registerHelper('bind-attr', bindAttrHelper);
EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated);
EmberHandlebars.registerHelper('collection', collectionHelper);
EmberHandlebars.registerHelper('log', logHelper);
EmberHandlebars.registerHelper('debugger', debuggerHelper);
EmberHandlebars.registerHelper('each', eachHelper);
EmberHandlebars.registerHelper('loc', locHelper);
EmberHandlebars.registerHelper('partial', partialHelper);
EmberHandlebars.registerHelper('template', templateHelper);
EmberHandlebars.registerHelper('yield', yieldHelper);
EmberHandlebars.registerHelper('view', viewHelper);
EmberHandlebars.registerHelper('unbound', unboundHelper);
EmberHandlebars.registerHelper('input', inputHelper);
EmberHandlebars.registerHelper('textarea', textareaHelper);

// run load hooks
runLoadHooks('Ember.Handlebars', EmberHandlebars);

export default EmberHandlebars;
<|endoftext|>


<commit_before>/* @flow */
import objectReduce from 'fast-loops/lib/objectReduce'
import cssifyObject from 'css-in-js-utils/lib/cssifyObject'
import isPlainObject from 'isobject'
import {
  isSupport,
  isMediaQuery,
  isNestedSelector,
  isUndefinedValue,
  normalizeNestedProperty,
  processStyleWithPlugins,
  generateCombinedMediaQuery,
  generateCSSSelector,
  RULE_TYPE,
} from 'fela-utils'

import generateMonolithicClassName from './generateMonolithicClassName'

import type DOMRenderer from '../../../flowtypes/DOMRenderer'
import type MonolithicRenderer from '../../../flowtypes/MonolithicRenderer'

function useMonolithicRenderer(
  renderer: DOMRenderer,
  prettySelectors: boolean = false
): MonolithicRenderer {
  renderer.prettySelectors = prettySelectors

  renderer._renderStyleToCache = (
    className: string,
    style: Object,
    pseudo: string = '',
    media: string = '',
    support: string = ''
  ) => {
    const ruleSet = objectReduce(
      style,
      (ruleset, value, property) => {
        if (isPlainObject(value)) {
          if (isNestedSelector(property)) {
            renderer._renderStyleToCache(
              className,
              value,
              pseudo + normalizeNestedProperty(property),
              media,
              support
            )
          } else if (isMediaQuery(property)) {
            const combinedMediaQuery = generateCombinedMediaQuery(
              media,
              property.slice(6).trim()
            )

            renderer._renderStyleToCache(
              className,
              value,
              pseudo,
              combinedMediaQuery,
              support
            )
          } else if (isSupport(property)) {
            const combinedSupport = generateCombinedMediaQuery(
              support,
              property.slice(9).trim()
            )
            renderer._renderStyleToCache(
              className,
              value,
              pseudo,
              media,
              combinedSupport
            )
          } else {
            console.warn(`The object key "${property}" is not a valid nested key in Fela.
Maybe you forgot to add a plugin to resolve it?
Check http://fela.js.org/docs/basics/Rules.html#styleobject for more information.`)
          }
        } else if (!isUndefinedValue(value)) {
          ruleset[property] = value
        }

        return ruleset
      },
      {}
    )

    if (Object.keys(ruleSet).length > 0) {
      const css = cssifyObject(ruleSet)
      const selector = generateCSSSelector(className, pseudo)

      const change = {
        type: RULE_TYPE,
        className,
        selector,
        declaration: css,
        media,
        pseudo,
        support,
      }

      const declarationReference = selector + media + support
      renderer.cache[declarationReference] = change
      renderer._emitChange(change)
    }
  }

  renderer._renderStyleToClassNames = (
    { _className, ...style }: Object,
    rule: Function
  ): string => {
    if (Object.keys(style).length < 1) {
      return ''
    }

    const localRulePrefix =
      renderer.prettySelectors && (rule.ruleName || rule.name)
        ? `${rule.ruleName || rule.name}_`
        : ''

    const className = generateMonolithicClassName(
      style,
      (renderer.selectorPrefix || '') + (rule.selectorPrefix || localRulePrefix)
    )

    if (!renderer.cache.hasOwnProperty(className)) {
      renderer._renderStyleToCache(className, style)
      renderer.cache[className] = {}
    }

    return (_className ? ' ' + _className : '') + className
  }

  renderer.renderRule = (rule: Function, props: Object = {}): string =>
    renderer._renderStyle(rule(props, renderer), props, rule)

  renderer._renderStyle = (
    style: Object = {},
    props: Object = {},
    rule?: Function
  ): string => {
    const processedStyle = processStyleWithPlugins(
      renderer,
      style,
      RULE_TYPE,
      props
    )

    return renderer._renderStyleToClassNames(processedStyle, rule || {})
  }

  renderer.subscribe(event => {
    if (event.type === 'REHYDRATATION_FINISHED') {
      // Repair cache for monolithic usage
      renderer.cache = Object.keys(renderer.cache).reduce((acc, key) => {
        const item = renderer.cache[key]
        if (item.type === 'RULE') {
          return Object.assign(acc, {
            [item.className + item.media + item.support]: item,
          })
        }
        return Object.assign(acc, { [key]: item })
      }, {})
    }
  })

  return renderer
}

export default function monolithic(options: Object = {}) {
  return (renderer: DOMRenderer) =>
    useMonolithicRenderer(
      renderer,
      process.env.NODE_ENV !== 'production' && options.prettySelectors
    )
}
<commit_msg>fixed false className concatenation<commit_after>/* @flow */
import objectReduce from 'fast-loops/lib/objectReduce'
import cssifyObject from 'css-in-js-utils/lib/cssifyObject'
import isPlainObject from 'isobject'
import {
  isSupport,
  isMediaQuery,
  isNestedSelector,
  isUndefinedValue,
  normalizeNestedProperty,
  processStyleWithPlugins,
  generateCombinedMediaQuery,
  generateCSSSelector,
  RULE_TYPE,
} from 'fela-utils'

import generateMonolithicClassName from './generateMonolithicClassName'

import type DOMRenderer from '../../../flowtypes/DOMRenderer'
import type MonolithicRenderer from '../../../flowtypes/MonolithicRenderer'

function useMonolithicRenderer(
  renderer: DOMRenderer,
  prettySelectors: boolean = false
): MonolithicRenderer {
  renderer.prettySelectors = prettySelectors

  renderer._renderStyleToCache = (
    className: string,
    style: Object,
    pseudo: string = '',
    media: string = '',
    support: string = ''
  ) => {
    const ruleSet = objectReduce(
      style,
      (ruleset, value, property) => {
        if (isPlainObject(value)) {
          if (isNestedSelector(property)) {
            renderer._renderStyleToCache(
              className,
              value,
              pseudo + normalizeNestedProperty(property),
              media,
              support
            )
          } else if (isMediaQuery(property)) {
            const combinedMediaQuery = generateCombinedMediaQuery(
              media,
              property.slice(6).trim()
            )

            renderer._renderStyleToCache(
              className,
              value,
              pseudo,
              combinedMediaQuery,
              support
            )
          } else if (isSupport(property)) {
            const combinedSupport = generateCombinedMediaQuery(
              support,
              property.slice(9).trim()
            )
            renderer._renderStyleToCache(
              className,
              value,
              pseudo,
              media,
              combinedSupport
            )
          } else {
            console.warn(`The object key "${property}" is not a valid nested key in Fela.
Maybe you forgot to add a plugin to resolve it?
Check http://fela.js.org/docs/basics/Rules.html#styleobject for more information.`)
          }
        } else if (!isUndefinedValue(value)) {
          ruleset[property] = value
        }

        return ruleset
      },
      {}
    )

    if (Object.keys(ruleSet).length > 0) {
      const css = cssifyObject(ruleSet)
      const selector = generateCSSSelector(className, pseudo)

      const change = {
        type: RULE_TYPE,
        className,
        selector,
        declaration: css,
        media,
        pseudo,
        support,
      }

      const declarationReference = selector + media + support
      renderer.cache[declarationReference] = change
      renderer._emitChange(change)
    }
  }

  renderer._renderStyleToClassNames = (
    { _className, ...style }: Object,
    rule: Function
  ): string => {
    if (Object.keys(style).length < 1) {
      return ''
    }

    const localRulePrefix =
      renderer.prettySelectors && (rule.ruleName || rule.name)
        ? `${rule.ruleName || rule.name}_`
        : ''

    const className = generateMonolithicClassName(
      style,
      (renderer.selectorPrefix || '') + (rule.selectorPrefix || localRulePrefix)
    )

    if (!renderer.cache.hasOwnProperty(className)) {
      renderer._renderStyleToCache(className, style)
      renderer.cache[className] = {}
    }

    return (_className ? _className + ' ' : '') + className
  }

  renderer.renderRule = (rule: Function, props: Object = {}): string =>
    renderer._renderStyle(rule(props, renderer), props, rule)

  renderer._renderStyle = (
    style: Object = {},
    props: Object = {},
    rule?: Function
  ): string => {
    const processedStyle = processStyleWithPlugins(
      renderer,
      style,
      RULE_TYPE,
      props
    )

    return renderer._renderStyleToClassNames(processedStyle, rule || {})
  }

  renderer.subscribe(event => {
    if (event.type === 'REHYDRATATION_FINISHED') {
      // Repair cache for monolithic usage
      renderer.cache = Object.keys(renderer.cache).reduce((acc, key) => {
        const item = renderer.cache[key]
        if (item.type === 'RULE') {
          return Object.assign(acc, {
            [item.className + item.media + item.support]: item,
          })
        }
        return Object.assign(acc, { [key]: item })
      }, {})
    }
  })

  return renderer
}

export default function monolithic(options: Object = {}) {
  return (renderer: DOMRenderer) =>
    useMonolithicRenderer(
      renderer,
      process.env.NODE_ENV !== 'production' && options.prettySelectors
    )
}
<|endoftext|>


<commit_before><commit_msg>feat(gatsby-cli): support for develop PORT env var (#20110)<commit_after><|endoftext|>


<commit_before>/**
 * Policies are simply Express middleware functions which run before your controllers.
 * You can apply one or more policies for a given controller or action.
 *
 * Any policy file (e.g. `authenticated.js`) can be dropped into the `/policies` folder,
 * at which point it can be accessed below by its filename, minus the extension, (e.g. `authenticated`)
 *
 * For more information on policies, check out:
 * http://sailsjs.org/#documentation
 */
module.exports.policies = {
    /**
     * By default require authentication always.
     *
     * see api/policies/authenticated.js
     */
    "*": ["flashMessage", "authenticated"],

    // whitelist the auth controller, this is used for login
    "auth": {
        "*": true,

        // Custom actions
        login:          ["flashMessage"],
        logout:         [true],
        authenticate:   [true]
    },

    // Project controller policies
    "Project": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"], // Todo: try to figure out how to restrict access to all projects
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket"], // Todo: it is really good that every user can add new project?
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        backlog:    ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        milestones: ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        planning:   ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        statistics: ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        sprints:    ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"]
    },

    // Phase controller policies
    "Phase": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasPhaseAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasPhaseAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasPhaseAdmin"],

        // Custom actions
        edit:       ["flashMessage", "authenticated", "isAjax", "hasProjectAdmin"]
    },

    // Sprint controller policies
    "Sprint": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAdmin"],

        // Custom actions
        add:            ["flashMessage", "authenticated", "isAjax", "hasSprintAdmin"],
        edit:           ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"],
        backlog:        ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"],
        charts:         ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"],
        chartDataTasks: ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"]
    },

    // Milestone controller policies
    "Milestone": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax", "hasMilestoneAdmin"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasMilestoneAccess"],
        stories:    ["flashMessage", "authenticated", "isAjax", "hasMilestoneAccess"]
    },

    // Story controller policies
    "Story": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax", "hasStoryAdmin"],
        split:      ["flashMessage", "authenticated", "isAjax", "hasStoryAdmin"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasStoryAccess"],
        tasks:      ["flashMessage", "authenticated", "isAjax", "hasStoryAccess"]
    },

    // Task controller policies
    "Task": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax", "hasTaskAdmin"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasTaskAccess"],
        statistics: ["flashMessage", "authenticated", "isAjax", "hasTaskAccess"]
    },

    // User controller policies
    "User": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasUserAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasUserAdminOrItself"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasUserAdmin"],

        // Custom actions
        list:           ["flashMessage", "authenticated", "isAjax", "hasUserAdmin"],
        add:            ["flashMessage", "authenticated", "isAjax", "hasUserAdmin"],
        edit:           ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"],
        history:        ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"],
        projects:       ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"],
        changePassword: ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"]
    },

    // ProjectUser controller policies
    "ProjectUser": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],

        // Custom actions
        users:          ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        availableUsers: ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAccess"],
        ownProjects:    ["flashMessage", "authenticated", "isAjaxOrSocket"],
        getRole:        ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAccess"]
    },

    // Type controller policies
    "Type": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "isAdministrator"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "isAdministrator"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "isAdministrator"]
    },

    // Type controller policies
    "Validator": {
        // By default do not allow nothing
        "*":            false,

        // Custom actions
        isUnique:       ["flashMessage", "authenticated", "isAjax"],
        passwordCheck:  ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"]
    }
};
<commit_msg>Added basic policies for Comment controller.<commit_after>/**
 * Policies are simply Express middleware functions which run before your controllers.
 * You can apply one or more policies for a given controller or action.
 *
 * Any policy file (e.g. `authenticated.js`) can be dropped into the `/policies` folder,
 * at which point it can be accessed below by its filename, minus the extension, (e.g. `authenticated`)
 *
 * For more information on policies, check out:
 * http://sailsjs.org/#documentation
 */
module.exports.policies = {
    /**
     * By default require authentication always.
     *
     * see api/policies/authenticated.js
     */
    "*": ["flashMessage", "authenticated"],

    // whitelist the auth controller, this is used for login
    "auth": {
        "*": true,

        // Custom actions
        login:          ["flashMessage"],
        logout:         [true],
        authenticate:   [true]
    },

    // Project controller policies
    "Project": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"], // Todo: try to figure out how to restrict access to all projects
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket"], // Todo: it is really good that every user can add new project?
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        backlog:    ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        milestones: ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        planning:   ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        statistics: ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        sprints:    ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"]
    },

    // Phase controller policies
    "Phase": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasPhaseAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasPhaseAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasPhaseAdmin"],

        // Custom actions
        edit:       ["flashMessage", "authenticated", "isAjax", "hasProjectAdmin"]
    },

    // Sprint controller policies
    "Sprint": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasSprintAdmin"],

        // Custom actions
        add:            ["flashMessage", "authenticated", "isAjax", "hasSprintAdmin"],
        edit:           ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"],
        backlog:        ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"],
        charts:         ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"],
        chartDataTasks: ["flashMessage", "authenticated", "isAjax", "hasSprintAccess"]
    },

    // Milestone controller policies
    "Milestone": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasMilestoneAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax", "hasMilestoneAdmin"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasMilestoneAccess"],
        stories:    ["flashMessage", "authenticated", "isAjax", "hasMilestoneAccess"]
    },

    // Story controller policies
    "Story": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasStoryAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax", "hasStoryAdmin"],
        split:      ["flashMessage", "authenticated", "isAjax", "hasStoryAdmin"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasStoryAccess"],
        tasks:      ["flashMessage", "authenticated", "isAjax", "hasStoryAccess"]
    },

    // Task controller policies
    "Task": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAccess"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasTaskAdmin"],

        // Custom actions
        add:        ["flashMessage", "authenticated", "isAjax", "hasTaskAdmin"],
        edit:       ["flashMessage", "authenticated", "isAjax", "hasTaskAccess"],
        statistics: ["flashMessage", "authenticated", "isAjax", "hasTaskAccess"]
    },

    // User controller policies
    "User": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasUserAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasUserAdminOrItself"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasUserAdmin"],

        // Custom actions
        list:           ["flashMessage", "authenticated", "isAjax", "hasUserAdmin"],
        add:            ["flashMessage", "authenticated", "isAjax", "hasUserAdmin"],
        edit:           ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"],
        history:        ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"],
        projects:       ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"],
        changePassword: ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"]
    },

    // ProjectUser controller policies
    "ProjectUser": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAdmin"],

        // Custom actions
        users:          ["flashMessage", "authenticated", "isAjax", "hasProjectAccess"],
        availableUsers: ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAccess"],
        ownProjects:    ["flashMessage", "authenticated", "isAjaxOrSocket"],
        getRole:        ["flashMessage", "authenticated", "isAjaxOrSocket", "hasProjectAccess"]
    },

    // Type controller policies
    "Type": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "isAdministrator"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "isAdministrator"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket", "isAdministrator"]
    },

    // Story controller policies
    "Comment": {
        // By default do not allow nothing
        "*":        false,

        // Default handling for blueprints
        // TODO: add policy to check actual right to create, update and destroy
        find:       ["flashMessage", "authenticated", "isAjaxOrSocket"],
        create:     ["flashMessage", "authenticated", "isAjaxOrSocket", "addUserDataCreate"],
        update:     ["flashMessage", "authenticated", "isAjaxOrSocket", "addUserDataUpdate"],
        destroy:    ["flashMessage", "authenticated", "isAjaxOrSocket"],

        // Custom actions
        index:      ["flashMessage", "authenticated", "isAjax"]
    },

    // Validator controller policies
    "Validator": {
        // By default do not allow nothing
        "*":            false,

        // Custom actions
        isUnique:       ["flashMessage", "authenticated", "isAjax"],
        passwordCheck:  ["flashMessage", "authenticated", "isAjax", "hasUserAdminOrItself"]
    }
};
<|endoftext|>


<commit_before>import knexjs from 'knex'
import * as logger from '../app/support/debugLogger';
import { load as configLoader } from './config'

const config = configLoader()

const knex = knexjs(config.postgres)

if (logger.isEnabledFor('sql')) {
  const log = logger.get('sql');

  knex.on('start', (builder) => {
    const q = builder.toString();
    const start = new Date().getTime();
    builder.on('end', () => {
      log('%s %s', q, logger.stylize(`${new Date().getTime() - start}ms`, 'green'));
    });
  });
}

export function connect() {
  return knex
}

export function configure() {
  const { textSearchConfigName } = config.postgres;
  return knex.raw(`SET default_text_search_config TO '${textSearchConfigName}'`)
}
<commit_msg>Add DEBUG log switch to show errored SQL queries<commit_after>import knexjs from 'knex'
import * as logger from '../app/support/debugLogger';
import { load as configLoader } from './config'

const config = configLoader()

const knex = knexjs(config.postgres)

if (logger.isEnabledFor('sql') || logger.isEnabledFor('sql-error')) {
  const log = logger.get('sql');
  const errLog = logger.get('sql-error');

  knex.on('start', (builder) => {
    const q = builder.toString();
    const start = new Date().getTime();
    builder.on('end', () => {
      log('%s %s', q, logger.stylize(`${new Date().getTime() - start}ms`, 'green'));
    });
    builder.on('error', () => {
      errLog('%s %s', logger.stylize('ERROR', 'red'), q);
    });
  });
}

export function connect() {
  return knex
}

export function configure() {
  const { textSearchConfigName } = config.postgres;
  return knex.raw(`SET default_text_search_config TO '${textSearchConfigName}'`)
}
<|endoftext|>


<commit_before>$(function() {
	var jumboTron = {
		$headerField: $("#jHeader"),
		$bodyField: $("#jBody"),
		init: function(header, body) {
			this.header = header;
			this.body = body;
			this.render();
		},
		render: function() {
			this.$headerField.html(this.header);
			this.$bodyField.html(this.body);
		}
	}

	var historyTable = {
		$panel: $("#historyPanel"),
		$tableBody: $("#historyTableBody"),
		init: function(name, histories) {
			this.name = name;
			this.histories = histories;
			this.render();
		},
 		render: function() {
			if(this.histories.length == 0) {
				this.$panel.css("display", "none");
			} else {
				this.$panel.css("display", "block");
				this.$tableBody.empty();
				for(var a = 0; a < Math.min(5, this.histories.length); a++) {
					this.$tableBody.append(this.getTableRow(this.histories[a]));
				}
			}
		},
		getTableRow: function(history) {
			return "
"+this.name+" v"+history.versionNumber+"	"+history.lastRank+" of "+history.lastNumPlayers+"	"+(history.lastNumGames != null ? history.lastNumGames : "Not Recorded")+"
";
		}
	}

	var statTable = {
		$tableBody: $("#statTableBody"),
		stats: [],
		init: function(stats) {
			this.stats = stats;
			this.render();
		},
 		render: function() {
			this.$tableBody.empty();
			for(var a = 0; a < this.stats.length; a++) {
				this.$tableBody.append(this.getTableRow(this.stats[a]));
			}
		},
		getTableRow: function(stat) {
			if(stat.mouseOverText != undefined && stat.mouseOverText != null) {
				return "
"+stat.name+"	"+stat.value+"
";
			} else {
				return "
"+stat.name+"	"+stat.value+"
";
			}
		}
	}

	var gameTable = {
		$tableHeader: $("#gameTableHeader"),
		$tableBody: $("#gameTableBody"),
		$loadButton: $("#loadButton"),
		games: [],
		init: function(userID, isMe, getNextGames) {
			this.userID = userID;
			this.getNextGames = getNextGames;
			this.games = getNextGames(this.userID);
			this.isMe = isMe;

			this.$loadButton.click(this, this.loadMore.bind(this));

			this.render();
		},
		render: function() {
			this.$tableHeader.html("Participants	Result	Dimensions	View	");
			if(this.isMe) this.$tableHeader.append("Error Log	");
			this.$tableBody.empty();
			for(var a = 0; a < this.games.length; a++) {
				this.$tableBody.append(this.getTableRow(this.games[a]));
			}
		},
		getTableRow: function(game) {
			var playersList = "
";
			var userID = this.userID;
			playersList += game.players.map(function(player) {
				if(player.userID == userID) {
					return "
"+player.username+"
";
				} else {
					return "
"+player.username+"
";
				}
			}).join(" ");

			playersList += "
";
			var $row = $("
"+playersList+"	"+game.result+"	"+game.mapWidth+"x"+game.mapHeight+"
");
			if(this.isMe) {
				var me = null;
				for(var a = 0; a < game.players.length; a++) {
					if(game.players[a].userID == this.userID) {
						me = game.players[a];
						break;
					}
				}
				if(me.errorLogName != undefined && me.errorLogName != null) $row.append("	");
				else $row.append("NA	");
			}
			return $row;
		},
		loadMore: function() {
			this.games = this.games.concat(this.getNextGames(this.userID, this.games[this.games.length-1].gameID));
			this.render();
		}
	}

	function statsFromUser(user, numUsers) {
		var statDetails = {
			"score": {name: "Trueskill Rating", mouseOverText: null},
			"mu": {name: "Trueskill Mu", mouseOverText: "Your estimated average skill discounting any uncertainty"},
			"sigma": {name: "Trueskill Sigma", mouseOverText: "The uncertainty of your \"mu\" value"},
			"numSubmissions": {name: "Number of Bots Submitted", mouseOverText: null},
			"numGames": {name: "Number of Games Played", mouseOverText: null},
			"language": {name: "Language", mouseOverText: null},
			"didTimeout": {name: "Timeout Frequency", mouseOverText: null},
			"territoryRanking": {name: "Territory Ranking", mouseOverText: "(Your total territory * Number of players)/(Number of frames you were alive * Map area)", percentile: true},
			"strengthRanking": {name: "Strength Ranking", mouseOverText: "(Your total strength * Number of players) / (Number of frames you were alive * Map area)", percentile: true},
			"productionRanking": {name: "Production Ranking", mouseOverText: "(Total amount of strength that you produced * Number of players) / (Number of turns you were alive * Map area)", percentile: true},
			"stillRanking": {name: "Still Move Frequency", mouseOverText: "(Number of still moves) / (Total number of moves)", percentile: true},
			"turnTimeRanking": {name: "Time per Turn", mouseOverText: "Average latency per turn", percentile: true}
		};
		var stats = [];
		for(var key in statDetails) {
			if(user[key] != undefined && user[key] != null) {
				if(statDetails[key].percentile) {
					stats.push({name: statDetails[key].name, mouseOverText: statDetails[key].mouseOverText, value: user[key]+" of "+numUsers})
				} else {
					stats.push({name: statDetails[key].name, mouseOverText: statDetails[key].mouseOverText, value: user[key]})
				}
			}
		}
		return stats;
	}

	var session = getSession();

	var userID = getGET("userID");
	var user = getUser(userID);
	var extraStats = getExtraStats(userID);
	$.extend(user, extraStats);
	user["score"] = Math.round(100*(user["mu"]-3*user["sigma"]))/100;
	user["didTimeout"] = (Math.round(1000*user["didTimeout"])/10) + "%";

	var numUsers = getNumActiveUsers();

	$(document).prop('title', user.username);

	jumboTron.init(user.username, "Ranked " + user.rank + " of " + numUsers);
	statTable.init(statsFromUser(user, numUsers));
	gameTable.init(userID, session == null ? false : parseInt(session.userID) == userID, function(userID, startingID) {
		console.log(startingID)
		var rawGames = getLatestGamesForUser(userID, 10, startingID);
		console.log(rawGames);
		var games = [];
		for(var a = 0; a < rawGames.length; a++) {
			var players = rawGames[a].users;
			players.sort(function(p1, p2) {
				return parseInt(p1.rank) - parseInt(p2.rank);
			});
			var thisUser = players.find(function(p){return parseInt(p.userID)==userID;});
			var result = thisUser.rank + " of " + players.length;

			games.push({
				gameID: rawGames[a].gameID,
				players: players,
				result: result,
				mapWidth: rawGames[a].mapWidth,
				mapHeight: rawGames[a].mapHeight,
				replayName: rawGames[a].replayName
			});
		}
		console.log(games)
		return games;
	});
	historyTable.init(user.username, getHistories(userID));
})
<commit_msg>Take out useless stats<commit_after>$(function() {
	var jumboTron = {
		$headerField: $("#jHeader"),
		$bodyField: $("#jBody"),
		init: function(header, body) {
			this.header = header;
			this.body = body;
			this.render();
		},
		render: function() {
			this.$headerField.html(this.header);
			this.$bodyField.html(this.body);
		}
	}

	var historyTable = {
		$panel: $("#historyPanel"),
		$tableBody: $("#historyTableBody"),
		init: function(name, histories) {
			this.name = name;
			this.histories = histories;
			this.render();
		},
 		render: function() {
			if(this.histories.length == 0) {
				this.$panel.css("display", "none");
			} else {
				this.$panel.css("display", "block");
				this.$tableBody.empty();
				for(var a = 0; a < Math.min(5, this.histories.length); a++) {
					this.$tableBody.append(this.getTableRow(this.histories[a]));
				}
			}
		},
		getTableRow: function(history) {
			return "
"+this.name+" v"+history.versionNumber+"	"+history.lastRank+" of "+history.lastNumPlayers+"	"+(history.lastNumGames != null ? history.lastNumGames : "Not Recorded")+"
";
		}
	}

	var statTable = {
		$tableBody: $("#statTableBody"),
		stats: [],
		init: function(stats) {
			this.stats = stats;
			this.render();
		},
 		render: function() {
			this.$tableBody.empty();
			for(var a = 0; a < this.stats.length; a++) {
				this.$tableBody.append(this.getTableRow(this.stats[a]));
			}
		},
		getTableRow: function(stat) {
			if(stat.mouseOverText != undefined && stat.mouseOverText != null) {
				return "
"+stat.name+"	"+stat.value+"
";
			} else {
				return "
"+stat.name+"	"+stat.value+"
";
			}
		}
	}

	var gameTable = {
		$tableHeader: $("#gameTableHeader"),
		$tableBody: $("#gameTableBody"),
		$loadButton: $("#loadButton"),
		games: [],
		init: function(userID, isMe, getNextGames) {
			this.userID = userID;
			this.getNextGames = getNextGames;
			this.games = getNextGames(this.userID);
			this.isMe = isMe;

			this.$loadButton.click(this, this.loadMore.bind(this));

			this.render();
		},
		render: function() {
			this.$tableHeader.html("Participants	Result	Dimensions	View	");
			if(this.isMe) this.$tableHeader.append("Error Log	");
			this.$tableBody.empty();
			for(var a = 0; a < this.games.length; a++) {
				this.$tableBody.append(this.getTableRow(this.games[a]));
			}
		},
		getTableRow: function(game) {
			var playersList = "
";
			var userID = this.userID;
			playersList += game.players.map(function(player) {
				if(player.userID == userID) {
					return "
"+player.username+"
";
				} else {
					return "
"+player.username+"
";
				}
			}).join(" ");

			playersList += "
";
			var $row = $("
"+playersList+"	"+game.result+"	"+game.mapWidth+"x"+game.mapHeight+"
");
			if(this.isMe) {
				var me = null;
				for(var a = 0; a < game.players.length; a++) {
					if(game.players[a].userID == this.userID) {
						me = game.players[a];
						break;
					}
				}
				if(me.errorLogName != undefined && me.errorLogName != null) $row.append("	");
				else $row.append("NA	");
			}
			return $row;
		},
		loadMore: function() {
			this.games = this.games.concat(this.getNextGames(this.userID, this.games[this.games.length-1].gameID));
			this.render();
		}
	}

	function statsFromUser(user, numUsers) {
		var statDetails = {
			"score": {name: "Trueskill Rating", mouseOverText: null},
			"mu": {name: "Trueskill Mu", mouseOverText: "Your estimated average skill discounting any uncertainty"},
			"sigma": {name: "Trueskill Sigma", mouseOverText: "The uncertainty of your \"mu\" value"},
			"numSubmissions": {name: "Number of Bots Submitted", mouseOverText: null},
			"numGames": {name: "Number of Games Played", mouseOverText: null},
			"language": {name: "Language", mouseOverText: null},
			"didTimeout": {name: "Timeout Frequency", mouseOverText: null},
			"stillRanking": {name: "Still Move Frequency", mouseOverText: "(Number of still moves) / (Total number of moves)", percentile: true},
			"turnTimeRanking": {name: "Time per Turn", mouseOverText: "Average latency per turn", percentile: true}
		};
		var stats = [];
		for(var key in statDetails) {
			if(user[key] != undefined && user[key] != null) {
				if(statDetails[key].percentile) {
					stats.push({name: statDetails[key].name, mouseOverText: statDetails[key].mouseOverText, value: user[key]+" of "+numUsers})
				} else {
					stats.push({name: statDetails[key].name, mouseOverText: statDetails[key].mouseOverText, value: user[key]})
				}
			}
		}
		return stats;
	}

	var session = getSession();

	var userID = getGET("userID");
	var user = getUser(userID);
	var extraStats = getExtraStats(userID);
	$.extend(user, extraStats);
	user["score"] = Math.round(100*(user["mu"]-3*user["sigma"]))/100;
	user["didTimeout"] = (Math.round(1000*user["didTimeout"])/10) + "%";

	var numUsers = getNumActiveUsers();

	$(document).prop('title', user.username);

	jumboTron.init(user.username, "Ranked " + user.rank + " of " + numUsers);
	statTable.init(statsFromUser(user, numUsers));
	gameTable.init(userID, session == null ? false : parseInt(session.userID) == userID, function(userID, startingID) {
		console.log(startingID)
		var rawGames = getLatestGamesForUser(userID, 10, startingID);
		console.log(rawGames);
		var games = [];
		for(var a = 0; a < rawGames.length; a++) {
			var players = rawGames[a].users;
			players.sort(function(p1, p2) {
				return parseInt(p1.rank) - parseInt(p2.rank);
			});
			var thisUser = players.find(function(p){return parseInt(p.userID)==userID;});
			var result = thisUser.rank + " of " + players.length;

			games.push({
				gameID: rawGames[a].gameID,
				players: players,
				result: result,
				mapWidth: rawGames[a].mapWidth,
				mapHeight: rawGames[a].mapHeight,
				replayName: rawGames[a].replayName
			});
		}
		console.log(games)
		return games;
	});
	historyTable.init(user.username, getHistories(userID));
})
<|endoftext|>


<commit_before>/* Copyright (c) 2013 The Tagspaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */

define(function(require, exports, module) {
"use strict";

	console.log("Loading editorHTML");
	exports.id = "editorHTML"; // ID should be equal to the directory name where the ext. is located
	exports.title = "HTML Editor";
	exports.type = "editor";
	exports.supportedFileTypes = [ "htm", "html" ];

	var TSCORE = require("tscore");

	var htmlEditor = undefined;

	var extensionsPath = TSCORE.Config.getExtensionPath();

	var extensionDirectory = extensionsPath+"/"+exports.id;

	exports.init = function(filePath, containerElementID) {
	    console.log("Initalization HTML Text Editor...");
		require([
            extensionsPath+'/editorText/codemirror/codemirror.js',
			extensionDirectory+'/summernote/summernote.min.js',
            //"css!"+extensionDirectory+'/summernote/summernote-bs3.css',
            "css!"+extensionDirectory+'/summernote/summernote.css',
            'css!'+extensionsPath+'/editorText/codemirror/codemirror.css',
            'css!'+extensionsPath+'/editorText/codemirror/theme/monokai.css',
            'css!'+extensionDirectory+'/extension.css',
		 	], function() {
                require([
                    extensionsPath+'/editorText/codemirror/mode/xml/xml.js',
                ]);
				$("#"+containerElementID).append('

');
				TSCORE.IO.loadTextFile(filePath);
		});
	};

	exports.setFileType = function(fileType) {
	    console.log("setFileType not supported on this extension");
	};

	exports.viewerMode = function(isViewerMode) {
	    // set readonly
	};

	exports.setContent = function(content) {
		$('#htmlEditor').html(content);
		$('#htmlEditor').summernote({
          focus: true,
          codemirror: {
            theme: 'monokai'
          },
          toolbar: [
            ['style', ['style']],
            ['style', ['bold', 'italic', 'underline', 'clear']],
            ['fontsize', ['fontsize']],
            ['color', ['color']],
            ['para', ['ul', 'ol', 'paragraph']],
            ['height', ['height']],
            //['insert', ['picture', 'link']], // no insert buttons
            ['table', ['table']],
            ['view', ['codeview']],
            //['help', ['help']] //no help button
          ]
		});
	};

	exports.getContent = function() {
		var content = $('#htmlEditor').code();
		//console.log("HTML content: "+content);
		return content;
	};

});
<commit_msg>fixing #32, #31, #30, #26<commit_after>/* Copyright (c) 2013 The Tagspaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */

define(function(require, exports, module) {
"use strict";

	console.log("Loading editorHTML");
	exports.id = "editorHTML"; // ID should be equal to the directory name where the ext. is located
	exports.title = "HTML Editor";
	exports.type = "editor";
	exports.supportedFileTypes = [ "htm", "html" ];

	var TSCORE = require("tscore");

	var htmlEditor = undefined;

	var extensionsPath = TSCORE.Config.getExtensionPath();

	var extensionDirectory = extensionsPath+"/"+exports.id;

	var content = undefined;

	exports.init = function(filePath, containerElementID) {
	    console.log("Initalization HTML Text Editor...");
		require([
			extensionDirectory+'/summernote/summernote.js',
            'css!'+extensionDirectory+'/summernote/summernote.css',
            'css!'+extensionDirectory+'/extension.css',
		 	], function() {
				$("#"+containerElementID).append('

');
				TSCORE.IO.loadTextFile(filePath);
		});
	};

	exports.setFileType = function(fileType) {
	    console.log("setFileType not supported on this extension");
	};

	exports.viewerMode = function(isViewerMode) {
	    // set readonly
	};

	exports.setContent = function(cont) {
		content = cont;

        var reg = /\]*\>([^]*)\<\/body/m;

        var bodyContent = undefined;

        // TODO try this
        try {
            bodyContent = content.match( reg )[1];
        } catch(e) {
            console.log("Error parsing HTML document. "+e);
            $('#htmlEditor').append("

  Error parsing HTML document. Probably a body tag was not found in the document.
");
            return false;
        }

		//console.log("body content: "+bodyContent);

        var cleanedBodyContent = bodyContent.replace(/


<commit_before>module.exports = function (targetObj) {
    for (var i = 1 ; i < arguments.length ; i += 1) {
        var sourceObj = arguments[i];
        for (var propertyName in sourceObj) {
            var getter = sourceObj.__lookupGetter__(propertyName),
                setter = sourceObj.__lookupSetter__(propertyName);
            if (getter || setter) {
                if (getter) {
                    targetObj.__defineGetter__(propertyName, getter);
                }
                if (setter) {
                    targetObj.__defineSetter__(propertyName, setter);
                }
            } else if (sourceObj[propertyName] !== void 0) {
                targetObj[propertyName] = sourceObj[propertyName];
            }
        }
    }
    return targetObj;
};
<commit_msg>extendWithGettersAndSetters.js<commit_after>module.exports = function (targetObj) {
    for (var i = 1 ; i < arguments.length ; i += 1) {
        var sourceObj = arguments[i];
        Object.keys(sourceObj).forEach(function (propertyName) {
            var getter = sourceObj.__lookupGetter__(propertyName),
                setter = sourceObj.__lookupSetter__(propertyName);
            if (getter || setter) {
                if (getter) {
                    targetObj.__defineGetter__(propertyName, getter);
                }
                if (setter) {
                    targetObj.__defineSetter__(propertyName, setter);
                }
            } else if (sourceObj[propertyName] !== void 0) {
                targetObj[propertyName] = sourceObj[propertyName];
            }
        });
    }
    return targetObj;
};
<|endoftext|>


<commit_before>const installDeps = require('../installDeps')

describe('installDeps', () => {
  it('install a list of dependencies | undefined', () => {
    // const result = installDeps()
    // expect(result).toBe('(which yarn && yarn) || npm install')
  })

  // it('install a list of dependencies | []', () => {
  //   const result = installDeps([])
  //   expect(result).toBe('(which yarn && yarn) || npm install')
  // })

  // it('install a list of dependencies | [react]', () => {
  //   const result = installDeps(['react-redux'])
  //   expect(result).toBe('(which yarn && yarn add react-redux) || npm install --save react-redux')
  // })

  // it('install a list of dependencies | [one, two]', () => {
  //   const result = installDeps(['react-redux', 'react-router-dom'])
  //   expect(result).toBe('(which yarn && yarn add react-redux react-router-dom) || npm install --save react-redux react-router-dom')
  // })

  // it('install a list of dependencies | object', () => {
  //   const result = installDeps({ name: 'a' })
  //   expect(result).toBe('(which yarn && yarn) || npm install')
  // })
})
<commit_msg>fix(lint): Remove unused variable<commit_after>// const installDeps = require('../installDeps')

describe('installDeps', () => {
  it('install a list of dependencies | undefined', () => {
    // const result = installDeps()
    // expect(result).toBe('(which yarn && yarn) || npm install')
  })

  // it('install a list of dependencies | []', () => {
  //   const result = installDeps([])
  //   expect(result).toBe('(which yarn && yarn) || npm install')
  // })

  // it('install a list of dependencies | [react]', () => {
  //   const result = installDeps(['react-redux'])
  //   expect(result).toBe('(which yarn && yarn add react-redux) || npm install --save react-redux')
  // })

  // it('install a list of dependencies | [one, two]', () => {
  //   const result = installDeps(['react-redux', 'react-router-dom'])
  //   expect(result).toBe('(which yarn && yarn add react-redux react-router-dom) || npm install --save react-redux react-router-dom')
  // })

  // it('install a list of dependencies | object', () => {
  //   const result = installDeps({ name: 'a' })
  //   expect(result).toBe('(which yarn && yarn) || npm install')
  // })
})
<|endoftext|>