<commit_before>/* @flow */

let IGNORED_APPS = [
  'Simulator',
];

const Layouts = {
  TALL_RIGHT: {
    name: 'Tall Right',
  }
};

// START HANDLERS

const keyHandlers: Array<KeyHandler> = [];
const eventHandlers: Array<EventHandler> = [];

const mod1 = ['alt', 'shift'];
const mod2 = ['alt', 'shift', 'ctrl'];

keyHandlers.push(Phoenix.bind('1', mod2, () => {
  const screen = Screen.currentScreen();
  performLayout(Layouts.TALL_RIGHT, { screen });
  showCenteredModalInScreen(Layouts.TALL_RIGHT.name, screen)
}));

keyHandlers.push(Phoenix.bind('i', mod1, () => {
  const app = App.launch("iTerm");
  app.focus();
}));

keyHandlers.push(Phoenix.bind('a', mod1, () => {
  const app = App.launch("Atom");
  app.focus();
}));

keyHandlers.push(Phoenix.bind('c', mod1, () => {
  const app = App.launch("Google Chrome");
  app.focus();
}));

keyHandlers.push(Phoenix.bind('return', mod1, () => {
  makePrimary(Window.focusedWindow());
}));

keyHandlers.push(Phoenix.bind('t', mod1, () => {
  const win = Window.focusedWindow();
  performLayout(Layouts.TALL_RIGHT, {
    screen: win.screen(),
    toggleIgnore: true,
    window: win,
  });
}));

keyHandlers.push(Phoenix.bind('h', mod1, () => {
  const win = Window.focusedWindow();
  performLayout(Layouts.TALL_RIGHT, {
    screen: win.screen(),
    decreaseWidth: true,
    window: win,
  });
}));

keyHandlers.push(Phoenix.bind('l', mod1, () => {
  const win = Window.focusedWindow();
  performLayout(Layouts.TALL_RIGHT, {
    screen: win.screen(),
    increaseWidth: true,
    window: win,
  });
}));

keyHandlers.push(Phoenix.bind('j', mod2, () => {
  performLayout(Layouts.TALL_RIGHT, {
    screen: Screen.currentScreen(),
    window: Window.focusedWindow(),
    moveWindowRight: true
  });
}));

keyHandlers.push(Phoenix.bind('k', mod2, () => {
  performLayout(Layouts.TALL_RIGHT, {
    screen: Screen.currentScreen(),
    window: Window.focusedWindow(),
    moveWindowLeft: true
  });
}));

keyHandlers.push(Phoenix.bind('j', mod1, () => {
  const fwin = Window.focusedWindow();
  fwin.screen().focusWindowToEast(fwin);
}));

keyHandlers.push(Phoenix.bind('k', mod1, () => {
  const fwin = Window.focusedWindow();
  fwin.screen().focusWindowToWest(fwin);
}));

eventHandlers.push(Phoenix.on('windowDidClose', (window: Window) => {
  performLayout(Layouts.TALL_RIGHT, {screen: Screen.currentScreen()});
}));

eventHandlers.push(Phoenix.on('windowDidOpen', (window: Window) => {
  performLayout(Layouts.TALL_RIGHT, { screen: Screen.currentScreen() });
}));

eventHandlers.push(Phoenix.on('windowDidResize', (window: Window) => {
  performLayout(Layouts.TALL_RIGHT, {screen: Screen.currentScreen()});
}));

// END HANDLERS

function showCenteredModalInScreen(message: string, screen: Screen) {
  const m = new Modal();
  m.duration = 1;
  m.message = message;

  const { width: mw, height: mh} = m.frame();
  const { width: sw, height: sh} = screen.visibleFrameInRectangle();

  const mx = (sw / 2) - (mw / 2);
  const my = (sh / 2) - (mh / 2);

  m.origin = {x: mx, y: my};

  m.show();
}

function makePrimary(window: Window) {
  performLayout(Layouts.TALL_RIGHT, {
    screen: window.screen(),
    primaryWindow: window,
  });
}

type Layout = {name: string};

function performLayout(layout: Layout, options) {
  const layoutFn = getLayoutFn(layout);

  // Toggle ignoring a window
  if (options.toggleIgnore && options.window) {
    const whash = options.window.hash();
    const widx = performLayout.ignoredWindows.indexOf(whash);
    widx >= 0 ? performLayout.ignoredWindows.splice(widx, 1)
      : performLayout.ignoredWindows.push(whash);
  }

  // Filter out ignored apps and windows
  let windows = options.screen.visibleWindows()
    .filter(w => {
      const appName = w.app().name();
      if (IGNORED_APPS.some(n => appName === n)) {
        return false;
      }
      if (performLayout.ignoredWindows.some(h => w.hash() ===h)) {
        return false;
      }
      return true;
    });
  layoutFn(windows, options);
}

performLayout.ignoredWindows = [];

function getLayoutFn(layout: Layout) {
  return layoutTallRight;
}

function layoutTallRight(windows: Array<Window>, options: Object) {
  const screen = options.screen;
  const shash = screen.hash();
  const {
    primaryWindow,
    increaseWidth,
    decreaseWidth,
    moveWindowLeft,
    moveWindowRight,
    window,
  } = options;

  const phash = primaryWindow && primaryWindow.hash();

  let winRatios = layoutTallRight.winRatios[shash];

  // TODO: make immutable
  // sort windows left to right, put priority win on far right
  windows.sort((a: Window, b: Window) => {
    var aFrame = a.frame(), bFrame = b.frame();
    if (a.isEqual(primaryWindow)) {
      return 1;
    } else if (b.isEqual(primaryWindow)) {
      return -1;
    }
    return aFrame.x - bFrame.x;
  });

  const numWindows = windows.length;

  // full-screen for 1 window
  if (numWindows === 1) {
    const w = windows[0];
    w.setFrame(screen.visibleFrameInRectangle());
    return;
  }

  if (window && moveWindowLeft || moveWindowRight) {
    const win1 = windows.filter(w => w.isEqual(window))[0];
    const idx = windows.indexOf(win1);
    const newIdx = (moveWindowLeft ? idx + 1
      : (idx || numWindows) - 1) % numWindows;
    const nwin = windows[newIdx];
    windows[idx] = nwin;
    windows[newIdx] = window;
  }

  const {
    x: sx, y: sy,
    width: swidth, height: sheight
  } = screen.visibleFrameInRectangle();

  if (window && increaseWidth || decreaseWidth) {
    const ratioStep = 0.03;
    const minRatio = 0.05;
    const maxRatio = 0.95 - ((windows.length - 1) * minRatio);

    const whash = window.hash();
    let wratio = winRatios[whash] ||
      (window.size().width / screen.visibleFrameInRectangle().width);
    wratio += increaseWidth ? ratioStep : -ratioStep;
    wratio = Math.min(Math.max(wratio, minRatio), maxRatio);
    winRatios[whash] = wratio;

    const totalRatios = Object.keys(winRatios)
      .map(k => winRatios[k])
      .reduce((o,v,i) => o + v, 0);

    if (totalRatios > maxRatio) {
      let delta = (totalRatios - maxRatio) / (winRatios.length - 1);
      Object.keys(winRatios).forEach(h => {
        if (h === whash) return;
        if (minRatio > winRatios[h] - delta) {
          delta += winRatios[h] - minRatio;
          winRatios[h] = minRatio;
        }
      });
      Object.keys(winRatios).forEach(h => {
        if (h === whash) return;
        if (winRatios[h] - delta > minRatio) {
          winRatios[h] -= delta;
        }
      });
    }

    layoutTallRight.winRatios[shash] = winRatios;
  }

  const winWidths = {};
  let totalWinWidths = 0;
  Object.keys(winRatios).forEach(h => {
    const r = winRatios[h];
    const w = Math.round(swidth * r);
    winWidths[h] = w;
    totalWinWidths += w;
  });

  const winWidth = (swidth - totalWinWidths) /
    Math.max(1, numWindows - Object.keys(winRatios).length);

  let cx = sx;
  windows.forEach((w: Window, i: number) => {
    const x = cx, y = sy, width = winWidths[w.hash()] || winWidth;
    cx += width;
    const newFrame = {
      x, y, height: sheight,
      width: width
    };
    w.setFrame(newFrame);
    // Phoenix.log('\n' + w.title() + '\n\t' + JSON.stringify(newFrame));
  });
}

layoutTallRight.winRatios = [];
Screen.screens().forEach(s => {
  layoutTallRight.winRatios[s.hash()] = { /* win-hash : ratio */ };
});

// START POLYFILLS

// $FlowFixMe polyfill
Screen.currentScreen = function(): Screen {
  const fwin = Window.focusedWindow();
  return fwin.screen();
}

// $FlowFixMe polyfill
Screen.prototype.visibleWindows = function(): Array<Window> {
  return Window.visibleWindows().filter(w => this.isEqual(w.screen()));
};

// $FlowFixMe polyfill
Screen.prototype.focusWindowToEast = function(window: Window): boolean {
  const windows = this.visibleWindows();

  // sort windows left to right
  windows.sort((a: Window, b: Window) => {
    var aFrame = a.frame(), bFrame = b.frame();
    return aFrame.x - bFrame.x;
  });

  const idx = windows.map(w => w.hash()).indexOf(window.hash());
  const newIdx = (idx || windows.length) - 1 % windows.length;

  return windows[newIdx].focus();
}

// $FlowFixMe polyfill
Screen.prototype.focusWindowToWest = function(window: Window): boolean {
  const windows = this.visibleWindows();

  // sort windows left to right
  windows.sort((a: Window, b: Window) => {
    var aFrame = a.frame(), bFrame = b.frame();
    return aFrame.x - bFrame.x;
  });

  const idx = windows.map(w => w.hash()).indexOf(window.hash());
  const newIdx = (idx + 1) % windows.length;

  return windows[newIdx].focus();
}

// END POLYFILLS

// FLOW HACKS

// Flow bug with not prioritizing libs
declare class Screen extends Identifiable {
  static currentScreen(): Screen;
  static screens(): Array<Screen>;
  screen(): Screen;
  visibleFrameInRectangle(): Rectangle;
  visibleWindows(): Array<Window>;
}
<commit_msg>Bug fix resize focused windows<commit_after>/* @flow */

let IGNORED_APPS = [
  'Simulator',
];

const Layouts = {
  TALL_RIGHT: {
    name: 'Tall Right',
  }
};

// DEBUG

function debug(o: any) {
  Phoenix.log(JSON.stringify(o));
}

// START HANDLERS

const keyHandlers: Array<KeyHandler> = [];
const eventHandlers: Array<EventHandler> = [];

const mod1 = ['alt', 'shift'];
const mod2 = ['alt', 'shift', 'ctrl'];

keyHandlers.push(Phoenix.bind('1', mod2, () => {
  const screen = Screen.currentScreen();
  performLayout(Layouts.TALL_RIGHT, { screen });
  showCenteredModalInScreen(Layouts.TALL_RIGHT.name, screen)
}));

keyHandlers.push(Phoenix.bind('i', mod1, () => {
  const app = App.launch("iTerm");
  app.focus();
}));

keyHandlers.push(Phoenix.bind('a', mod1, () => {
  const app = App.launch("Atom");
  app.focus();
}));

keyHandlers.push(Phoenix.bind('c', mod1, () => {
  const app = App.launch("Google Chrome");
  app.focus();
}));

keyHandlers.push(Phoenix.bind('return', mod1, () => {
  makePrimary(Window.focusedWindow());
}));

keyHandlers.push(Phoenix.bind('t', mod1, () => {
  const win = Window.focusedWindow();
  performLayout(Layouts.TALL_RIGHT, {
    screen: win.screen(),
    toggleIgnore: true,
    window: win,
  });
}));

keyHandlers.push(Phoenix.bind('h', mod1, () => {
  const win = Window.focusedWindow();
  performLayout(Layouts.TALL_RIGHT, {
    screen: win.screen(),
    decreaseWidth: true,
    window: win,
  });
}));

keyHandlers.push(Phoenix.bind('l', mod1, () => {
  const win = Window.focusedWindow();
  performLayout(Layouts.TALL_RIGHT, {
    screen: win.screen(),
    increaseWidth: true,
    window: win,
  });
}));

keyHandlers.push(Phoenix.bind('j', mod2, () => {
  performLayout(Layouts.TALL_RIGHT, {
    screen: Screen.currentScreen(),
    window: Window.focusedWindow(),
    moveWindowRight: true
  });
}));

keyHandlers.push(Phoenix.bind('k', mod2, () => {
  performLayout(Layouts.TALL_RIGHT, {
    screen: Screen.currentScreen(),
    window: Window.focusedWindow(),
    moveWindowLeft: true
  });
}));

keyHandlers.push(Phoenix.bind('j', mod1, () => {
  const fwin = Window.focusedWindow();
  fwin.screen().focusWindowToEast(fwin);
}));

keyHandlers.push(Phoenix.bind('k', mod1, () => {
  const fwin = Window.focusedWindow();
  fwin.screen().focusWindowToWest(fwin);
}));

eventHandlers.push(Phoenix.on('windowDidClose', (window: Window) => {
  performLayout(Layouts.TALL_RIGHT, {screen: Screen.currentScreen()});
}));

eventHandlers.push(Phoenix.on('windowDidOpen', (window: Window) => {
  performLayout(Layouts.TALL_RIGHT, { screen: Screen.currentScreen() });
}));

eventHandlers.push(Phoenix.on('windowDidResize', (window: Window) => {
  performLayout(Layouts.TALL_RIGHT, {screen: Screen.currentScreen()});
}));

// END HANDLERS

function showCenteredModalInScreen(message: string, screen: Screen) {
  const m = new Modal();
  m.duration = 1;
  m.message = message;

  const { width: mw, height: mh} = m.frame();
  const { width: sw, height: sh} = screen.visibleFrameInRectangle();

  const mx = (sw / 2) - (mw / 2);
  const my = (sh / 2) - (mh / 2);

  m.origin = {x: mx, y: my};

  m.show();
}

function makePrimary(window: Window) {
  performLayout(Layouts.TALL_RIGHT, {
    screen: window.screen(),
    primaryWindow: window,
  });
}

type Layout = {name: string};

function performLayout(layout: Layout, options) {
  const layoutFn = getLayoutFn(layout);

  // Toggle ignoring a window
  if (options.toggleIgnore && options.window) {
    const whash = options.window.hash();
    const widx = performLayout.ignoredWindows.indexOf(whash);
    widx >= 0 ? performLayout.ignoredWindows.splice(widx, 1)
      : performLayout.ignoredWindows.push(whash);
  }

  // Filter out ignored apps and windows
  let windows = options.screen.visibleWindows()
    .filter(w => {
      const appName = w.app().name();
      if (IGNORED_APPS.some(n => appName === n)) {
        return false;
      }
      if (performLayout.ignoredWindows.some(h => w.hash() ===h)) {
        return false;
      }
      return true;
    });
  layoutFn(windows, options);
}

performLayout.ignoredWindows = [];

function getLayoutFn(layout: Layout) {
  return layoutTallRight;
}

function layoutTallRight(windows: Array<Window>, options: Object) {
  const screen = options.screen;
  const numWindows = windows.length;

  // Return early if we only have one window
  if (numWindows === 1) {
    const w = windows[0];
    w.setFrame(screen.visibleFrameInRectangle());
    return;
  }

  const sHash = screen.hash();
  const {
    primaryWindow,
    increaseWidth,
    decreaseWidth,
    moveWindowLeft,
    moveWindowRight,
  } = options;

  const {
    x: sX, y: sY,
    width: sWidth, height: sHeight
  } = screen.visibleFrameInRectangle();

  // TODO: make immutable
  // sort windows left to right, put priority win on far right
  windows.sort((a: Window, b: Window) => {
    var aFrame = a.frame(), bFrame = b.frame();
    if (a.isEqual(primaryWindow)) {
      return 1;
    } else if (b.isEqual(primaryWindow)) {
      return -1;
    }
    return aFrame.x - bFrame.x;
  });

  // Move focused window left or right
  if (options.window && moveWindowLeft || moveWindowRight) {
    const window = options.window;
    const win1 = windows.filter(w => w.isEqual(window))[0];
    const idx = windows.indexOf(win1);
    const newIdx = (moveWindowLeft ? idx + 1
      : (idx || numWindows) - 1) % numWindows;
    const nwin = windows[newIdx];
    windows[idx] = nwin;
    windows[newIdx] = window;
  }

  // Resize focused window
  if (options.window && increaseWidth || decreaseWidth) {
    const window = options.window;
    const { width: wWidth, height: wHeight } = window.size();

    const minRatio = 0.16;
    const widthStep = 0.04;

    const numFlowWindows = numWindows - getNumSpecWindows(screen);
    const totalSpecRatio = getTotalSpecRatio(screen);

    const wSpecRatio = getSpecRatios(screen)[window.hash()] || 0;
    // Do not allow specifying all windows as spec windows
    // Only allow up to numWindows - 1 or already specified windows
    if (numFlowWindows > 1 || wSpecRatio) {
      const wCurrentRatio = wSpecRatio || wWidth / sWidth;
      const maxRatio  = 1 - (totalSpecRatio - wSpecRatio) - (minRatio * numFlowWindows);

      const tmpRatio = wCurrentRatio + (increaseWidth ? widthStep : -widthStep);
      const wNewRatio = Math.max(minRatio, Math.min(maxRatio, tmpRatio));

      debug({ wNewRatio });

      setSpecRatio(screen, window, wNewRatio);
    } else {
      // TOOD implement resizing of spec windows
      // - If there are *no* windows to flow, we must steal from specified windows
      //  - [ ] your minimum is minRatio
      //  - [ ] your maximum is 1 - (total ratios - yourself)
      //  - [ ] when descreasing in size, redistribute ratio evenly to other windows
      //  - [ ] when increasing in size, steal ratio evenly from other windows
    }
  }

  const specRatios = getSpecRatios(screen);
  const specRatioList = Object.keys(specRatios).map(hash => specRatios[hash]);
  const specWidthMap = {};
  const totalWinWidths = Object.keys(specRatios).reduce((t, hash) => {
    const width = Math.round(specRatios[hash] * sWidth);
    specWidthMap[hash] = width;
    return t += width;
  }, 0);

  const flowWidth = (sWidth - totalWinWidths) /
    Math.max(1, numWindows - getNumSpecWindows(screen));

  let cX = sX;
  windows.forEach((w: Window, i: number) => {
    const x = cX, y = sY, width = specWidthMap[w.hash()] || flowWidth;
    cX += width;
    const newFrame = {
      x, y, height: sHeight,
      width: width
    };
    w.setFrame(newFrame);
    // debug({ newFrame });
  });
}

layoutTallRight.winRatios = [];
Screen.screens().forEach(s => {
  layoutTallRight.winRatios[s.hash()] = { /* win-hash : ratio */ };
});

function getSpecRatios(screenOrHash: Screen|number): Object {
  const sHash = typeof screenOrHash === 'number' ? screenOrHash : screenOrHash.hash();
  return layoutTallRight.winRatios[sHash];
}

function getNumSpecWindows(screenOrHash: Screen|number): number {
  const sHash = typeof screenOrHash === 'number' ? screenOrHash : screenOrHash.hash();
  return Object.keys(getSpecRatios(screenOrHash)).length;
}

function getTotalSpecRatio(screenOrHash: Screen|number): number {
  const sHash = typeof screenOrHash === 'number' ? screenOrHash : screenOrHash.hash();
  const specRatios = getSpecRatios(screenOrHash);
  return Object.keys(specRatios)
    .map(hash => specRatios[hash])
    .reduce((t, r) => t + r, 0);
}

function setSpecRatio(screenOrHash: Screen|number, windowOrHash: Window|number, ratio: number) {
  const sHash = typeof screenOrHash === 'number' ? screenOrHash : screenOrHash.hash();
  const wHash = typeof windowOrHash === 'number' ? windowOrHash : windowOrHash.hash();
  layoutTallRight.winRatios[sHash][wHash] = ratio;
}

// START POLYFILLS

// $FlowFixMe polyfill
Screen.currentScreen = function(): Screen {
  const fwin = Window.focusedWindow();
  return fwin.screen();
}

// $FlowFixMe polyfill
Screen.prototype.visibleWindows = function(): Array<Window> {
  return Window.visibleWindows().filter(w => this.isEqual(w.screen()));
};

// $FlowFixMe polyfill
Screen.prototype.focusWindowToEast = function(window: Window): boolean {
  const windows = this.visibleWindows();

  // sort windows left to right
  windows.sort((a: Window, b: Window) => {
    var aFrame = a.frame(), bFrame = b.frame();
    return aFrame.x - bFrame.x;
  });

  const idx = windows.map(w => w.hash()).indexOf(window.hash());
  const newIdx = (idx || windows.length) - 1 % windows.length;

  return windows[newIdx].focus();
}

// $FlowFixMe polyfill
Screen.prototype.focusWindowToWest = function(window: Window): boolean {
  const windows = this.visibleWindows();

  // sort windows left to right
  windows.sort((a: Window, b: Window) => {
    var aFrame = a.frame(), bFrame = b.frame();
    return aFrame.x - bFrame.x;
  });

  const idx = windows.map(w => w.hash()).indexOf(window.hash());
  const newIdx = (idx + 1) % windows.length;

  return windows[newIdx].focus();
}

// END POLYFILLS

// FLOW HACKS

// Flow bug with not prioritizing libs
declare class Screen extends Identifiable {
  static currentScreen(): Screen;
  static screens(): Array<Screen>;
  screen(): Screen;
  visibleFrameInRectangle(): Rectangle;
  visibleWindows(): Array<Window>;
}
<|endoftext|>


<commit_before>// Official roles GET controllers

'use strict';

var aFrom               = require('es5-ext/array/from')
  , flatten             = require('es5-ext/array/#/flatten')
  , remove              = require('es5-ext/array/#/remove')
  , uniq                = require('es5-ext/array/#/uniq')
  , isNaturalNumber     = require('es5-ext/number/is-natural')
  , toNaturalNumber     = require('es5-ext/number/to-pos-integer')
  , normalizeOptions    = require('es5-ext/object/normalize-options')
  , toArray             = require('es5-ext/object/to-array')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , includes            = require('es5-ext/string/#/contains')
  , d                   = require('d')
  , ensureSet           = require('es6-set/valid-set')
  , deferred            = require('deferred')
  , memoize             = require('memoizee')
  , serializeValue      = require('dbjs/_setup/serialize/value')
  , unserializeValue    = require('dbjs/_setup/unserialize/value')
  , ObservableSet       = require('observable-set/primitive')
  , mano                = require('mano')
  , QueryHandler        = require('../../utils/query-handler')
  , defaultItemsPerPage = require('../../conf/objects-list-items-per-page')
  , getDbSet            = require('../utils/get-db-set')
  , getDbArray          = require('../utils/get-db-array')
  , getIndexMap         = require('../utils/get-db-sort-index-map')

  , hasBadWs = RegExp.prototype.test.bind(/\s{2,}/)
  , compareStamps = function (a, b) { return a.stamp - b.stamp; }
  , db = mano.db
  , isArray = Array.isArray, slice = Array.prototype.slice, push = Array.prototype.push
  , ceil = Math.ceil, create = Object.create
  , defineProperty = Object.defineProperty, stringify = JSON.stringify;

var compareIndexMeta = function (meta1, meta2) {
	return meta1.name.localeCompare(meta2.name) || meta1.value.localeCompare(meta2.value);
};

// Business processes table query handler
var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

// Single business process full data query handler
var getBusinessProcessQueryHandler = function (indexName) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				if (!value) throw new Error("Missing id");
				return mano.dbDriver.getComputed(value + '/' + indexName)(function (data) {
					if (!data || (data.value !== '11')) return null;
					return value;
				});
			}
		}
	]);
};

var getFilteredSet = memoize(function (baseSet, filterString) {
	var set = new ObservableSet(), baseSetListener, indexListener
	  , def = deferred(), count = 0, isInitialized = false;
	var filter = function (ownerId, data) {
		var value = unserializeValue(data.value);
		if (value && includes.call(value, filterString)) set.add(ownerId);
		else set.delete(ownerId);
	};
	var findAndFilter = function (ownerId) {
		return mano.dbDriver.getComputed(ownerId + '/searchString').aside(function (data) {
			if (!baseSet.has(ownerId)) return;
			filter(ownerId, data);
		});
	};
	baseSet.on('change', baseSetListener = function (event) {
		if (event.type === 'add') findAndFilter(event.value).done();
		else set.delete(event.value);
	});
	mano.dbDriver.on('computed:searchString', indexListener = function (event) {
		if (!baseSet.has(event.ownerId)) return;
		filter(event.ownerId, event.data);
	});
	baseSet.forEach(function (ownerId) {
		++count;
		findAndFilter(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(set);
		});
	});
	isInitialized = true;
	if (!count) def.resolve(set);
	defineProperty(set, '_dispose', d(function () {
		baseSet.off(baseSetListener);
		mano.dbDriver.off('computed:searchString', indexListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (set) { set._dispose(); } });

var getDbArrayLru = memoize(function (set, sortIndexName) {
	var arr = [], itemsMap = getIndexMap(sortIndexName)
	  , count = 0, isInitialized = false, def = deferred(), setListener, itemsListener;
	var add = function (ownerId) {
		return deferred(itemsMap[ownerId] || mano.dbDriver.getComputed(ownerId + '/' + sortIndexName))
			.aside(function (data) {
				if (!set.has(ownerId)) return;
				if (!itemsMap[ownerId]) itemsMap[ownerId] = { id: ownerId, stamp: data.stamp };
				arr.push(itemsMap[ownerId]);
				if (def.resolved) arr.sort(compareStamps);
			});
	};
	set.on('change', setListener = function (event) {
		if (event.type === 'add') add(event.value).done();
		else remove.call(arr, itemsMap[event.value]);
	});
	itemsMap.on('update', itemsListener = function (event) {
		if (!set.has(event.ownerId)) return;
		if (def.resolved) arr.sort(compareStamps);
	});
	set.forEach(function (ownerId) {
		++count;
		add(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(arr.sort(compareStamps));
		});
	});
	isInitialized = true;
	if (!count) def.resolve(arr.sort(compareStamps));
	defineProperty(set, '_dispose', d(function () {
		set.off(setListener);
		itemsMap.off(itemsListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (arr) { arr._dispose(); } });

module.exports = exports = function (conf) {
	conf = normalizeOptions(ensureObject(conf));
	var roleName = ensureString(conf.roleName)
	  , statusIndexName = ensureString(conf.statusIndexName)
	  , allIndexName = ensureString(conf.allIndexName)
	  , bpListProps = ensureSet(conf.listProperties)
	  , bpListComputedProps = conf.listComputedProperties && aFrom(conf.listComputedProperties)
	  , tableQueryHandler = getTableQueryHandler(ensureObject(conf.statusMap))
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(conf.allIndexName)
	  , itemsPerPage = toNaturalNumber(conf.itemsPerPage) || defaultItemsPerPage
	  , indexes;

	if (conf.resolveCollectionMeta != null) ensureCallable(conf.resolveCollectionMeta);

	if (bpListComputedProps) {
		indexes = [];
		deferred.map(bpListComputedProps, function (keyPath) {
			return mano.dbDriver.indexKeyPath(keyPath)(function (map) {
				indexes.push({ keyPath: keyPath, map: map });
			});
		});
	}

	var getTableData = memoize(function (query) {
		var indexMeta = exports.getIndexMeta(query, conf), promise;
		if (isArray(indexMeta)) {
			promise = deferred.map(indexMeta.sort(compareIndexMeta), function (indexMeta) {
				return getDbSet('computed', indexMeta.name, indexMeta.value);
			})(function (sets) {
				return aFrom(sets).reduce(function (set1, set2) { return set1.and(set2); });
			});
		} else {
			promise = getDbSet('computed', indexMeta.name, indexMeta.value);
		}
		return promise(function (baseSet) {
			if (!query.search) return getDbArray(baseSet, 'computed', allIndexName);
			return deferred.map(query.search.split(/\s+/).sort(), function (value) {
				return getFilteredSet(baseSet, value)(function (set) {
					return getDbArrayLru(set, allIndexName);
				});
			})(function (arrays) {
				if (arrays.length === 1) return arrays[0];
				return uniq.call(arrays.reduce(function (current, next, index) {
					if (index === 1) current = aFrom(current);
					push.apply(current, next);
					return current;
				})).sort(compareStamps);
			});
		})(function (arr) {
			var size = arr.length, pageCount, offset, computedEvents, directEvents, statuses, statusMap;
			if (!size) return { size: size };
			pageCount = ceil(size / itemsPerPage);
			if (query.page > pageCount) return { size: size };

			// Pagination
			offset = (query.page - 1) * itemsPerPage;
			arr = slice.call(arr, offset, offset + itemsPerPage);
			if (bpListComputedProps) {
				computedEvents = deferred.map(arr, function (data) {
					var objId = data.id;
					return deferred.map(bpListComputedProps, function (keyPath) {
						return mano.dbDriver.getComputed(objId + '/' + keyPath)(function (data) {
							if (isArray(data.value)) {
								return data.value.map(function (data) {
									var key = data.key ? '*' + data.key : '';
									return data.stamp + '.' + objId + '/' + keyPath + key + '.' + data.value;
								});
							}
							return data.stamp + '.' + objId + '/' + keyPath + '.' + data.value;
						});
					});
				});
			} else {
				computedEvents = [];
			}
			directEvents = deferred.map(arr, function (data) {
				return mano.dbDriver.getDirectObject(data.id, { keyPaths: bpListProps })(function (datas) {
					return datas.map(function (data) {
						return data.data.stamp + '.' + data.id + '.' + data.data.value;
					});
				});
			});
			if (!query.status) {
				statusMap = create(null);
				statuses = deferred.map(arr, function (data) {
					return mano.dbDriver.getComputed(data.id + '/' + statusIndexName)
						.aside(function (record) {
							statusMap[data.id] = record ? unserializeValue(record.value) : null;
						});
				})(statusMap);
			}
			return deferred(directEvents, computedEvents, statuses)
				.spread(function (directEvents, computedEvents, statusMap) {
					return {
						view: arr.map(function (data) { return data.stamp + '.' + data.id; }).join('\n'),
						size: size,
						data: flatten.call([directEvents, computedEvents]),
						statusMap: statusMap
					};
				});
		});
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		'get-business-processes-view': function (query) {
			// Get snapshot of business processes table page
			return tableQueryHandler.resolve(query)(function (query) { return getTableData(query); });
		},
		'get-business-process-data': function (query) {
			// Get full data of one of the business processeses
			return businessProcessQueryHandler.resolve(query)(function (query) {
				if (!query.id) return { passed: false };
				// Put business process to top in visitedBusinessProcesses LRU queue
				db.User.getById(this.req.$user).visitedBusinessProcesses[roleName]
					.add(db.BusinessProcess.getById(query.id));
				return { passed: true };
			}.bind(this));
		}
	};
};

exports.getIndexMeta = function (query, conf) {
	var meta;
	if (query.status) {
		if (conf.resolveCollectionMeta) {
			meta = conf.resolveCollectionMeta(query.status);
			return { name: meta.name, value: serializeValue(meta.value) };
		}
		return { name: conf.statusIndexName, value: serializeValue(query.status) };
	}
	return { name: conf.allIndexName, value: '11' };
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, {
	name: 'search',
	ensure: function (value) {
		if (!value) return;
		if (value.toLowerCase() !== value) throw new Error("Unexpected search value");
		if (hasBadWs(value)) throw new Error("Unexpected search value");
		if (value !== uniq.call(value.split(/\s/)).join(' ')) {
			throw new Error("Unexpected search value");
		}
		return value;
	}
}, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<commit_msg>Support multiple roles in official app router<commit_after>// Official roles GET controllers

'use strict';

var aFrom               = require('es5-ext/array/from')
  , flatten             = require('es5-ext/array/#/flatten')
  , remove              = require('es5-ext/array/#/remove')
  , uniq                = require('es5-ext/array/#/uniq')
  , constant            = require('es5-ext/function/constant')
  , isNaturalNumber     = require('es5-ext/number/is-natural')
  , toNaturalNumber     = require('es5-ext/number/to-pos-integer')
  , normalizeOptions    = require('es5-ext/object/normalize-options')
  , toArray             = require('es5-ext/object/to-array')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , includes            = require('es5-ext/string/#/contains')
  , uncapitalize        = require('es5-ext/string/#/uncapitalize')
  , d                   = require('d')
  , ensureSet           = require('es6-set/valid-set')
  , deferred            = require('deferred')
  , memoize             = require('memoizee')
  , serializeValue      = require('dbjs/_setup/serialize/value')
  , unserializeValue    = require('dbjs/_setup/unserialize/value')
  , ObservableSet       = require('observable-set/primitive')
  , mano                = require('mano')
  , QueryHandler        = require('../../utils/query-handler')
  , defaultItemsPerPage = require('../../conf/objects-list-items-per-page')
  , getDbSet            = require('../utils/get-db-set')
  , getDbArray          = require('../utils/get-db-array')
  , getIndexMap         = require('../utils/get-db-sort-index-map')

  , hasBadWs = RegExp.prototype.test.bind(/\s{2,}/)
  , compareStamps = function (a, b) { return a.stamp - b.stamp; }
  , db = mano.db
  , isArray = Array.isArray, slice = Array.prototype.slice, push = Array.prototype.push
  , ceil = Math.ceil, create = Object.create
  , defineProperty = Object.defineProperty, stringify = JSON.stringify;

var compareIndexMeta = function (meta1, meta2) {
	return meta1.name.localeCompare(meta2.name) || meta1.value.localeCompare(meta2.value);
};

// Business processes table query handler
var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

// Single business process full data query handler
var getBusinessProcessQueryHandler = function (indexName) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				if (!value) throw new Error("Missing id");
				return mano.dbDriver.getComputed(value + '/' + indexName)(function (data) {
					if (!data || (data.value !== '11')) return null;
					return value;
				});
			}
		}
	]);
};

var getFilteredSet = memoize(function (baseSet, filterString) {
	var set = new ObservableSet(), baseSetListener, indexListener
	  , def = deferred(), count = 0, isInitialized = false;
	var filter = function (ownerId, data) {
		var value = unserializeValue(data.value);
		if (value && includes.call(value, filterString)) set.add(ownerId);
		else set.delete(ownerId);
	};
	var findAndFilter = function (ownerId) {
		return mano.dbDriver.getComputed(ownerId + '/searchString').aside(function (data) {
			if (!baseSet.has(ownerId)) return;
			filter(ownerId, data);
		});
	};
	baseSet.on('change', baseSetListener = function (event) {
		if (event.type === 'add') findAndFilter(event.value).done();
		else set.delete(event.value);
	});
	mano.dbDriver.on('computed:searchString', indexListener = function (event) {
		if (!baseSet.has(event.ownerId)) return;
		filter(event.ownerId, event.data);
	});
	baseSet.forEach(function (ownerId) {
		++count;
		findAndFilter(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(set);
		});
	});
	isInitialized = true;
	if (!count) def.resolve(set);
	defineProperty(set, '_dispose', d(function () {
		baseSet.off(baseSetListener);
		mano.dbDriver.off('computed:searchString', indexListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (set) { set._dispose(); } });

var getDbArrayLru = memoize(function (set, sortIndexName) {
	var arr = [], itemsMap = getIndexMap(sortIndexName)
	  , count = 0, isInitialized = false, def = deferred(), setListener, itemsListener;
	var add = function (ownerId) {
		return deferred(itemsMap[ownerId] || mano.dbDriver.getComputed(ownerId + '/' + sortIndexName))
			.aside(function (data) {
				if (!set.has(ownerId)) return;
				if (!itemsMap[ownerId]) itemsMap[ownerId] = { id: ownerId, stamp: data.stamp };
				arr.push(itemsMap[ownerId]);
				if (def.resolved) arr.sort(compareStamps);
			});
	};
	set.on('change', setListener = function (event) {
		if (event.type === 'add') add(event.value).done();
		else remove.call(arr, itemsMap[event.value]);
	});
	itemsMap.on('update', itemsListener = function (event) {
		if (!set.has(event.ownerId)) return;
		if (def.resolved) arr.sort(compareStamps);
	});
	set.forEach(function (ownerId) {
		++count;
		add(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(arr.sort(compareStamps));
		});
	});
	isInitialized = true;
	if (!count) def.resolve(arr.sort(compareStamps));
	defineProperty(set, '_dispose', d(function () {
		set.off(setListener);
		itemsMap.off(itemsListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (arr) { arr._dispose(); } });

var initializeHandler = function (conf) {
	conf = normalizeOptions(ensureObject(conf));
	var statusIndexName = ensureString(conf.statusIndexName)
	  , allIndexName = ensureString(conf.allIndexName)
	  , bpListProps = ensureSet(conf.listProperties)
	  , bpListComputedProps = conf.listComputedProperties && aFrom(conf.listComputedProperties)
	  , tableQueryHandler = getTableQueryHandler(ensureObject(conf.statusMap))
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(conf.allIndexName)
	  , itemsPerPage = toNaturalNumber(conf.itemsPerPage) || defaultItemsPerPage
	  , indexes;

	ensureString(conf.roleName);
	if (conf.resolveCollectionMeta != null) ensureCallable(conf.resolveCollectionMeta);

	if (bpListComputedProps) {
		indexes = [];
		deferred.map(bpListComputedProps, function (keyPath) {
			return mano.dbDriver.indexKeyPath(keyPath)(function (map) {
				indexes.push({ keyPath: keyPath, map: map });
			});
		});
	}

	var getTableData = memoize(function (query) {
		var indexMeta = exports.getIndexMeta(query, conf), promise;
		if (isArray(indexMeta)) {
			promise = deferred.map(indexMeta.sort(compareIndexMeta), function (indexMeta) {
				return getDbSet('computed', indexMeta.name, indexMeta.value);
			})(function (sets) {
				return aFrom(sets).reduce(function (set1, set2) { return set1.and(set2); });
			});
		} else {
			promise = getDbSet('computed', indexMeta.name, indexMeta.value);
		}
		return promise(function (baseSet) {
			if (!query.search) return getDbArray(baseSet, 'computed', allIndexName);
			return deferred.map(query.search.split(/\s+/).sort(), function (value) {
				return getFilteredSet(baseSet, value)(function (set) {
					return getDbArrayLru(set, allIndexName);
				});
			})(function (arrays) {
				if (arrays.length === 1) return arrays[0];
				return uniq.call(arrays.reduce(function (current, next, index) {
					if (index === 1) current = aFrom(current);
					push.apply(current, next);
					return current;
				})).sort(compareStamps);
			});
		})(function (arr) {
			var size = arr.length, pageCount, offset, computedEvents, directEvents, statuses, statusMap;
			if (!size) return { size: size };
			pageCount = ceil(size / itemsPerPage);
			if (query.page > pageCount) return { size: size };

			// Pagination
			offset = (query.page - 1) * itemsPerPage;
			arr = slice.call(arr, offset, offset + itemsPerPage);
			if (bpListComputedProps) {
				computedEvents = deferred.map(arr, function (data) {
					var objId = data.id;
					return deferred.map(bpListComputedProps, function (keyPath) {
						return mano.dbDriver.getComputed(objId + '/' + keyPath)(function (data) {
							if (isArray(data.value)) {
								return data.value.map(function (data) {
									var key = data.key ? '*' + data.key : '';
									return data.stamp + '.' + objId + '/' + keyPath + key + '.' + data.value;
								});
							}
							return data.stamp + '.' + objId + '/' + keyPath + '.' + data.value;
						});
					});
				});
			} else {
				computedEvents = [];
			}
			directEvents = deferred.map(arr, function (data) {
				return mano.dbDriver.getDirectObject(data.id, { keyPaths: bpListProps })(function (datas) {
					return datas.map(function (data) {
						return data.data.stamp + '.' + data.id + '.' + data.data.value;
					});
				});
			});
			if (!query.status) {
				statusMap = create(null);
				statuses = deferred.map(arr, function (data) {
					return mano.dbDriver.getComputed(data.id + '/' + statusIndexName)
						.aside(function (record) {
							statusMap[data.id] = record ? unserializeValue(record.value) : null;
						});
				})(statusMap);
			}
			return deferred(directEvents, computedEvents, statuses)
				.spread(function (directEvents, computedEvents, statusMap) {
					return {
						view: arr.map(function (data) { return data.stamp + '.' + data.id; }).join('\n'),
						size: size,
						data: flatten.call([directEvents, computedEvents]),
						statusMap: statusMap
					};
				});
		});
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		tableQueryHandler: tableQueryHandler,
		getTableData: getTableData,
		businessProcessQueryHandler: businessProcessQueryHandler
	};
};

module.exports = exports = function (mainConf) {
	var resolveHandler;
	if (isArray(mainConf)) {
		resolveHandler = (function () {
			var map = mainConf.reduce(function (map, conf) {
				map[conf.roleName] = initializeHandler(conf);
			}, create(null));
			return function (userId) {
				var handler, roleName = uncapitalize.call(db.User.getById(userId)
					.currentRoleResolved.slice('official'.length));
				handler = map[roleName];
				if (!handler) throw new Error("Cannot resolve conf for role name: " + stringify(roleName));
				return handler;
			};
		}());
	} else {
		resolveHandler = constant(initializeHandler(mainConf));
	}
	return {
		'get-business-processes-view': function (query) {
			var handler = resolveHandler(this.req.$user);
			// Get snapshot of business processes table page
			return handler.tableQueryHandler.resolve(query)(function (query) {
				return handler.getTableData(query);
			});
		},
		'get-business-process-data': function (query) {
			var handler = resolveHandler(this.req.$user);
			// Get full data of one of the business processeses
			return handler.businessProcessQueryHandler.resolve(query)(function (query) {
				if (!query.id) return { passed: false };
				// Put business process to top in visitedBusinessProcesses LRU queue
				db.User.getById(this.req.$user).visitedBusinessProcesses[handler.roleName]
					.add(db.BusinessProcess.getById(query.id));
				return { passed: true };
			}.bind(this));
		}
	};
};

exports.getIndexMeta = function (query, conf) {
	var meta;
	if (query.status) {
		if (conf.resolveCollectionMeta) {
			meta = conf.resolveCollectionMeta(query.status);
			return { name: meta.name, value: serializeValue(meta.value) };
		}
		return { name: conf.statusIndexName, value: serializeValue(query.status) };
	}
	return { name: conf.allIndexName, value: '11' };
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, {
	name: 'search',
	ensure: function (value) {
		if (!value) return;
		if (value.toLowerCase() !== value) throw new Error("Unexpected search value");
		if (hasBadWs(value)) throw new Error("Unexpected search value");
		if (value !== uniq.call(value.split(/\s/)).join(' ')) {
			throw new Error("Unexpected search value");
		}
		return value;
	}
}, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<|endoftext|>


<commit_before>// Official roles GET controllers

'use strict';

var aFrom           = require('es5-ext/array/from')
  , ensureArray     = require('es5-ext/array/valid-array')
  , flatten         = require('es5-ext/array/#/flatten')
  , isNaturalNumber = require('es5-ext/number/is-natural')
  , toArray         = require('es5-ext/object/to-array')
  , ensureObject    = require('es5-ext/object/valid-object')
  , ensureCallable  = require('es5-ext/object/valid-callable')
  , ensureString    = require('es5-ext/object/validate-stringifiable-value')
  , memoize         = require('memoizee/plain')
  , ensureDatabase  = require('dbjs/valid-dbjs')
  , db              = require('mano').db
  , getCompare      = require('../../utils/get-compare')
  , getSearchFilter = require('../../utils/get-search-filter')
  , serializeView   = require('../../utils/db-view/serialize')
  , getEvents       = require('../../utils/dbjs-get-path-events')
  , QueryHandler    = require('../../utils/query-handler')

  , map = Array.prototype.map, ceil = Math.ceil, stringify = JSON.stringify
  , itemsPerPage = 50;

require('memoizee/ext/max-age');

var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

var getBusinessProcessQueryHandler = function (statusMap) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				var bp;
				if (!value) throw new Error("Missing id");
				bp = db.BusinessProcess.getById(value);
				if (!bp) return null;
				if (!statusMap.all.data.has(bp)) return null;
				return value;
			}
		}
	]);
};

module.exports = exports = function (data) {
	ensureObject(data);
	var roleName = ensureString(data.roleName)
	  , statusMap = ensureObject(data.statusMap)
	  , bpListProps = aFrom(data.listProperties)
	  , bpListComputedProps = data.listComputedProperties && aFrom(data.listComputedProperties)
	  , searchFilter = getSearchFilter(ensureArray(data.searchablePropertyNames))
	  , tableQueryHandler = getTableQueryHandler(statusMap)
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(statusMap)
	  , dbSubmitted = bpListComputedProps ? ensureDatabase(data.dbSubmitted) : null
	  , getOrderIndex = ensureCallable(data.getOrderIndex);

	var getTableData = memoize(function (query) {
		var list, pageCount, offset, size;
		// Status
		list = statusMap[query.status || 'all'].data;
		// Search
		if (query.search) list = list.filter(searchFilter(query.search));
		size = list.size;
		if (!size) return { size: size };
		pageCount = ceil(size / itemsPerPage);
		if (query.page > pageCount) return { size: size };
		// Sort
		list = list.toArray(getCompare(getOrderIndex));
		// Pagination
		offset = (query.page - 1) * itemsPerPage;
		list = list.slice(offset, offset + itemsPerPage);
		return {
			view: serializeView(list, getOrderIndex),
			size: size,
			data: flatten.call(map.call(list, function (object) {
				var subObject
				  , events = bpListProps.map(function (path) { return getEvents(object, path); });
				events.unshift(object._lastOwnEvent_);
				if (!dbSubmitted) return events;
				subObject = dbSubmitted.BusinessProcess.getById(object.__id__);
				return [
					events,
					bpListComputedProps.map(function (path) { return getEvents(subObject, path); })
				];
			})).map(String)
		};
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		'get-business-processes-view': function (query) {
			return getTableData(tableQueryHandler.resolve(query));
		},
		'get-business-process-data': function (query) {
			query = businessProcessQueryHandler.resolve(query);
			if (!query.id) return { passed: false };
			db.User.getById(this.req.$user).visitedBusinessProcesses[roleName]
				.add(db.BusinessProcess.getById(query.id));
			return { passed: true };
		}
	};
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, { name: 'search' }, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<commit_msg>Attach statusMap in case of 'all' status<commit_after>// Official roles GET controllers

'use strict';

var aFrom           = require('es5-ext/array/from')
  , ensureArray     = require('es5-ext/array/valid-array')
  , find            = require('es5-ext/array/#/find')
  , flatten         = require('es5-ext/array/#/flatten')
  , isNaturalNumber = require('es5-ext/number/is-natural')
  , toArray         = require('es5-ext/object/to-array')
  , ensureObject    = require('es5-ext/object/valid-object')
  , ensureCallable  = require('es5-ext/object/valid-callable')
  , ensureString    = require('es5-ext/object/validate-stringifiable-value')
  , memoize         = require('memoizee/plain')
  , ensureDatabase  = require('dbjs/valid-dbjs')
  , db              = require('mano').db
  , getCompare      = require('../../utils/get-compare')
  , getSearchFilter = require('../../utils/get-search-filter')
  , serializeView   = require('../../utils/db-view/serialize')
  , getEvents       = require('../../utils/dbjs-get-path-events')
  , QueryHandler    = require('../../utils/query-handler')

  , map = Array.prototype.map, ceil = Math.ceil, keys = Object.keys, stringify = JSON.stringify
  , itemsPerPage = 50;

require('memoizee/ext/max-age');

var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

var getBusinessProcessQueryHandler = function (statusMap) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				var bp;
				if (!value) throw new Error("Missing id");
				bp = db.BusinessProcess.getById(value);
				if (!bp) return null;
				if (!statusMap.all.data.has(bp)) return null;
				return value;
			}
		}
	]);
};

module.exports = exports = function (data) {
	ensureObject(data);
	var roleName = ensureString(data.roleName)
	  , statusMap = ensureObject(data.statusMap)
	  , bpListProps = aFrom(data.listProperties)
	  , bpListComputedProps = data.listComputedProperties && aFrom(data.listComputedProperties)
	  , searchFilter = getSearchFilter(ensureArray(data.searchablePropertyNames))
	  , tableQueryHandler = getTableQueryHandler(statusMap)
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(statusMap)
	  , dbSubmitted = bpListComputedProps ? ensureDatabase(data.dbSubmitted) : null
	  , getOrderIndex = ensureCallable(data.getOrderIndex)
	  , statuses = keys(statusMap).filter(function (name) { return (name !== 'all'); });

	var getTableData = memoize(function (query) {
		var list, pageCount, offset, size, result;
		// Status
		list = statusMap[query.status || 'all'].data;
		// Search
		if (query.search) list = list.filter(searchFilter(query.search));
		size = list.size;
		if (!size) return { size: size };
		pageCount = ceil(size / itemsPerPage);
		if (query.page > pageCount) return { size: size };
		// Sort
		list = list.toArray(getCompare(getOrderIndex));
		// Pagination
		offset = (query.page - 1) * itemsPerPage;
		list = list.slice(offset, offset + itemsPerPage);
		result = {
			view: serializeView(list, getOrderIndex),
			size: size,
			data: flatten.call(map.call(list, function (object) {
				var subObject
				  , events = bpListProps.map(function (path) { return getEvents(object, path); });
				events.unshift(object._lastOwnEvent_);
				if (!dbSubmitted) return events;
				subObject = dbSubmitted.BusinessProcess.getById(object.__id__);
				return [
					events,
					bpListComputedProps.map(function (path) { return getEvents(subObject, path); })
				];
			})).map(String)
		};
		if (!query.status) {
			list.forEach(function (bp) {
				this[bp.__id__] = find.call(statuses,
					function (status) { return statusMap[status].data.has(bp); });
			}, result.statusMap = {});
		}
		return result;
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		'get-business-processes-view': function (query) {
			return getTableData(tableQueryHandler.resolve(query));
		},
		'get-business-process-data': function (query) {
			query = businessProcessQueryHandler.resolve(query);
			if (!query.id) return { passed: false };
			db.User.getById(this.req.$user).visitedBusinessProcesses[roleName]
				.add(db.BusinessProcess.getById(query.id));
			return { passed: true };
		}
	};
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, { name: 'search' }, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<|endoftext|>


<commit_before>import express from 'express';
import passport from 'passport';
import mongoose from 'mongoose';
import GitHubStrategy from 'passport-github2'
import TwitterStrategy from 'passport-twitter';
import LinkedInStrategy from 'passport-linkedin';
import Session from 'express-session';
import User from '../models/user';
import dotenv from 'dotenv';
dotenv.config();

const APP_HOST = 'https://safe-cliffs-78756.herokuapp.com';
const CLIENT_URL = process.env.NODE_ENV === 'production' ? APP_HOST : 'http://localhost:3000';
const SERVER_URL = process.env.NODE_ENV === 'production' ? APP_HOST : 'http://localhost:8080';

// authentication middleware using express-session:
export const isAuthenticated = (req, res, next) => {
  if (req.user) {
    next();
  } else {
    res.redirect(`${CLIENT_URL}/login`);
  }
}

const router = express.Router();

// use MongoStore to persist sessions
var MongoStore = require('connect-mongo')(Session);
router.use(Session({
    resave: false,
    saveUninitialized: false,
    secret: process.env.SESSION_SECRET,
    cookie: { maxAge: 1000 * 60 * 60 * 8 }, // 8 hours
    store: new MongoStore({ mongooseConnection: mongoose.connection })
}));

router.use(passport.initialize());
router.use(passport.session());

passport.serializeUser(function(user, done) { done(null, user) });
passport.deserializeUser(function(user, done) { done(null, user) });

// GITHUB
passport.use(new GitHubStrategy({
  clientID: process.env.NODE_ENV === 'production' ?
    process.env.GITHUB_PROD_ID : process.env.GITHUB_CLIENT_ID,
  clientSecret: process.env.NODE_ENV === 'production' ?
    process.env.GITHUB_PROD_SECRET : process.env.GITHUB_SECRET,
  callbackURL: `${SERVER_URL}/auth/github/callback`
}, (accesstoken, refreshToken, profile, done) => {
    User.findOne({ githubId: profile.id }, (err, user) => {

      if (err) return done(err);

      if (!user) {
        // new registration: create and save user in database
        user = new User({
          githubId: profile.id,
          username: profile.username,
          personal: {
            memberSince: new Date(),
            avatarUrl: profile._json.avatar_url,
            profileUrl: profile.profileUrl,
            displayName: profile._json.name ? profile._json.name : '',
            email: profile._json.email ? profile._json.email : '',
            location: profile._json.location ? profile._json.location : '',
            bio: profile._json.bio ? profile._json.bio : '',
          },
          career: {
            company: profile._json.company ? profile._json.company : '',
          }
        });
        user.save((err) => {
          if (!err) {
            return done(err, user);
          }
        });
      } else {
        // user registered previously and exists in database
        console.log('user already exists');
        return done(err, user);
      }
    });
}));

router.get('/auth/github', passport.authenticate('github'));

router.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: `${CLIENT_URL}/login` }), ((req, res) => {
  // successfull authentication from github
  res.redirect(`${CLIENT_URL}/verify_account`);
}));

// TWITTER
passport.use(new TwitterStrategy({
  consumerKey: process.env.TWITTER_KEY,
  consumerSecret: process.env.TWITTER_SECRET,
  callbackURL: `${SERVER_URL}/connect/twitter/callback`
}, (token, tokenSecret, profile, done) => {
  return done(null, profile)
}));

router.get('/connect/twitter', isAuthenticated, passport.authorize('twitter'));

router.get('/connect/twitter/callback',
  passport.authorize('twitter', { failureRedirect: `${CLIENT_URL}/dashboard/preferences` }), ((req, res) => {
    const { user, account } = req;

    User.findOne({ githubId: user.githubId }, (err, updatedUser) => {
      if (!err) {
        updatedUser.social.twitter = account.username;
        updatedUser.save();
        res.redirect(`${CLIENT_URL}/dashboard/preferences`);
        console.log('updated user with twitter handle');
      } else {
        console.log(err);
      }
    });
}));

// LinkedIn
passport.use(new LinkedInStrategy({
  consumerKey: process.env.LINKEDIN_KEY,
  consumerSecret: process.env.LINKEDIN_SECRET,
  callbackURL: `${SERVER_URL}/connect/linkedin/callback`
}, (token, tokenSecret, profile, done) => {
  return done(null, profile)
}));

router.get('/connect/linkedin', isAuthenticated, passport.authorize('linkedin'));

router.get('/connect/linkedin/callback',
  passport.authorize('linkedin', { failureRedirect: `${CLIENT_URL}/dashboard/preferences` }), ((req, res) => {

    User.findOne({ githubId: req.user.githubId }, (err, updatedUser) => {
      if (!err) {
        updatedUser.social.linkedin = req.account.displayName;
        updatedUser.save();
        res.redirect(`${CLIENT_URL}/dashboard/preferences`);
        console.log('updated user with linkedin handle');
      } else {
        console.log(err);
      }
    });
}));

// logout user & redirect to home page
router.get('/logout', function(req, res){
  req.logout();
  res.redirect(`${CLIENT_URL}/`);
});

export default router;
<commit_msg>update app host var (#145)<commit_after>import express from 'express';
import passport from 'passport';
import mongoose from 'mongoose';
import GitHubStrategy from 'passport-github2'
import TwitterStrategy from 'passport-twitter';
import LinkedInStrategy from 'passport-linkedin';
import Session from 'express-session';
import User from '../models/user';
import dotenv from 'dotenv';
dotenv.config();

const APP_HOST = process.env.APP_HOST;
const CLIENT_URL = process.env.NODE_ENV === 'production' ? APP_HOST : 'http://localhost:3000';
const SERVER_URL = process.env.NODE_ENV === 'production' ? APP_HOST : 'http://localhost:8080';

// authentication middleware using express-session:
export const isAuthenticated = (req, res, next) => {
  if (req.user) {
    next();
  } else {
    res.redirect(`${CLIENT_URL}/login`);
  }
}

const router = express.Router();

// use MongoStore to persist sessions
var MongoStore = require('connect-mongo')(Session);
router.use(Session({
    resave: false,
    saveUninitialized: false,
    secret: process.env.SESSION_SECRET,
    cookie: { maxAge: 1000 * 60 * 60 * 8 }, // 8 hours
    store: new MongoStore({ mongooseConnection: mongoose.connection })
}));

router.use(passport.initialize());
router.use(passport.session());

passport.serializeUser(function(user, done) { done(null, user) });
passport.deserializeUser(function(user, done) { done(null, user) });

// GITHUB
passport.use(new GitHubStrategy({
  clientID: process.env.NODE_ENV === 'production' ?
    process.env.GITHUB_PROD_ID : process.env.GITHUB_CLIENT_ID,
  clientSecret: process.env.NODE_ENV === 'production' ?
    process.env.GITHUB_PROD_SECRET : process.env.GITHUB_SECRET,
  callbackURL: `${SERVER_URL}/auth/github/callback`
}, (accesstoken, refreshToken, profile, done) => {
    User.findOne({ githubId: profile.id }, (err, user) => {

      if (err) return done(err);

      if (!user) {
        // new registration: create and save user in database
        user = new User({
          githubId: profile.id,
          username: profile.username,
          personal: {
            memberSince: new Date(),
            avatarUrl: profile._json.avatar_url,
            profileUrl: profile.profileUrl,
            displayName: profile._json.name ? profile._json.name : '',
            email: profile._json.email ? profile._json.email : '',
            location: profile._json.location ? profile._json.location : '',
            bio: profile._json.bio ? profile._json.bio : '',
          },
          career: {
            company: profile._json.company ? profile._json.company : '',
          }
        });
        user.save((err) => {
          if (!err) {
            return done(err, user);
          }
        });
      } else {
        // user registered previously and exists in database
        console.log('user already exists');
        return done(err, user);
      }
    });
}));

router.get('/auth/github', passport.authenticate('github'));

router.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: `${CLIENT_URL}/login` }), ((req, res) => {
  // successfull authentication from github
  res.redirect(`${CLIENT_URL}/verify_account`);
}));

// TWITTER
passport.use(new TwitterStrategy({
  consumerKey: process.env.TWITTER_KEY,
  consumerSecret: process.env.TWITTER_SECRET,
  callbackURL: `${SERVER_URL}/connect/twitter/callback`
}, (token, tokenSecret, profile, done) => {
  return done(null, profile)
}));

router.get('/connect/twitter', isAuthenticated, passport.authorize('twitter'));

router.get('/connect/twitter/callback',
  passport.authorize('twitter', { failureRedirect: `${CLIENT_URL}/dashboard/preferences` }), ((req, res) => {
    const { user, account } = req;

    User.findOne({ githubId: user.githubId }, (err, updatedUser) => {
      if (!err) {
        updatedUser.social.twitter = account.username;
        updatedUser.save();
        res.redirect(`${CLIENT_URL}/dashboard/preferences`);
        console.log('updated user with twitter handle');
      } else {
        console.log(err);
      }
    });
}));

// LinkedIn
passport.use(new LinkedInStrategy({
  consumerKey: process.env.LINKEDIN_KEY,
  consumerSecret: process.env.LINKEDIN_SECRET,
  callbackURL: `${SERVER_URL}/connect/linkedin/callback`
}, (token, tokenSecret, profile, done) => {
  return done(null, profile)
}));

router.get('/connect/linkedin', isAuthenticated, passport.authorize('linkedin'));

router.get('/connect/linkedin/callback',
  passport.authorize('linkedin', { failureRedirect: `${CLIENT_URL}/dashboard/preferences` }), ((req, res) => {

    User.findOne({ githubId: req.user.githubId }, (err, updatedUser) => {
      if (!err) {
        updatedUser.social.linkedin = req.account.displayName;
        updatedUser.save();
        res.redirect(`${CLIENT_URL}/dashboard/preferences`);
        console.log('updated user with linkedin handle');
      } else {
        console.log(err);
      }
    });
}));

// logout user & redirect to home page
router.get('/logout', function(req, res){
  req.logout();
  res.redirect(`${CLIENT_URL}/`);
});

export default router;
<|endoftext|>


<commit_before>window.FlashCanvasOptions = {
  swfPath: 'lib/FlashCanvas/bin/'
};
yepnope([

  {
    test : (navigator.appVersion.indexOf("MSIE") != -1  && parseFloat(navigator.appVersion.split("MSIE")[1]) < 9),
    yep : [
      'lib/flotr2/lib/base64.js'
    ]
  },
  {
    test : (navigator.appVersion.indexOf("MSIE") != -1),
    yep : [
      'lib/FlashCanvas/bin/flashcanvas.js'
    ]
  },

  // Libs
  'flotr2.min.js',
  {
    test : ('ontouchstart' in window),
    nope : [
      'handles.js'
    ]
  },
  'lib/bonzo/bonzo.min.js',
  'vis.min.js',

  { complete : example }
]);
<commit_msg>Add jquery and use flotr basic.<commit_after>window.FlashCanvasOptions = {
  swfPath: 'lib/FlashCanvas/bin/'
};
yepnope([

  'lib/jquery/jquery-1.7.1.min.js',

  // IE
  {
    test : (navigator.appVersion.indexOf("MSIE") != -1  && parseFloat(navigator.appVersion.split("MSIE")[1]) < 9),
    yep : [
      'lib/flotr2/lib/base64.js'
    ]
  },
  {
    test : (navigator.appVersion.indexOf("MSIE") != -1),
    yep : [
      'lib/FlashCanvas/bin/flashcanvas.js'
    ]
  },

  // Libs
  'flotr2-basic.min.js',
  {
    test : ('ontouchstart' in window),
    nope : [
      'handles.js'
    ]
  },
  'lib/bonzo/bonzo.min.js',
  'vis.min.js',

  { complete : example }
]);
<|endoftext|>


<commit_before>// Copyright (c) 2012, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

function parseLines(lines, callback) {
    var re = /^\/tmp\/[^:]+:([0-9]+)(:([0-9]+))?:\s+(.*)/;
    $.each(lines.split('\n'), function(_, line) {
        line = line.trim();
        if (line != "") {
            var match = line.match(re);
            if (match) {
                callback(parseInt(match[1]), match[4]);
            } else {
                callback(null, line);
            }
        }
    });
}

function clearBackground(cm) {
    for (var i = 0; i < cm.lineCount(); ++i) {
        cm.removeLineClass(i, "background", null);
    }
}

const NumRainbowColours = 12;

function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback) {
    var compilersByExe = {};
    var pendingTimeout = null;
    var asmCodeMirror = null;
    var cppEditor = null;
    var lastRequest = null;
    var currentAssembly = null;
    var filters = origFilters;
    var ignoreChanges = true; // Horrible hack to avoid onChange doing anything on first starting, ie before we've set anything up.

    cppEditor = CodeMirror.fromTextArea(domRoot.find(".editor textarea")[0], {
        lineNumbers: true,
        matchBrackets: true,
        useCPP: true,
        mode: "text/x-c++src"
    });
    cppEditor.on("change", onChange);
    asmCodeMirror = CodeMirror.fromTextArea(domRoot.find(".asm textarea")[0], {
        lineNumbers: true,
                  matchBrackets: true,
                  mode: "text/x-asm",
                  readOnly: true
    });

    function getSetting(name) {
        return window.localStorage[windowLocalPrefix + "." + name];
    }
    function setSetting(name, value) {
        window.localStorage[windowLocalPrefix + "." + name] = value;
    }

    if (getSetting('code')) cppEditor.setValue(getSetting('code'));
    domRoot.find('.compiler').change(onCompilerChange);
    domRoot.find('.compiler_options').change(onChange).keyup(onChange);
    ignoreChanges = false;

    if (getSetting('compilerOptions')) {
        domRoot.find('.compiler_options').val(getSetting('compilerOptions'));
    }

    function makeErrNode(text) {
        var node = $('
!!
');
        node.find(".msg").text(text);
        return node[0];
    }

    var errorWidgets = [];
    function onCompileResponse(data) {
        var stdout = data.stdout || "";
        var stderr = data.stderr || "";
        if (data.code == 0) {
            stdout += "\nCompiled ok";
        } else {
            stderr += "\nCompilation failed";
        }
        $('.result .output :visible').remove();
        var highlightLine = (data.asm == null);
        for (var i = 0; i < errorWidgets.length; ++i)
            cppEditor.removeLineWidget(errorWidgets[i]);
        errorWidgets.length = 0;
        parseLines(stderr + stdout, function(lineNum, msg) {
            var elem = $('.result .output .template').clone().appendTo('.result .output').removeClass('template');
            if (lineNum) {
                errorWidgets.push(cppEditor.addLineWidget(lineNum - 1, makeErrNode(msg), {
                    coverGutter:false, noHScroll: true
                }));
                elem.html($('').append(lineNum + " : " + msg)).click(function() {
                    cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0});
                    return false;
                });
            } else {
                elem.text(msg);
            }
        });
        currentAssembly = data.asm || "[no output]";
        updateAsm();
    }

    function numberUsedLines(asm) {
        var sourceLines = {};
        $.each(asm, function(_, x) { if (x.source) sourceLines[x.source - 1] = true; });
        var ordinal = 0;
        $.each(sourceLines, function(k, _) { sourceLines[k] = ordinal++; });
        var asmLines = {};
        $.each(asm, function(index, x) { if (x.source) asmLines[index] = sourceLines[x.source - 1]; });
        return { source: sourceLines, asm: asmLines };
    }

    var lastUpdatedAsm = null;
    function updateAsm(forceUpdate) {
        if (!currentAssembly) return;
        var hashedUpdate = JSON.stringify({
            asm: currentAssembly,
            filters: filters
        });
        if (!forceUpdate && lastUpdatedAsm == hashedUpdate) { return; }
        lastUpdatedAsm = hashedUpdate;

        var asm = processAsm(currentAssembly, filters);
        var asmText = $.map(asm, function(x){ return x.text; }).join("\n");
        var numberedLines = numberUsedLines(asm);
        asmCodeMirror.setValue(asmText);

        clearBackground(cppEditor);
        clearBackground(asmCodeMirror);
        if (filters.colouriseAsm) {
            $.each(numberedLines.source, function(line, ordinal) {
                cppEditor.addLineClass(parseInt(line), "background", "rainbow-" + (ordinal % NumRainbowColours));
            });
            $.each(numberedLines.asm, function(line, ordinal) {
                asmCodeMirror.addLineClass(parseInt(line), "background", "rainbow-" + (ordinal % NumRainbowColours));
            });
        }
    }

    function pickOnlyRequestFilters(filters) {
        return {intel: !!filters.intel };
    }

    function onChange() {
        if (ignoreChanges) return;  // Ugly hack during startup.
        if (pendingTimeout) clearTimeout(pendingTimeout);
        pendingTimeout = setTimeout(function() {
            var data = {
                source: cppEditor.getValue(),
                compiler: $('.compiler').val(),
                options: $('.compiler_options').val(),
                filters: pickOnlyRequestFilters(filters)
            };
            setSetting('compiler', data.compiler);
            setSetting('compilerOptions', data.options);
            if (JSON.stringify(data) == JSON.stringify(lastRequest)) return;
            lastRequest = data;
            $.ajax({
                type: 'POST',
                url: '/compile',
                dataType: 'json',
                data: data,
                success: onCompileResponse});
        }, 750);
        setSetting('code', cppEditor.getValue());
        updateAsm();
        onChangeCallback();
    }

    function setSource(code) {
        cppEditor.setValue(code);
    }

    function getSource() {
        return cppEditor.getValue();
    }

    function serialiseState() {
        var state = {
            source: cppEditor.getValue(),
            compiler: domRoot.find('.compiler').val(),
            options: domRoot.find('.compiler_options').val(),
        };
        return state;
    }

    function deserialiseState(state) {
        cppEditor.setValue(state.source);
        domRoot.find('.compiler').val(state.compiler);
        domRoot.find('.compiler_options').val(state.options);
        // Somewhat hackily persist compiler into local storage else when the ajax response comes in
        // with the list of compilers it can splat over the deserialized version.
        // The whole serialize/hash/localStorage code is a mess! TODO(mg): fix
        setSetting('compiler', state.compiler);
        updateAsm(true);  // Force the update to reset colours after calling cppEditor.setValue
        return true;
    }

    function onCompilerChange() {
        onChange();
        var compiler = compilersByExe[$('.compiler').val()];
        domRoot.find('.filter button.btn[value="intel"]').toggleClass("disabled", !compiler.supportedOpts["-masm"]);
    }

    function setCompilers(compilers) {
        domRoot.find('.compiler option').remove();
        compilersByExe = {};
        $.each(compilers, function(index, arg) {
            compilersByExe[arg.exe] = arg;
            domRoot.find('.compiler').append($('<option value="' + arg.exe + '">' + arg.version + '</option>'));
        });
        if (getSetting('compiler')) {
            domRoot.find('.compiler').val(getSetting('compiler'));
        }
        onCompilerChange();
    }

    function setFilters(f) {
        filters = f;
        onChange();  // used to just update ASM, but things like "Intel syntax" need a new request
    }

    return {
        serialiseState: serialiseState,
        deserialiseState: deserialiseState,
        setCompilers: setCompilers,
        getSource: getSource,
        setSource: setSource,
        setFilters: setFilters
    };
}
<commit_msg>Note assembler is processing while waiting callback from web<commit_after>// Copyright (c) 2012, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

function parseLines(lines, callback) {
    var re = /^\/tmp\/[^:]+:([0-9]+)(:([0-9]+))?:\s+(.*)/;
    $.each(lines.split('\n'), function(_, line) {
        line = line.trim();
        if (line != "") {
            var match = line.match(re);
            if (match) {
                callback(parseInt(match[1]), match[4]);
            } else {
                callback(null, line);
            }
        }
    });
}

function clearBackground(cm) {
    for (var i = 0; i < cm.lineCount(); ++i) {
        cm.removeLineClass(i, "background", null);
    }
}

const NumRainbowColours = 12;

function Compiler(domRoot, origFilters, windowLocalPrefix, onChangeCallback) {
    var compilersByExe = {};
    var pendingTimeout = null;
    var asmCodeMirror = null;
    var cppEditor = null;
    var lastRequest = null;
    var currentAssembly = null;
    var filters = origFilters;
    var ignoreChanges = true; // Horrible hack to avoid onChange doing anything on first starting, ie before we've set anything up.

    cppEditor = CodeMirror.fromTextArea(domRoot.find(".editor textarea")[0], {
        lineNumbers: true,
        matchBrackets: true,
        useCPP: true,
        mode: "text/x-c++src"
    });
    cppEditor.on("change", onChange);
    asmCodeMirror = CodeMirror.fromTextArea(domRoot.find(".asm textarea")[0], {
        lineNumbers: true,
                  matchBrackets: true,
                  mode: "text/x-asm",
                  readOnly: true
    });

    function getSetting(name) {
        return window.localStorage[windowLocalPrefix + "." + name];
    }
    function setSetting(name, value) {
        window.localStorage[windowLocalPrefix + "." + name] = value;
    }

    if (getSetting('code')) cppEditor.setValue(getSetting('code'));
    domRoot.find('.compiler').change(onCompilerChange);
    domRoot.find('.compiler_options').change(onChange).keyup(onChange);
    ignoreChanges = false;

    if (getSetting('compilerOptions')) {
        domRoot.find('.compiler_options').val(getSetting('compilerOptions'));
    }

    function makeErrNode(text) {
        var node = $('
!!
');
        node.find(".msg").text(text);
        return node[0];
    }

    var errorWidgets = [];
    function onCompileResponse(data) {
        var stdout = data.stdout || "";
        var stderr = data.stderr || "";
        if (data.code == 0) {
            stdout += "\nCompiled ok";
        } else {
            stderr += "\nCompilation failed";
        }
        $('.result .output :visible').remove();
        var highlightLine = (data.asm == null);
        for (var i = 0; i < errorWidgets.length; ++i)
            cppEditor.removeLineWidget(errorWidgets[i]);
        errorWidgets.length = 0;
        parseLines(stderr + stdout, function(lineNum, msg) {
            var elem = $('.result .output .template').clone().appendTo('.result .output').removeClass('template');
            if (lineNum) {
                errorWidgets.push(cppEditor.addLineWidget(lineNum - 1, makeErrNode(msg), {
                    coverGutter:false, noHScroll: true
                }));
                elem.html($('').append(lineNum + " : " + msg)).click(function() {
                    cppEditor.setSelection({line: lineNum - 1, ch: 0}, {line: lineNum, ch: 0});
                    return false;
                });
            } else {
                elem.text(msg);
            }
        });
        currentAssembly = data.asm || "[no output]";
        updateAsm();
    }

    function numberUsedLines(asm) {
        var sourceLines = {};
        $.each(asm, function(_, x) { if (x.source) sourceLines[x.source - 1] = true; });
        var ordinal = 0;
        $.each(sourceLines, function(k, _) { sourceLines[k] = ordinal++; });
        var asmLines = {};
        $.each(asm, function(index, x) { if (x.source) asmLines[index] = sourceLines[x.source - 1]; });
        return { source: sourceLines, asm: asmLines };
    }

    var lastUpdatedAsm = null;
    function updateAsm(forceUpdate) {
        if (!currentAssembly) return;
        var hashedUpdate = JSON.stringify({
            asm: currentAssembly,
            filters: filters
        });
        if (!forceUpdate && lastUpdatedAsm == hashedUpdate) { return; }
        lastUpdatedAsm = hashedUpdate;

        var asm = processAsm(currentAssembly, filters);
        var asmText = $.map(asm, function(x){ return x.text; }).join("\n");
        var numberedLines = numberUsedLines(asm);
        asmCodeMirror.setValue(asmText);

        clearBackground(cppEditor);
        clearBackground(asmCodeMirror);
        if (filters.colouriseAsm) {
            $.each(numberedLines.source, function(line, ordinal) {
                cppEditor.addLineClass(parseInt(line), "background", "rainbow-" + (ordinal % NumRainbowColours));
            });
            $.each(numberedLines.asm, function(line, ordinal) {
                asmCodeMirror.addLineClass(parseInt(line), "background", "rainbow-" + (ordinal % NumRainbowColours));
            });
        }
    }

    function pickOnlyRequestFilters(filters) {
        return {intel: !!filters.intel };
    }

    function onChange() {
        if (ignoreChanges) return;  // Ugly hack during startup.
        if (pendingTimeout) clearTimeout(pendingTimeout);
        pendingTimeout = setTimeout(function() {
            var data = {
                source: cppEditor.getValue(),
                compiler: $('.compiler').val(),
                options: $('.compiler_options').val(),
                filters: pickOnlyRequestFilters(filters)
            };
            setSetting('compiler', data.compiler);
            setSetting('compilerOptions', data.options);
            if (JSON.stringify(data) == JSON.stringify(lastRequest)) return;
            lastRequest = data;
            $.ajax({
                type: 'POST',
                url: '/compile',
                dataType: 'json',
                data: data,
                success: onCompileResponse});
            asmCodeMirror.setValue("Processing...");
        }, 750);
        setSetting('code', cppEditor.getValue());
        updateAsm();
        onChangeCallback();
    }

    function setSource(code) {
        cppEditor.setValue(code);
    }

    function getSource() {
        return cppEditor.getValue();
    }

    function serialiseState() {
        var state = {
            source: cppEditor.getValue(),
            compiler: domRoot.find('.compiler').val(),
            options: domRoot.find('.compiler_options').val(),
        };
        return state;
    }

    function deserialiseState(state) {
        cppEditor.setValue(state.source);
        domRoot.find('.compiler').val(state.compiler);
        domRoot.find('.compiler_options').val(state.options);
        // Somewhat hackily persist compiler into local storage else when the ajax response comes in
        // with the list of compilers it can splat over the deserialized version.
        // The whole serialize/hash/localStorage code is a mess! TODO(mg): fix
        setSetting('compiler', state.compiler);
        updateAsm(true);  // Force the update to reset colours after calling cppEditor.setValue
        return true;
    }

    function onCompilerChange() {
        onChange();
        var compiler = compilersByExe[$('.compiler').val()];
        domRoot.find('.filter button.btn[value="intel"]').toggleClass("disabled", !compiler.supportedOpts["-masm"]);
    }

    function setCompilers(compilers) {
        domRoot.find('.compiler option').remove();
        compilersByExe = {};
        $.each(compilers, function(index, arg) {
            compilersByExe[arg.exe] = arg;
            domRoot.find('.compiler').append($('<option value="' + arg.exe + '">' + arg.version + '</option>'));
        });
        if (getSetting('compiler')) {
            domRoot.find('.compiler').val(getSetting('compiler'));
        }
        onCompilerChange();
    }

    function setFilters(f) {
        filters = f;
        onChange();  // used to just update ASM, but things like "Intel syntax" need a new request
    }

    return {
        serialiseState: serialiseState,
        deserialiseState: deserialiseState,
        setCompilers: setCompilers,
        getSource: getSource,
        setSource: setSource,
        setFilters: setFilters
    };
}
<|endoftext|>


<commit_before>import React from 'react';

// Components

import Button from '../button';
import Dropdown from '../dropdown'

const HeaderActions = ({primary, secondary}) =>  {
      return (

              {primary.map((primary) => {
                  if(Array.isArray(primary.action)) {
                      return <Dropdown iconProps={{name: primary.icon}} operationList={primary.action} shape='fab'/>;
                  } else {
                      return (
                          <Button key={primary.label} handleOnClick={primary.action} icon={primary.icon} label={primary.label} shape='fab' style={{className: primary.className}} type='button'/>
                      );
                  }
              })}
              <Dropdown iconProps={{name: 'more_vert'}} operations={secondary} shape='fab'/>

      );
};

export default HeaderActions;
<commit_msg>Fix secondary actions<commit_after>import React from 'react';

// Components

import Button from '../button';
import Dropdown from '../dropdown'

const HeaderActions = ({primary, secondary}) =>  {
      return (

              {primary.map((primary) => {
                  if(Array.isArray(primary.action)) {
                      return <Dropdown iconProps={{name: primary.icon}} operationList={primary.action} shape='fab'/>;
                  } else {
                      return (
                          <Button key={primary.label} handleOnClick={primary.action} icon={primary.icon} label={primary.label} shape='fab' style={{className: primary.className}} type='button'/>
                      );
                  }
              })}
              { secondary && <Dropdown iconProps={{name: 'more_vert'}} operations={secondary} shape='fab'/>}

      );
};

export default HeaderActions;
<|endoftext|>


<commit_before>const ELLIPSIS = '…';

/**
 * @param {Array} verseObjects
 * @param {Object} contextId
 * @param {boolean} isMatch // if true, all children will be considered a match and will be included in the returned text
 */
export const getAlignedText = (verseObjects, wordsToMatch, occurrenceToMatch, isMatch=false) => {
  // TODO: FIX FOR HINDI, परमेश्वर (God), Titus 1:1, 2nd occurrence
  let text = '';
  let separator = ' ';
  let inBetween = false;
  verseObjects.forEach(verseObject => {
    if ((verseObject.type == 'milestone' || verseObject.type == 'word')) {
      if ((wordsToMatch.indexOf(verseObject.content) >= 0 && verseObject.occurrence == occurrenceToMatch) || isMatch) {
        if (inBetween) {
          separator += ELLIPSIS+' ';
          inBetween = false;
        }
        if (verseObject.text) {
          text += (text?separator:'') + verseObject.text;
          separator = ' ';
        }
        if (verseObject.children) {
          text += (text?separator:'') + getAlignedText(verseObject.children, wordsToMatch, occurrenceToMatch, true);
          separator = ' ';
        }
      } else if (verseObject.children) {
        let childWord = getAlignedText(verseObject.children, wordsToMatch, occurrenceToMatch, isMatch);
        if (childWord) {
          if (inBetween) {
            separator += ELLIPSIS+' ';
            inBetween = false;
          }
          text += (text?separator:'') + childWord;
          separator = ' ';
        } else if (text) {
          inBetween = true;
        }
      }
    } else if (verseObject.type == "text" && text) {
      if (separator == ' ') {
        separator = '';
      }
      separator += verseObject.text;
    }
  });
  return text;
};
<commit_msg>Adds documentation to the getAlignedGLText function<commit_after>const ELLIPSIS = '…';

/**
 * @param {Array} verseObjects
 * @param {Object} contextId
 * @param {boolean} isMatch // if true, all children will be considered a match and will be included in the returned text
 */
export const getAlignedText = (verseObjects, wordsToMatch, occurrenceToMatch, isMatch=false) => {
  // TODO: FIX FOR HINDI, परमेश्वर (God), Titus 1:1, 2nd occurrence
  let text = '';
  let separator = ' ';
  let needsEllipsis = false;
  verseObjects.forEach(verseObject => {
    if ((verseObject.type == 'milestone' || verseObject.type == 'word')) {
      // It is a milestone or a word...we want to handle all of them.
      if ((wordsToMatch.indexOf(verseObject.content) >= 0 && verseObject.occurrence == occurrenceToMatch) || isMatch) {
        // We have a match (or previoiusly had a match in the parent) so we want to include all text that we find,
        if (needsEllipsis) {
          // Need to add an ellipsis to the separator since a previous match but not one right next to this one
          separator += ELLIPSIS+' ';
          needsEllipsis = false;
        }
        if (text) {
          // There has previously been text, so append the separator, either a space or punctuation
          text += separator;
        }
        separator = ' '; // reset the separator for the next word
        if (verseObject.text) {
          // Handle type word, appending the text from this node
          text += verseObject.text;
        }
        if (verseObject.children) {
          // Handle children of type milestone, appending all the text of the children, isMatch is true
          text += getAlignedText(verseObject.children, wordsToMatch, occurrenceToMatch, true);
        }
      } else if (verseObject.children) {
        // Did not find a match, yet still need to go through all the children and see if there's match.
        // If there isn't a match here, i.e. childText is empty, and we have text, we still need
        // an ellipsis if a later match is found since there was some text here
        let childText = getAlignedText(verseObject.children, wordsToMatch, occurrenceToMatch, isMatch);
        if (childText) {
          if (needsEllipsis) {
            separator += ELLIPSIS+' ';
            needsEllipsis = false;
          }
          text += (text?separator:'') + childText;
          separator = ' ';
        } else if (text) {
          needsEllipsis = true;
        }
      }
    } else if (verseObject.type == "text" && text) {
      // Found some text that is a word separator/punctuation, e.g. the apostrophe between "God" and "s" for "God's"
      // We want to preserve this so we can show "God's" instead of "God ... s"
      if (separator == ' ') {
        separator = '';
      }
      separator += verseObject.text;
    }
  });
  return text;
};
<|endoftext|>