<commit_before>/*
 * L.DomUtil contains various utility functions for working with DOM.
 */

L.DomUtil = {
	get: function (id) {
		return (typeof id === 'string' ? document.getElementById(id) : id);
	},

	getStyle: function (el, style) {

		var value = el.style[style];

		if (!value && el.currentStyle) {
			value = el.currentStyle[style];
		}

		if ((!value || value === 'auto') && document.defaultView) {
			var css = document.defaultView.getComputedStyle(el, null);
			value = css ? css[style] : null;
		}

		return value === 'auto' ? null : value;
	},

	getViewportOffset: function (element) {

		var top = 0,
		    left = 0,
		    el = element,
		    docBody = document.body,
		    docEl = document.documentElement,
		    pos,
		    ie7 = L.Browser.ie7;

		do {
			top  += el.offsetTop  || 0;
			left += el.offsetLeft || 0;

			//add borders
			top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0;
			left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0;

			pos = L.DomUtil.getStyle(el, 'position');

			if (el.offsetParent === docBody && pos === 'absolute') { break; }

			if (pos === 'fixed') {
				top  += docBody.scrollTop  || docEl.scrollTop  || 0;
				left += docBody.scrollLeft || docEl.scrollLeft || 0;
				break;
			}
			el = el.offsetParent;

		} while (el);

		el = element;

		do {
			if (el === docBody) { break; }

			top  -= el.scrollTop  || 0;
			left -= el.scrollLeft || 0;

			// webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
			// https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
			if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
				left += el.scrollWidth - el.clientWidth;

				// ie7 shows the scrollbar by default and provides clientWidth counting it, so we
				// need to add it back in if it is visible; scrollbar is on the left as we are RTL
				if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' &&
				           L.DomUtil.getStyle(el, 'overflow') !== 'hidden') {
					left += 17;
				}
			}

			el = el.parentNode;
		} while (el);

		return new L.Point(left, top);
	},

	documentIsLtr: function () {
		if (!L.DomUtil._docIsLtrCached) {
			L.DomUtil._docIsLtrCached = true;
			L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr';
		}
		return L.DomUtil._docIsLtr;
	},

	create: function (tagName, className, container) {

		var el = document.createElement(tagName);
		el.className = className;

		if (container) {
			container.appendChild(el);
		}

		return el;
	},

	disableTextSelection: function () {
		if (document.selection && document.selection.empty) {
			document.selection.empty();
		}
		if (!this._onselectstart) {
			this._onselectstart = document.onselectstart || null;
			document.onselectstart = L.Util.falseFn;
		}
	},

	enableTextSelection: function () {
		if (document.onselectstart === L.Util.falseFn) {
			document.onselectstart = this._onselectstart;
			this._onselectstart = null;
		}
	},

	hasClass: function (el, name) {
		return (el.className.length > 0) &&
		        new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className);
	},

	addClass: function (el, name) {
		if (!L.DomUtil.hasClass(el, name)) {
			el.className += (el.className ? ' ' : '') + name;
		}
	},

	removeClass: function (el, name) {
		el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' '));
	},

	setOpacity: function (el, value) {

		if ('opacity' in el.style) {
			el.style.opacity = value;

		} else if ('filter' in el.style) {

			var filter = false,
			    filterName = 'DXImageTransform.Microsoft.Alpha';

			// filters collection throws an error if we try to retrieve a filter that doesn't exist
			try {
				filter = el.filters.item(filterName);
			} catch (e) {
				// don't set opacity to 1 if we haven't already set an opacity,
				// it isn't needed and breaks transparent pngs.
				if (value === 1) { return; }
			}

			value = Math.round(value * 100);

			if (filter) {
				filter.Enabled = (value !== 100);
				filter.Opacity = value;
			} else {
				el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
			}
		}
	},

	testProp: function (props) {

		var style = document.documentElement.style;

		for (var i = 0; i < props.length; i++) {
			if (props[i] in style) {
				return props[i];
			}
		}
		return false;
	},

	getTranslateString: function (point) {
		// on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate
		// makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care
		// (same speed either way), Opera 12 doesn't support translate3d

		var is3d = L.Browser.webkit3d,
		    open = 'translate' + (is3d ? '3d' : '') + '(',
		    close = (is3d ? ',0' : '') + ')';

		return open + point.x + 'px,' + point.y + 'px' + close;
	},

	getScaleString: function (scale, origin) {

		var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))),
		    scaleStr = ' scale(' + scale + ') ';

		return preTranslateStr + scaleStr;
	},

	setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean])

		// jshint camelcase: false
		el._leaflet_pos = point;

		if (!disable3D && L.Browser.any3d) {
			el.style[L.DomUtil.TRANSFORM] =  L.DomUtil.getTranslateString(point);

			// workaround for Android 2/3 stability (https://github.com/CloudMade/Leaflet/issues/69)
			if (L.Browser.mobileWebkit3d) {
				el.style.WebkitBackfaceVisibility = 'hidden';
			}
		} else {
			el.style.left = point.x + 'px';
			el.style.top = point.y + 'px';
		}
	},

	getPosition: function (el) {
		// this method is only used for elements previously positioned using setPosition,
		// so it's safe to cache the position for performance

		// jshint camelcase: false
		return el._leaflet_pos;
	}
};

// prefix style property names

L.DomUtil.TRANSFORM = L.DomUtil.testProp(
        ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);

// webkitTransition comes first because some browser versions that drop vendor prefix don't do
// the same for the transitionend event, in particular the Android 4.1 stock browser

L.DomUtil.TRANSITION = L.DomUtil.testProp(
        ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);

L.DomUtil.TRANSITION_END =
        L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ?
        L.DomUtil.TRANSITION + 'End' : 'transitionend';
<commit_msg>calculate x position with postion:relative and width/maxWidth<commit_after>/*
 * L.DomUtil contains various utility functions for working with DOM.
 */

L.DomUtil = {
	get: function (id) {
		return (typeof id === 'string' ? document.getElementById(id) : id);
	},

	getStyle: function (el, style) {

		var value = el.style[style];

		if (!value && el.currentStyle) {
			value = el.currentStyle[style];
		}

		if ((!value || value === 'auto') && document.defaultView) {
			var css = document.defaultView.getComputedStyle(el, null);
			value = css ? css[style] : null;
		}

		return value === 'auto' ? null : value;
	},

	getViewportOffset: function (element) {

		var top = 0,
		    left = 0,
		    el = element,
		    docBody = document.body,
		    docEl = document.documentElement,
		    pos,
		    ie7 = L.Browser.ie7;

		do {
			top  += el.offsetTop  || 0;
			left += el.offsetLeft || 0;

			//add borders
			top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0;
			left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0;

			pos = L.DomUtil.getStyle(el, 'position');

			if (el.offsetParent === docBody && pos === 'absolute') { break; }

			if (pos === 'fixed') {
				top  += docBody.scrollTop  || docEl.scrollTop  || 0;
				left += docBody.scrollLeft || docEl.scrollLeft || 0;
				break;
			}

            if (pos === 'relative' && !el.offsetLeft) {
                var width = L.DomUtil.getStyle(el, 'width'),
                    maxWidth = L.DomUtil.getStyle(el, 'max-width');

                if (width !== 'none' || maxWidth !== 'none') {
                    var r = el.getBoundingClientRect();
                    left += r.left + el.clientLeft;
                }

                break;
            }

            el = el.offsetParent;

		} while (el);

		el = element;

		do {
			if (el === docBody) { break; }

			top  -= el.scrollTop  || 0;
			left -= el.scrollLeft || 0;

			// webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
			// https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
			if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
				left += el.scrollWidth - el.clientWidth;

				// ie7 shows the scrollbar by default and provides clientWidth counting it, so we
				// need to add it back in if it is visible; scrollbar is on the left as we are RTL
				if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' &&
				           L.DomUtil.getStyle(el, 'overflow') !== 'hidden') {
					left += 17;
				}
			}

			el = el.parentNode;
		} while (el);

		return new L.Point(left, top);
	},

	documentIsLtr: function () {
		if (!L.DomUtil._docIsLtrCached) {
			L.DomUtil._docIsLtrCached = true;
			L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr';
		}
		return L.DomUtil._docIsLtr;
	},

	create: function (tagName, className, container) {

		var el = document.createElement(tagName);
		el.className = className;

		if (container) {
			container.appendChild(el);
		}

		return el;
	},

	disableTextSelection: function () {
		if (document.selection && document.selection.empty) {
			document.selection.empty();
		}
		if (!this._onselectstart) {
			this._onselectstart = document.onselectstart || null;
			document.onselectstart = L.Util.falseFn;
		}
	},

	enableTextSelection: function () {
		if (document.onselectstart === L.Util.falseFn) {
			document.onselectstart = this._onselectstart;
			this._onselectstart = null;
		}
	},

	hasClass: function (el, name) {
		return (el.className.length > 0) &&
		        new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className);
	},

	addClass: function (el, name) {
		if (!L.DomUtil.hasClass(el, name)) {
			el.className += (el.className ? ' ' : '') + name;
		}
	},

	removeClass: function (el, name) {
		el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' '));
	},

	setOpacity: function (el, value) {

		if ('opacity' in el.style) {
			el.style.opacity = value;

		} else if ('filter' in el.style) {

			var filter = false,
			    filterName = 'DXImageTransform.Microsoft.Alpha';

			// filters collection throws an error if we try to retrieve a filter that doesn't exist
			try {
				filter = el.filters.item(filterName);
			} catch (e) {
				// don't set opacity to 1 if we haven't already set an opacity,
				// it isn't needed and breaks transparent pngs.
				if (value === 1) { return; }
			}

			value = Math.round(value * 100);

			if (filter) {
				filter.Enabled = (value !== 100);
				filter.Opacity = value;
			} else {
				el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
			}
		}
	},

	testProp: function (props) {

		var style = document.documentElement.style;

		for (var i = 0; i < props.length; i++) {
			if (props[i] in style) {
				return props[i];
			}
		}
		return false;
	},

	getTranslateString: function (point) {
		// on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate
		// makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care
		// (same speed either way), Opera 12 doesn't support translate3d

		var is3d = L.Browser.webkit3d,
		    open = 'translate' + (is3d ? '3d' : '') + '(',
		    close = (is3d ? ',0' : '') + ')';

		return open + point.x + 'px,' + point.y + 'px' + close;
	},

	getScaleString: function (scale, origin) {

		var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))),
		    scaleStr = ' scale(' + scale + ') ';

		return preTranslateStr + scaleStr;
	},

	setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean])

		// jshint camelcase: false
		el._leaflet_pos = point;

		if (!disable3D && L.Browser.any3d) {
			el.style[L.DomUtil.TRANSFORM] =  L.DomUtil.getTranslateString(point);

			// workaround for Android 2/3 stability (https://github.com/CloudMade/Leaflet/issues/69)
			if (L.Browser.mobileWebkit3d) {
				el.style.WebkitBackfaceVisibility = 'hidden';
			}
		} else {
			el.style.left = point.x + 'px';
			el.style.top = point.y + 'px';
		}
	},

	getPosition: function (el) {
		// this method is only used for elements previously positioned using setPosition,
		// so it's safe to cache the position for performance

		// jshint camelcase: false
		return el._leaflet_pos;
	}
};

// prefix style property names

L.DomUtil.TRANSFORM = L.DomUtil.testProp(
        ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);

// webkitTransition comes first because some browser versions that drop vendor prefix don't do
// the same for the transitionend event, in particular the Android 4.1 stock browser

L.DomUtil.TRANSITION = L.DomUtil.testProp(
        ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);

L.DomUtil.TRANSITION_END =
        L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ?
        L.DomUtil.TRANSITION + 'End' : 'transitionend';
<|endoftext|>


<commit_before>/* @flow */
import { Emitter, CompositeDisposable } from 'sb-event-kit'
import { Server } from 'ws'
import disposableEvent from 'disposable-event'
import websocketPort from './lib/wport'
import Cache from './cache'
import { log, handleError } from './lib/fns'
import getOptions from './opts'

import type WebSocket from 'ws'

type Message = {
  _type: string,
  timestamp: number
}

export default new class Bridge {
  cache: Map<string, Message>;
  server: ?Server;
  emitter: Emitter;
  connections: Set<WebSocket>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.cache = new Map()
    this.server = null
    this.emitter = new Emitter()
    this.connections = new Set()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.emitter)
  }

  activateNew(): Promise {
    return new Promise((resolve, reject) => {
      const server = this.server = new Server({
        port: websocketPort()
      })
      const subscriptions = new CompositeDisposable()
      subscriptions.add(disposableEvent(server, 'listening', function() {
        subscriptions.dispose()
        resolve()
      }))
      subscriptions.add(disposableEvent(server, 'error', function(error) {
        subscriptions.dispose()
        reject(error)
      }))
      this.subscriptions.add(disposableEvent(server, 'connection', connection => this.handleConnection(connection)))
    }).then(() => {
    })
  }
  handleConnection(connection: WebSocket) {
    this.connections.add(connection)
    connection.on('close', () => {
      this.connections.delete(connection)
    })
    connection.on('message', async (data, flags) => {
      if (flags.binary) {
        log.bridge('Ignoring message because it\'s binary')
        return
      }

      let message
      try {
        message = JSON.parse(data)
        log.bridge('IN', message._type)
        await this.emitter.emit(`message:${message._type}`, message)
      } catch (error) {
        handleError(error)
      } finally {
        if (message && message.id) {
          connection.send(this.encodeMessage(message._type, Object.assign({id: message.id}, message.result)))
        }
      }
    })

    connection.send(this.encodeMessage('motion:baseDir', {
      dir: Cache.baseDir()
    }))
    connection.send(this.encodeMessage('motion:opts', getOptions()))

    for (const value in this.cache.values()) {
      connection.send(value)
    }
  }

  broadcast(type, message, cacheKey = null) {
    this.broadcastRaw(this.encodeMessage(type, message), cacheKey)
  }

  encodeMessage(type, message = {}) {
    log.bridge('OUT', type)
    return JSON.stringify(Object.assign({
      _type: type,
      timestamp: Date.now()
    }, message))
  }

  broadcastRaw(message, cacheKey = null) {
    if (typeof message !== 'string') {
      throw new Error('Malformed message given')
    }

    // If we have any active connections
    if (this.connections.size) {
      this.connections.forEach(function(connection) {
        connection.send(message)
      })
    }

    if (cacheKey !== null) {
      this.cache.set(cacheKey, message)
    }
  }

  onDidReceiveMessage(type, callback) {
    return this.emitter.on(`message:${type}`, callback)
  }

  dispose() {
    if (this.server) {
      this.server.close()
    }
    this.connections.clear()
    this.subscriptions.dispose()
    this.cache.clear()
  }
}
<commit_msg>:art: Flow-ize bridge class<commit_after>/* @flow */
import { Emitter, CompositeDisposable } from 'sb-event-kit'
import { Server } from 'ws'
import disposableEvent from 'disposable-event'
import websocketPort from './lib/wport'
import Cache from './cache'
import { log, handleError } from './lib/fns'
import getOptions from './opts'

import type {Disposable} from 'sb-event-kit'
import type WebSocket from 'ws'

type Message = {
  _type: string,
  timestamp: number
}

export default new class Bridge {
  cache: Map<string, string>;
  server: ?Server;
  emitter: Emitter;
  connections: Set<WebSocket>;
  subscriptions: CompositeDisposable;

  constructor() {
    this.cache = new Map()
    this.server = null
    this.emitter = new Emitter()
    this.connections = new Set()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.emitter)
  }

  activate(): Promise {
    return new Promise((resolve, reject) => {
      const server = this.server = new Server({
        port: websocketPort()
      })
      const subscriptions = new CompositeDisposable()
      subscriptions.add(disposableEvent(server, 'listening', function() {
        subscriptions.dispose()
        resolve()
      }))
      subscriptions.add(disposableEvent(server, 'error', function(error) {
        subscriptions.dispose()
        reject(error)
      }))
      this.subscriptions.add(disposableEvent(server, 'connection', connection => this.handleConnection(connection)))
    })
  }
  handleConnection(connection: WebSocket) {
    this.connections.add(connection)
    connection.on('close', () => {
      this.connections.delete(connection)
    })
    connection.on('message', async (data, flags) => {
      if (flags.binary) {
        log.bridge('Ignoring message because it\'s binary')
        return
      }

      let message
      try {
        message = JSON.parse(data)
        log.bridge('IN', message._type)
        await this.emitter.emit(`message:${message._type}`, message)
      } catch (error) {
        handleError(error)
      } finally {
        if (message && message.id) {
          connection.send(this.encodeMessage(message._type, Object.assign({id: message.id}, message.result)))
        }
      }
    })

    connection.send(this.encodeMessage('motion:baseDir', {
      dir: Cache.baseDir()
    }))
    connection.send(this.encodeMessage('motion:opts', getOptions()))

    for (const value in this.cache.values()) {
      connection.send(value)
    }
  }

  broadcast(type: string, message: Message, cacheKey: ?string = null) {
    this.broadcastRaw(this.encodeMessage(type, message), cacheKey)
  }

  encodeMessage(type: string, message: Object): string {
    log.bridge('OUT', type)
    return JSON.stringify(Object.assign({
      _type: type,
      timestamp: Date.now()
    }, message))
  }

  broadcastRaw(message: string, cacheKey: ?string = null) {
    if (typeof message !== 'string') {
      throw new Error('Malformed message given')
    }

    // If we have any active connections
    if (this.connections.size) {
      this.connections.forEach(function(connection) {
        connection.send(message)
      })
    }

    if (cacheKey) {
      this.cache.set(cacheKey, message)
    }
  }

  onDidReceiveMessage(type: string, callback: Function): Disposable {
    return this.emitter.on(`message:${type}`, callback)
  }

  dispose() {
    if (this.server) {
      this.server.close()
    }
    this.connections.clear()
    this.subscriptions.dispose()
    this.cache.clear()
  }
}
<|endoftext|>


<commit_before>function copyArray (a, na) {
  na = na || []
  for (var i = 0; i < a.length; i++) {
    na[i] = a[i]
  }
  return na
}

function CommandQueue (ctx) {
  this._ctx = ctx
  this._commands = 0
  this._prevProgram = null
  this._prevTextures = []

  this.debug = false
  this.profile = false
}

var ID = 0

var updatedUniforms = { }
var createdCommands = 0

CommandQueue.prototype.getContext = function () {
  return this._ctx
}

// currenlty this doesn't do anything but in the future it can provide:
// - defaults
// - validation
CommandQueue.prototype.createDrawCommand = function (obj) {
  createdCommands++
  obj._type = 'draw'
  obj._id = ID++
  return obj
}

CommandQueue.prototype.createClearCommand = function (obj) {
  createdCommands++
  obj._type = 'clear'
  obj._id = ID++
  return obj
}

CommandQueue.prototype.createTextureUpdateCommand = function (obj) {
}

CommandQueue.prototype.createVertexArrayUpdateCommand = function (obj) {
}

function applyUniforms (ctx, program, uniforms, prevUniforms, prevTextures, debug) {
  if (debug) {
    // verify if we provide all uniforms required by the shader
    for (var requiredUniform in program._uniforms) {
      if (requiredUniform === 'uProjectionMatrix') continue
      if (requiredUniform === 'uViewMatrix') continue
      if (requiredUniform === 'uInverseViewMatrix') continue
      if (requiredUniform === 'uModelMatrix') continue
      if (requiredUniform === 'uNormalMatrix') continue
      if (uniforms[requiredUniform] === undefined) {
        // console.log('missing uniform', requiredUniform)
      }
    }
  }

  var textureOffset = 0
  // console.log(Object.keys(uniforms).length)
  for (var uniformName in uniforms) {
    // TODO: can i do array index check instead of function call?
    // if (debug) console.log('  setUniform', uniformName, '' + uniforms[uniformName])
    // if (!program.hasUniform(uniformName)) {
    if (!program._uniforms[uniformName]) {
      // console.log('Unnecessary uniform', uniformName)
      continue
    }
    var value = uniforms[uniformName]
    if (debug) {
      if (value === null || value === undefined) {
        throw new Error('Null uniform value for ' + uniformName + ' in PBRMaterial')
      }
    }
    if (value.getTarget) { // it's a texture
      if (prevTextures[textureOffset] !== value) {
        ctx.bindTexture(value, textureOffset)
        prevTextures[textureOffset] = value
      }
      value = textureOffset++
    }

    var shouldUpdate = false
    var prevValue = prevUniforms[uniformName]
    var len = value.length

    if (prevValue === undefined) {
      shouldUpdate = true
    } else if (len) {
      for (var i = 0; i < len; i++) {
        if (value[i] !== prevValue[i]) {
          shouldUpdate = true
          break
        }
      }
    } else if (value !== prevValue) {
      shouldUpdate = true
    }

    if (shouldUpdate) {
      prevUniforms[uniformName] = len ? copyArray(value, prevUniforms[uniformName]) : value
      program.setUniform(uniformName, value)
      updatedUniforms[uniformName] = (updatedUniforms[uniformName] || 0) + 1
    }
  }
  return textureOffset
}

function debugObject (cmd) {
  for (var prop in cmd) {
    console.log('  ', prop, '' + cmd[prop])
  }
}

// cmd - a command to submit to the queue, the immediate execution is not guaranteed and will
// depend on the curren optimization strategy
// opts - submit call specific command overrides Object or Array of Objects
// subContextCallback - all submit calls within this callback will
// inherit defaults from the currently executing cmd
CommandQueue.prototype.submit = function (cmd, opts, subCommanDraw) {
  this._commands++// .push([cmd, opts, subCommanDraw])
  // if (this.debug) console.log('submit', cmd._type, cmd._id, cmd.name || '')

  if (this.debug && cmd.name) {
    console.log('prev uniforms')
    debugObject(this._prevUniforms)
  }

  if (!cmd._type) {
    if (this.debug) console.log(cmd.toString())
    throw new Error('Unknown cmd type')
  }
  if (opts) {
    // TODO: optimize this
    cmd = Object.assign({}, cmd, opts)
    if (cmd.uniforms && opts.uniforms) {
      cmd.uniforms = Object.assign({}, cmd.uniforms, opts.uniforms)
    }
  }

  var pushedStates = 0

  var ctx = this._ctx
  if (cmd.framebuffer) {
    ctx.pushState(ctx.FRAMEBUFFER_BIT)
    ctx.bindFramebuffer(cmd.framebuffer)
    pushedStates++
    if (cmd.framebufferColorAttachments) {
      // FIXME: this modifies the framebuffer permamently after the call
      for (var attachmentIndex in cmd.framebufferColorAttachments) {
        var colorAttachment = cmd.framebufferColorAttachments[attachmentIndex]
        var index = parseInt(attachmentIndex, 10)
        cmd.framebuffer.setColorAttachment(index, colorAttachment.target, colorAttachment.handle, colorAttachment.level)
      }
    }
    if (cmd.framebufferDepthAttachment) {
      // FIXME: this modifies the framebuffer permamently after the call
      var depthAttachment = cmd.framebufferDepthAttachment
      cmd.framebuffer.setDepthAttachment(depthAttachment.target, depthAttachment.handle, depthAttachment.level)
    }
  }

  var clearFlags = 0
  if (cmd.color !== undefined) {
    ctx.pushState(ctx.COLOR_BIT)
    pushedStates++
    ctx.setClearColor(cmd.color[0], cmd.color[1], cmd.color[2], cmd.color[3])
    clearFlags |= ctx.COLOR_BIT
  }
  if (cmd.depth !== undefined) {
    ctx.pushState(ctx.DEPTH_BIT)
    pushedStates++
    ctx.setClearDepth(cmd.depth)
    clearFlags |= ctx.DEPTH_BIT
  }
  if (clearFlags) {
    ctx.clear(clearFlags)
  }

  if (cmd.program !== undefined) {
    if (this._prevProgram !== cmd.program) {
      ctx.bindProgram(cmd.program)
      this._prevProgram = cmd.program
      if (!cmd.program._prevUniforms) {
        cmd.program._prevUniforms = {}
      }
    }
  }

  if (cmd.uniforms !== undefined) {
    applyUniforms(ctx, cmd.program, cmd.uniforms, cmd.program._prevUniforms, this._prevTextures, this.debug)
  }

  if (cmd.projectionMatrix !== undefined) {
    ctx.pushState(ctx.MATRIX_PROJECTION_BIT)
    pushedStates++
    ctx.setProjectionMatrix(cmd.projectionMatrix)
  }

  if (cmd.viewMatrix !== undefined) {
    ctx.pushState(ctx.MATRIX_VIEW_BIT)
    pushedStates++
    ctx.setViewMatrix(cmd.viewMatrix)
  }

  if (cmd.modelMatrix !== undefined) {
    ctx.pushState(ctx.MATRIX_MODEL_BIT)
    pushedStates++
    ctx.setModelMatrix(cmd.modelMatrix)
  }

  if (cmd.viewport !== undefined) {
    ctx.pushState(ctx.VIEWPORT_BIT)
    pushedStates++
    ctx.setViewport(cmd.viewport[0], cmd.viewport[1], cmd.viewport[2], cmd.viewport[3])
  }

  if (cmd.depthTest !== undefined) {
    ctx.pushState(ctx.DEPTH_BIT)
    pushedStates++
    ctx.setDepthTest(cmd.depthTest)
  }

  if (cmd.cullFace !== undefined) {
    ctx.pushState(ctx.CULL_BIT)
    pushedStates++
    ctx.setCullFace(cmd.cullFace)
  }

  if (cmd.cullFaceMode !== undefined) {
    ctx.pushState(ctx.CULL_BIT)
    pushedStates++
    ctx.setCullFaceMode(cmd.cullFaceMode)
  }

  if (cmd.colorMask !== undefined) {
    ctx.pushState(ctx.COLOR_BIT)
    pushedStates++
    ctx.setColorMask(cmd.colorMask[0], cmd.colorMask[1], cmd.colorMask[2], cmd.colorMask[3])
  }

  if (cmd.mesh) {
    ctx.bindMesh(cmd.mesh)
    ctx.drawMesh()
  }

  if (subCommanDraw) {
    subCommanDraw()
  }

  // if (this.debug) console.log(' ', 'pushedStates', pushedStates)
  for (var i = 0; i < pushedStates; i++) {
    ctx.popState()
  }
}

// force execute of all commands in the queue
CommandQueue.prototype.flush = function () {
  if (this.profile) {
    console.log('CommandQueue', 'numCommands', this._commands, 'updatedUniforms', Object.keys(updatedUniforms).length, 'createdCommands', createdCommands)
  }
  this._prevProgram = null
  this._prevTextures.length = 0
  this._commands = 0
  if (this.profile) {
    console.log('CommandQueue', 'updatedUniforms', updatedUniforms)
  }
  updatedUniforms = {}
  createdCommands = 0
}

module.exports = CommandQueue
<commit_msg>CommandQueue added vertexArray support<commit_after>function copyArray (a, na) {
  na = na || []
  for (var i = 0; i < a.length; i++) {
    na[i] = a[i]
  }
  return na
}

function CommandQueue (ctx) {
  this._ctx = ctx
  this._commands = 0
  this._prevProgram = null
  this._prevTextures = []

  this.debug = false
  this.profile = false
}

var ID = 0

var updatedUniforms = { }
var createdCommands = 0

CommandQueue.prototype.getContext = function () {
  return this._ctx
}

// currenlty this doesn't do anything but in the future it can provide:
// - defaults
// - validation
CommandQueue.prototype.createDrawCommand = function (obj) {
  createdCommands++
  obj._type = 'draw'
  obj._id = ID++
  return obj
}

CommandQueue.prototype.createClearCommand = function (obj) {
  createdCommands++
  obj._type = 'clear'
  obj._id = ID++
  return obj
}

CommandQueue.prototype.createTextureUpdateCommand = function (obj) {
}

CommandQueue.prototype.createVertexArrayUpdateCommand = function (obj) {
}

function applyUniforms (ctx, program, uniforms, prevUniforms, prevTextures, debug) {
  if (debug) {
    // verify if we provide all uniforms required by the shader
    for (var requiredUniform in program._uniforms) {
      if (requiredUniform === 'uProjectionMatrix') continue
      if (requiredUniform === 'uViewMatrix') continue
      if (requiredUniform === 'uInverseViewMatrix') continue
      if (requiredUniform === 'uModelMatrix') continue
      if (requiredUniform === 'uNormalMatrix') continue
      if (uniforms[requiredUniform] === undefined) {
        // console.log('missing uniform', requiredUniform)
      }
    }
  }

  var textureOffset = 0
  // console.log(Object.keys(uniforms).length)
  for (var uniformName in uniforms) {
    // TODO: can i do array index check instead of function call?
    // if (debug) console.log('  setUniform', uniformName, '' + uniforms[uniformName])
    // if (!program.hasUniform(uniformName)) {
    if (!program._uniforms[uniformName]) {
      // console.log('Unnecessary uniform', uniformName)
      continue
    }
    var value = uniforms[uniformName]
    if (debug) {
      if (value === null || value === undefined) {
        throw new Error('Null uniform value for ' + uniformName + ' in PBRMaterial')
      }
    }
    if (value.getTarget) { // it's a texture
      if (prevTextures[textureOffset] !== value) {
        ctx.bindTexture(value, textureOffset)
        prevTextures[textureOffset] = value
      }
      value = textureOffset++
    }

    var shouldUpdate = false
    var prevValue = prevUniforms[uniformName]
    var len = value.length

    if (prevValue === undefined) {
      shouldUpdate = true
    } else if (len) {
      for (var i = 0; i < len; i++) {
        if (value[i] !== prevValue[i]) {
          shouldUpdate = true
          break
        }
      }
    } else if (value !== prevValue) {
      shouldUpdate = true
    }

    if (shouldUpdate) {
      prevUniforms[uniformName] = len ? copyArray(value, prevUniforms[uniformName]) : value
      program.setUniform(uniformName, value)
      updatedUniforms[uniformName] = (updatedUniforms[uniformName] || 0) + 1
    }
  }
  return textureOffset
}

function debugObject (cmd) {
  for (var prop in cmd) {
    console.log('  ', prop, '' + cmd[prop])
  }
}

// cmd - a command to submit to the queue, the immediate execution is not guaranteed and will
// depend on the curren optimization strategy
// opts - submit call specific command overrides Object or Array of Objects
// subContextCallback - all submit calls within this callback will
// inherit defaults from the currently executing cmd
CommandQueue.prototype.submit = function (cmd, opts, subCommanDraw) {
  this._commands++// .push([cmd, opts, subCommanDraw])
  // if (this.debug) console.log('submit', cmd._type, cmd._id, cmd.name || '')

  if (this.debug && cmd.name) {
    console.log('prev uniforms')
    debugObject(this._prevUniforms)
  }

  if (!cmd._type) {
    if (this.debug) console.log(cmd.toString())
    throw new Error('Unknown cmd type')
  }
  if (opts) {
    // TODO: optimize this
    cmd = Object.assign({}, cmd, opts)
    if (cmd.uniforms && opts.uniforms) {
      cmd.uniforms = Object.assign({}, cmd.uniforms, opts.uniforms)
    }
  }

  var pushedStates = 0

  var ctx = this._ctx
  if (cmd.framebuffer) {
    ctx.pushState(ctx.FRAMEBUFFER_BIT)
    ctx.bindFramebuffer(cmd.framebuffer)
    pushedStates++
    if (cmd.framebufferColorAttachments) {
      // FIXME: this modifies the framebuffer permamently after the call
      for (var attachmentIndex in cmd.framebufferColorAttachments) {
        var colorAttachment = cmd.framebufferColorAttachments[attachmentIndex]
        var index = parseInt(attachmentIndex, 10)
        cmd.framebuffer.setColorAttachment(index, colorAttachment.target, colorAttachment.handle, colorAttachment.level)
      }
    }
    if (cmd.framebufferDepthAttachment) {
      // FIXME: this modifies the framebuffer permamently after the call
      var depthAttachment = cmd.framebufferDepthAttachment
      cmd.framebuffer.setDepthAttachment(depthAttachment.target, depthAttachment.handle, depthAttachment.level)
    }
  }

  var clearFlags = 0
  if (cmd.color !== undefined) {
    ctx.pushState(ctx.COLOR_BIT)
    pushedStates++
    ctx.setClearColor(cmd.color[0], cmd.color[1], cmd.color[2], cmd.color[3])
    clearFlags |= ctx.COLOR_BIT
  }
  if (cmd.depth !== undefined) {
    ctx.pushState(ctx.DEPTH_BIT)
    pushedStates++
    ctx.setClearDepth(cmd.depth)
    clearFlags |= ctx.DEPTH_BIT
  }
  if (clearFlags) {
    ctx.clear(clearFlags)
  }

  if (cmd.program !== undefined) {
    if (this._prevProgram !== cmd.program) {
      ctx.bindProgram(cmd.program)
      this._prevProgram = cmd.program
      if (!cmd.program._prevUniforms) {
        cmd.program._prevUniforms = {}
      }
    }
  }

  if (cmd.uniforms !== undefined) {
    applyUniforms(ctx, cmd.program, cmd.uniforms, cmd.program._prevUniforms, this._prevTextures, this.debug)
  }

  if (cmd.projectionMatrix !== undefined) {
    ctx.pushState(ctx.MATRIX_PROJECTION_BIT)
    pushedStates++
    ctx.setProjectionMatrix(cmd.projectionMatrix)
  }

  if (cmd.viewMatrix !== undefined) {
    ctx.pushState(ctx.MATRIX_VIEW_BIT)
    pushedStates++
    ctx.setViewMatrix(cmd.viewMatrix)
  }

  if (cmd.modelMatrix !== undefined) {
    ctx.pushState(ctx.MATRIX_MODEL_BIT)
    pushedStates++
    ctx.setModelMatrix(cmd.modelMatrix)
  }

  if (cmd.viewport !== undefined) {
    ctx.pushState(ctx.VIEWPORT_BIT)
    pushedStates++
    ctx.setViewport(cmd.viewport[0], cmd.viewport[1], cmd.viewport[2], cmd.viewport[3])
  }

  if (cmd.depthTest !== undefined) {
    ctx.pushState(ctx.DEPTH_BIT)
    pushedStates++
    ctx.setDepthTest(cmd.depthTest)
  }

  if (cmd.cullFace !== undefined) {
    ctx.pushState(ctx.CULL_BIT)
    pushedStates++
    ctx.setCullFace(cmd.cullFace)
  }

  if (cmd.cullFaceMode !== undefined) {
    ctx.pushState(ctx.CULL_BIT)
    pushedStates++
    ctx.setCullFaceMode(cmd.cullFaceMode)
  }

  if (cmd.colorMask !== undefined) {
    ctx.pushState(ctx.COLOR_BIT)
    pushedStates++
    ctx.setColorMask(cmd.colorMask[0], cmd.colorMask[1], cmd.colorMask[2], cmd.colorMask[3])
  }

  if (cmd.mesh) {
    ctx.bindMesh(cmd.mesh)
    ctx.drawMesh()
  }

  if (cmd.vertexArray) {
    ctx.bindVertexArray(cmd.vertexArray)
    ctx.drawElements(cmd.primitiveType, cmd.count, 0)
  }

  if (subCommanDraw) {
    subCommanDraw()
  }

  // if (this.debug) console.log(' ', 'pushedStates', pushedStates)
  for (var i = 0; i < pushedStates; i++) {
    ctx.popState()
  }
}

// force execute of all commands in the queue
CommandQueue.prototype.flush = function () {
  if (this.profile) {
    console.log('CommandQueue', 'numCommands', this._commands, 'updatedUniforms', Object.keys(updatedUniforms).length, 'createdCommands', createdCommands)
  }
  this._prevProgram = null
  this._prevTextures.length = 0
  this._commands = 0
  if (this.profile) {
    console.log('CommandQueue', 'updatedUniforms', updatedUniforms)
  }
  updatedUniforms = {}
  createdCommands = 0
}

module.exports = CommandQueue
<|endoftext|>


<commit_before>import { helper } from '@ember/component/helper';
import { hubURL } from "@cardstack/plugin-utils/environment";

export function csImageUrl([imageOrFile]) {
  let id;
  if (imageOrFile.constructor.modelName === 'cardstack-file') {
    id = imageOrFile.get('id');
  } else {
    id = imageOrFile.belongsTo('file').id()
  }
  return `${hubURL}/api/cardstack-files/${id}`;
}

export default helper(csImageUrl);
<commit_msg>friendlier image url helper<commit_after>import { helper } from '@ember/component/helper';
import { hubURL } from "@cardstack/plugin-utils/environment";

export function csImageUrl(imageOrFile) {
  let id;
  if (imageOrFile.constructor.modelName === 'cardstack-file') {
    id = imageOrFile.get('id');
  } else {
    id = imageOrFile.belongsTo('file').id()
  }
  return `${hubURL}/api/cardstack-files/${id}`;
}

export default helper(function([imageOrFile]) {
  return csImageUrl(imageOrFile);
});
<|endoftext|>


<commit_before>/* eslint-disable no-console */
import chai from 'chai';
import dirty from 'dirty-chai';
import sinonChai from 'sinon-chai';
import sinon from 'sinon';
import fs from 'fs';
import path from 'path';
import shell from 'shelljs';
import electron from 'electron';
import { Application } from 'spectron';
import mockery from 'mockery';

import paths from '../helpers/paths';
import meteorDesktop from '../../lib/index';

shell.config.fatal = true;

chai.use(sinonChai);
chai.use(dirty);
const { describe, it } = global;
const { expect } = chai;

/**
 * This is first experimental integration test.
 */

let appDir = '';

/**
 * Waits until a promise from a function finally returns true.
 * @param {Function} functionReturningPromise - function to test
 * @param {number}   ms                       - expiration timeout in milliseconds
 * @returns {Promise}
 */
function waitFor(functionReturningPromise, ms = 10000) {
    return new Promise((resolve, reject) => {
        let invokerTimeout;
        let timeout;
        const invokeFunction = () =>
            functionReturningPromise()
                .then((result) => {
                    console.log(result);
                    if (result) {
                        clearTimeout(invokerTimeout);
                        clearTimeout(timeout);
                        resolve();
                    } else {
                        invokerTimeout = setTimeout(invokeFunction, 500);
                    }
                })
                .catch(() => {
                    invokerTimeout = setTimeout(invokeFunction, 500);
                });
        invokeFunction();
        timeout = setTimeout(() => {
            clearTimeout(invokerTimeout);
            reject('timeout expired on waitFor');
        }, ms);
    });
}

/**
 * Waits for the app to load and appear.
 * @param {Object} app - test app
 * @returns {{app: (Application|*), window: *}}
 */
async function waitForApp(app) {
    await app.client.waitUntilWindowLoaded();
    const window = app.browserWindow;
    // Wait for the main window for max 30seconds. Adjust to your app.
    await waitFor(window.isVisible, 30000);
    expect(await app.client.getWindowCount()).to.equal(1);
    await app.client.waitUntil(
        async () => app.client.execute(
            () => document.readyState === 'complete'
        )
    );
    return { app, window };
}

describe('desktop', () => {
    let MeteorDesktop;

    before(() => {
        appDir = path.join(paths.testsIntegrationTmpPath, 'test-desktop');
    });

    beforeEach(() => {
        try {
            fs.unlinkSync('meteor.log');
        } catch (e) {
            // No worries...
        }
    });

    describe('add to scripts', () => {
        let exitStub;

        before(() => {
            mockery.registerMock('path', {
                resolve: dir => dir,
                join: () => `${appDir}${path.sep}package.json`
            });
            mockery.enable({
                warnOnReplace: false,
                warnOnUnregistered: false
            });
        });
        after(() => {
            mockery.deregisterMock('path');
            mockery.disable();
            exitStub.restore();
        });

        it('should add a `desktop` entry in package.json', () => {
            exitStub = sinon.stub(process, 'exit');
            require('../../lib/scripts/addToScripts'); // eslint-disable-line
            const packageJson = JSON.parse(fs.readFileSync(path.join(appDir, 'package.json'), 'utf8'));
            expect(exitStub).to.have.callCount(0);
            expect(packageJson.scripts.desktop).to.be.equal('meteor-desktop');
        });
    });

    describe('build with params --scaffold -b', () => {
        let exitStub;
        let app;

        after(async () => {
            exitStub.restore();
            if (app && app.isRunning()) {
                await app.stop();
            }
        });

        it('should create a build', async () => {
            exitStub = sinon.stub(process, 'exit', () => {
                try {
                    console.log(fs.readFileSync('meteor.log', 'utf8'));
                } catch (e) {
                    // Nothing to do.
                }
                process.exit(1);
            });
            // Load plugins directly from the package instead of those published to atmosphere.
            process.env.METEOR_PACKAGE_DIRS = path.resolve(path.join(__dirname, '..', '..', 'plugins'));
            process.env.MONGO_URL = 'none';
            MeteorDesktop = meteorDesktop(
                appDir,
                appDir,
                {
                    ddpUrl: 'http://127.0.0.1:3080',
                    scaffold: true,
                    build: true,
                    skipMobileBuild: !!process.env.TRAVIS,
                    forceCordovaBuild: !!process.env.TRAVIS
                }
            );
            // Build the app.
            await MeteorDesktop.build();

            // Run it.
            app = new Application({
                path: electron,
                args: [path.join(appDir, '.meteor', 'desktop-build')],
                requireName: 'electronRequire',
                startTimeout: 60000,
                env: {
                    NODE_ENV: 'test',
                    ELECTRON_ENV: 'test',
                    METEOR_DESKTOP_NO_SPLASH_SCREEN: 1
                },
                chromeDriverLogPath: path.join(__dirname, 'chrome.log')
            });
            try {
                await app.start();
                await waitForApp(app);
            } catch (e) {
                console.log(e);
                console.log(e.trace);
                console.log(fs.readFileSync(path.join(__dirname, 'chrome.log'), 'utf-8'));
            }
            const title = await app.client.getTitle();
            expect(title).to.equal('test-desktop');
            const text = await app.client.getText('h1');
            expect(text).to.equal('Welcome to Meteor!');
        }).timeout(10 * 60000);
    });
});
<commit_msg>Fix tests<commit_after>/* eslint-disable no-console */
import chai from 'chai';
import dirty from 'dirty-chai';
import sinonChai from 'sinon-chai';
import sinon from 'sinon';
import fs from 'fs';
import path from 'path';
import shell from 'shelljs';
import electron from 'electron';
import { Application } from 'spectron';
import mockery from 'mockery';

import paths from '../helpers/paths';
import meteorDesktop from '../../lib/index';

shell.config.fatal = true;

chai.use(sinonChai);
chai.use(dirty);
const { describe, it } = global;
const { expect } = chai;

/**
 * This is first experimental integration test.
 */

let appDir = '';

/**
 * Waits until a promise from a function finally returns true.
 * @param {Function} functionReturningPromise - function to test
 * @param {number}   ms                       - expiration timeout in milliseconds
 * @returns {Promise}
 */
function waitFor(functionReturningPromise, ms = 10000) {
    return new Promise((resolve, reject) => {
        let invokerTimeout;
        let timeout;
        const invokeFunction = () =>
            functionReturningPromise()
                .then((result) => {
                    console.log(result);
                    if (result) {
                        clearTimeout(invokerTimeout);
                        clearTimeout(timeout);
                        resolve();
                    } else {
                        invokerTimeout = setTimeout(invokeFunction, 500);
                    }
                })
                .catch(() => {
                    invokerTimeout = setTimeout(invokeFunction, 500);
                });
        invokeFunction();
        timeout = setTimeout(() => {
            clearTimeout(invokerTimeout);
            reject('timeout expired on waitFor');
        }, ms);
    });
}

/**
 * Waits for the app to load and appear.
 * @param {Object} app - test app
 * @returns {{app: (Application|*), window: *}}
 */
async function waitForApp(app) {
    await app.client.waitUntilWindowLoaded();
    const window = app.browserWindow;
    // Wait for the main window for max 30seconds. Adjust to your app.
    await waitFor(window.isVisible, 30000);
    expect(await app.client.getWindowCount()).to.equal(1);
    await app.client.waitUntil(
        async () => app.client.execute(
            () => document.readyState === 'complete'
        )
    );
    return { app, window };
}

describe('desktop', () => {
    let MeteorDesktop;

    before(() => {
        appDir = path.join(paths.testsIntegrationTmpPath, 'test-desktop');
    });

    beforeEach(() => {
        try {
            fs.unlinkSync('meteor.log');
        } catch (e) {
            // No worries...
        }
    });

    describe('add to scripts', () => {
        let exitStub;

        before(() => {
            mockery.registerMock('path', {
                resolve: dir => dir,
                join: () => `${appDir}${path.sep}package.json`
            });
            mockery.enable({
                warnOnReplace: false,
                warnOnUnregistered: false
            });
        });
        after(() => {
            mockery.deregisterMock('path');
            mockery.disable();
            exitStub.restore();
        });

        it('should add a `desktop` entry in package.json', () => {
            exitStub = sinon.stub(process, 'exit');
            require('../../lib/scripts/addToScripts'); // eslint-disable-line
            const packageJson = JSON.parse(fs.readFileSync(path.join(appDir, 'package.json'), 'utf8'));
            expect(exitStub).to.have.callCount(0);
            expect(packageJson.scripts.desktop).to.be.equal('meteor-desktop');
        });
    });

    describe('build with params --scaffold -b', () => {
        let exitStub;
        let app;

        after(async () => {
            exitStub.restore();
            if (app && app.isRunning()) {
                await app.stop();
            }
        });

        it('should create a build', async () => {
            exitStub = sinon.stub(process, 'exit', () => {
                try {
                    console.log(fs.readFileSync('meteor.log', 'utf8'));
                } catch (e) {
                    // Nothing to do.
                }
                process.exit(1);
            });
            // Load plugins directly from the package instead of those published to atmosphere.
            process.env.METEOR_PACKAGE_DIRS = path.resolve(path.join(__dirname, '..', '..', 'plugins'));
            process.env.MONGO_URL = 'none';
            MeteorDesktop = meteorDesktop(
                appDir,
                appDir,
                {
                    ddpUrl: 'http://127.0.0.1:3080',
                    scaffold: true,
                    build: true,
                    output: appDir,
                    skipMobileBuild: !!process.env.TRAVIS,
                    forceCordovaBuild: !!process.env.TRAVIS
                }
            );
            // Build the app.
            await MeteorDesktop.build();

            // Run it.
            app = new Application({
                path: electron,
                args: [path.join(appDir, '.meteor', 'desktop-build')],
                requireName: 'electronRequire',
                startTimeout: 60000,
                env: {
                    NODE_ENV: 'test',
                    ELECTRON_ENV: 'test',
                    METEOR_DESKTOP_NO_SPLASH_SCREEN: 1
                },
                chromeDriverLogPath: path.join(__dirname, 'chrome.log')
            });
            try {
                await app.start();
                await waitForApp(app);
            } catch (e) {
                console.log(e);
                console.log(e.trace);
                console.log(fs.readFileSync(path.join(__dirname, 'chrome.log'), 'utf-8'));
            }
            const title = await app.client.getTitle();
            expect(title).to.equal('test-desktop');
            const text = await app.client.getText('h1');
            expect(text).to.equal('Welcome to Meteor!');
        }).timeout(10 * 60000);
    });
});
<|endoftext|>


<commit_before>// Show usercard by click profile link.
//
'use strict';

N.wire.once('navigate.done', function init_usercard_click() {
  let $body = $('body');
  let $fake_popover = $('

').appendTo($body);
  let POPOVER_WIDTH = $fake_popover.outerWidth(true);
  let POPOVER_HEIGHT = $fake_popover.outerHeight(true);
  let popover_shown = false;

  $fake_popover.remove();

  // Add click handler to `._ucard-popover`.
  //
  $body.on('click', '._ucard-popover', function (event) {
    let $container = $('.layout__container');
    let $link = $(this);

    // Skip for devices with small screens (navigate profile page).
    if (POPOVER_WIDTH * 1.5 > $container.width() ||
        POPOVER_HEIGHT * 2 > $(window).height()) {
      return;
    }

    // Try parse href to get `user_hid` from member page link.
    let user_hid = N.router.matchAll($link.attr('href'))
      .find(match => match.meta?.methods?.get === 'users.member')?.params?.user_hid;

    if (!user_hid) return;

    // Prevent default navigator behaviour.
    event.preventDefault();

    N.io.rpc(module.apiPath, { user_hid })
      .then(function (res) {
        // Add reference info to template data.
        // Example: "fp:fp4c8153c09f81af617c72a584"
        // Can be used to pre-fill title & content via hooks
        let ref = $link.data('user-ref');
        if (ref) res.ref = ref;

        let pos_left = $link.offset().left + $link.innerWidth();
        let $card = $(N.runtime.render(module.apiPath, res));

        if (pos_left + POPOVER_WIDTH > $container.offset().left + $container.width()) {

          // If popover with offset get out container edge - show it under
          // link near right container edge.
          $card.css({
            top: $link.offset().top + $link.outerHeight(),
            right: ($(window).width() - $container.width()) / 2
          });

          $card.addClass('ucard-popover__m-bottom');
        } else {

          // Show at one line with link.
          $card.css({
            top: $link.offset().top,
            left: pos_left
          });
        }

        $card.appendTo($body).fadeIn('fast');

        popover_shown = true;
      })
      .catch(err => {
        if (err.code !== N.io.NOT_FOUND) {
          throw err;
        }

        N.wire.emit('notify', t('error'));
      });
  });

  // Close popover by click outside
  //
  $body.on('click', function (e) {

    // If shown
    if (popover_shown) {

      // If click inside popover
      if (!$(e.target).closest('#ucard-popover').length) {
        $('#ucard-popover').remove();
        popover_shown = false;
      }
    }
  });

  // Close popover on page leave
  //
  N.wire.on('navigate.exit', function page_leave() {
    if (popover_shown) {
      $('#ucard-popover').remove();
      popover_shown = false;
    }
  });

  // Create new dialog with user
  //
  N.wire.on(module.apiPath + ':message', function create_dialog(data) {
    let params = {
      nick: data.$this.data('to-nick'),
      hid: data.$this.data('to-hid'),
      ref: data.$this.data('ref')
    };

    return N.wire.emit('users.dialog.create:begin', params)
      .then(() => {
        if (popover_shown) {
          $('#ucard-popover').remove();
          popover_shown = false;
        }
      });
  });
});
<commit_msg>Load users package when needed<commit_after>// Show usercard by click profile link.
//
'use strict';

N.wire.once('navigate.done', function init_usercard_click() {
  let $body = $('body');
  let $fake_popover = $('

').appendTo($body);
  let POPOVER_WIDTH = $fake_popover.outerWidth(true);
  let POPOVER_HEIGHT = $fake_popover.outerHeight(true);
  let popover_shown = false;

  $fake_popover.remove();

  // Add click handler to `._ucard-popover`.
  //
  $body.on('click', '._ucard-popover', function (event) {
    let $container = $('.layout__container');
    let $link = $(this);

    // Skip for devices with small screens (navigate profile page).
    if (POPOVER_WIDTH * 1.5 > $container.width() ||
        POPOVER_HEIGHT * 2 > $(window).height()) {
      return;
    }

    // Try parse href to get `user_hid` from member page link.
    let user_hid = N.router.matchAll($link.attr('href'))
      .find(match => match.meta?.methods?.get === 'users.member')?.params?.user_hid;

    if (!user_hid) return;

    // Prevent default navigator behaviour.
    event.preventDefault();

    N.io.rpc(module.apiPath, { user_hid })
      .then(function (res) {
        // Add reference info to template data.
        // Example: "fp:fp4c8153c09f81af617c72a584"
        // Can be used to pre-fill title & content via hooks
        let ref = $link.data('user-ref');
        if (ref) res.ref = ref;

        let pos_left = $link.offset().left + $link.innerWidth();
        let $card = $(N.runtime.render(module.apiPath, res));

        if (pos_left + POPOVER_WIDTH > $container.offset().left + $container.width()) {

          // If popover with offset get out container edge - show it under
          // link near right container edge.
          $card.css({
            top: $link.offset().top + $link.outerHeight(),
            right: ($(window).width() - $container.width()) / 2
          });

          $card.addClass('ucard-popover__m-bottom');
        } else {

          // Show at one line with link.
          $card.css({
            top: $link.offset().top,
            left: pos_left
          });
        }

        $card.appendTo($body).fadeIn('fast');

        popover_shown = true;
      })
      .catch(err => {
        if (err.code !== N.io.NOT_FOUND) {
          throw err;
        }

        N.wire.emit('notify', t('error'));
      });
  });

  // Close popover by click outside
  //
  $body.on('click', function (e) {

    // If shown
    if (popover_shown) {

      // If click inside popover
      if (!$(e.target).closest('#ucard-popover').length) {
        $('#ucard-popover').remove();
        popover_shown = false;
      }
    }
  });

  // Close popover on page leave
  //
  N.wire.on('navigate.exit', function page_leave() {
    if (popover_shown) {
      $('#ucard-popover').remove();
      popover_shown = false;
    }
  });

  // Create new dialog with user
  //
  N.wire.on(module.apiPath + ':message', function create_dialog(data) {
    let params = {
      nick: data.$this.data('to-nick'),
      hid: data.$this.data('to-hid'),
      ref: data.$this.data('ref')
    };

    return Promise.resolve()
      .then(() => N.loader.loadAssets('users'))
      .then(() => N.wire.emit('users.dialog.create:begin', params))
      .then(() => {
        if (popover_shown) {
          $('#ucard-popover').remove();
          popover_shown = false;
        }
      });
  });
});
<|endoftext|>


<commit_before>describe('verticalBarchart directive', function () {
	'use strict';

	var createElement, element, scope, statsData, isolateScope;
	var flushAllD3Transitions = function () {
		var now = Date.now;
		Date.now = function () {
			return Infinity;
		};
		d3.timer.flush();
		Date.now = now;
	};

	beforeEach(module('talend.widget'));
	beforeEach(inject(function ($rootScope, $compile) {
		statsData = [
			{'data': [0, 5], 'occurrences': 9},
			{'data': [5, 10], 'occurrences': 8},
			{'data': [10, 15], 'occurrences': 6},
			{'data': [15, 20], 'occurrences': 5}
		];

		createElement = function () {

			scope = $rootScope.$new();
			scope.visData = null;
			scope.existingFilter = null;
			scope.clicked = false;
			scope.onclck = function () {
				scope.clicked = true;
			};

			element = angular.element('<vertical-barchart id="barChart" width="250" height="400"' +
				'on-click="onclck"' +
				'visu-data="visData"' +
				'key-field="data"' +
				'existing-filter="existingFilter"'+
				'value-field="occurrences"' +
				'></vertical-barchart>');

			angular.element('body').append(element);
			$compile(element)(scope);
			scope.$digest();

			isolateScope = element.isolateScope();
		};
	}));

	beforeEach(function () {
		jasmine.clock().install();
	});
	afterEach(function () {
		jasmine.clock().uninstall();

		scope.$destroy();
		element.remove();
	});

	it('should render all bars after a 100ms delay', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);

		//then
		expect(element.find('rect').length).toBe(statsData.length * 2);
		expect(element.find('.bg-rect').length).toBe(statsData.length);
		expect(element.find('.bar').length).toBe(statsData.length);
		expect(element.find('.grid').length).toBe(1);
	});

	it('should check the initial bars opacity', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);

		//then
		_.each(isolateScope.buckets[0], function(bucket){
			expect(d3.select(bucket).style('opacity')).toBe('1');
		});
	});

	it('should update the bars opacity after applying a filter outside the bars ranges', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		//when
		scope.existingFilter = [105, 200];
		scope.$digest();
		jasmine.clock().tick(600);

		flushAllD3Transitions();

		//then
		_.each(isolateScope.buckets[0], function(bucket){
			var opac = +(d3.select(bucket).style('opacity'));
			expect(opac.toFixed(1)).toBe('0.4');
		});
	});

	it('should update the bars opacity after applying a filter intersecting with 1 bar range', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		//when
		scope.existingFilter = [15, 20];
		scope.$digest();
		jasmine.clock().tick(600);

		flushAllD3Transitions();

		//then
		var opacities = [0.4, 0.4, 0.4, 1];

		_.each(isolateScope.buckets[0], function(bucket, index){
			var opac = +(d3.select(bucket).style('opacity'));
			opac = +opac.toFixed(1);
			expect(opac).toBe(opacities[index]);
		});
	});

	it('should update the bars opacity after applying a filter intersecting with to 2 bar range', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		//when
		scope.existingFilter = [13, 20];
		scope.$digest();
		jasmine.clock().tick(600);

		flushAllD3Transitions();

		//then
		var opacities = [0.4, 0.4, 1, 1];

		_.each(isolateScope.buckets[0], function(bucket, index){
			var opac = +(d3.select(bucket).style('opacity'));
			opac = +opac.toFixed(1);
			expect(opac).toBe(opacities[index]);
		});
	});
});<commit_msg>TDP-502 TDP-276 TDP-525 TU WIP<commit_after>describe('verticalBarchart directive', function () {
	'use strict';

	var createElement, element, scope, statsData, isolateScope;
	var flushAllD3Transitions = function () {
		var now = Date.now;
		Date.now = function () {
			return Infinity;
		};
		d3.timer.flush();
		Date.now = now;
	};

	beforeEach(module('talend.widget'));
	beforeEach(inject(function ($rootScope, $compile) {
		statsData = [
			{'data': [0, 5], 'occurrences': 9},
			{'data': [5, 10], 'occurrences': 8},
			{'data': [10, 15], 'occurrences': 6},
			{'data': [15, 20], 'occurrences': 5}
		];

		createElement = function () {

			scope = $rootScope.$new();
			scope.visData = null;
			scope.existingFilter = null;
			scope.onclck = function(obj){
				console.log(obj);
			};//jasmine.createSpy('spy');

			element = angular.element('<vertical-barchart id="barChart" width="250" height="400"' +
				'on-click="onclck"' +
				'visu-data="visData"' +
				'key-field="data"' +
				'existing-filter="existingFilter"'+
				'value-field="occurrences"' +
				'></vertical-barchart>');

			angular.element('body').append(element);
			$compile(element)(scope);
			scope.$digest();

			isolateScope = element.isolateScope();
		};
	}));

	beforeEach(function () {
		jasmine.clock().install();
	});
	afterEach(function () {
		jasmine.clock().uninstall();

		scope.$destroy();
		element.remove();
	});

	it('should render all bars after a 100ms delay', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);

		//then
		expect(element.find('rect').length).toBe(statsData.length * 2);
		expect(element.find('.bg-rect').length).toBe(statsData.length);
		expect(element.find('.bar').length).toBe(statsData.length);
		expect(element.find('.grid').length).toBe(1);
	});

	it('should check the initial bars opacity', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);

		//then
		_.each(isolateScope.buckets[0], function(bucket){
			expect(d3.select(bucket).style('opacity')).toBe('1');
		});
	});

	it('should update the bars opacity after applying a filter outside the bars ranges', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		//when
		scope.existingFilter = [105, 200];
		scope.$digest();
		jasmine.clock().tick(600);

		flushAllD3Transitions();

		//then
		_.each(isolateScope.buckets[0], function(bucket){
			var opac = +(d3.select(bucket).style('opacity'));
			expect(opac.toFixed(1)).toBe('0.4');
		});
	});

	it('should update the bars opacity after applying a filter intersecting with 1 bar range', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		//when
		scope.existingFilter = [15, 20];
		scope.$digest();
		jasmine.clock().tick(600);

		flushAllD3Transitions();

		//then
		var opacities = [0.4, 0.4, 0.4, 1];

		_.each(isolateScope.buckets[0], function(bucket, index){
			var opac = +(d3.select(bucket).style('opacity'));
			opac = +opac.toFixed(1);
			expect(opac).toBe(opacities[index]);
		});
	});

	it('should update the bars opacity after applying a filter intersecting with to 2 bar range', function () {
		//given
		createElement();

		//when
		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		//when
		scope.existingFilter = [13, 20];
		scope.$digest();
		jasmine.clock().tick(600);

		flushAllD3Transitions();

		//then
		var opacities = [0.4, 0.4, 1, 1];

		_.each(isolateScope.buckets[0], function(bucket, index){
			var opac = +(d3.select(bucket).style('opacity'));
			opac = +opac.toFixed(1);
			expect(opac).toBe(opacities[index]);
		});
	});

	it('should trigger filter propagation', function () {
		//given
		createElement();

		scope.visData = statsData;
		scope.$digest();
		jasmine.clock().tick(100);
		flushAllD3Transitions();

		spyOn(scope, 'onclck').and.returnValue();

		var bgBar2 = $(d3.selectAll('.bg-rect')[0][2]);
		//var event = angular.element.Event('click');
		bgBar2.click();
		//then
		//bgBar2.trigger(event);
		expect(scope.onclck).toHaveBeenCalledWith({'data': [10, 15], 'occurrences': 6});
	});
});<|endoftext|>


<commit_before>'use strict';

const request = require('request-promise');
const tokens = require('./token.js');

const getUserInfo = (psid) => {
  return request({
    uri: 'https://graph.facebook.com/v2.8/' + psid,
    method: 'GET',
    json: true, headers: {
      'Content-Type': 'application/json'
    },
    qs: {
      access_token: tokens.FB_PAGE_TOKEN
    }
  }).then((response) => {
    console.log('GET', 'https://graph.facebook.com/v2.8/' + psid + '?access_token=FB_PAGE_TOKEN');
    console.log(response);
    return JSON.parse(response);
  });
};

module.exports = {
  user: getUserInfo
};
<commit_msg>Maybe it's not JSON<commit_after>'use strict';

const request = require('request-promise');
const tokens = require('./token.js');

const getUserInfo = (psid) => {
  return request({
    uri: 'https://graph.facebook.com/v2.8/' + psid,
    method: 'GET',
    json: true, headers: {
      'Content-Type': 'application/json'
    },
    qs: {
      access_token: tokens.FB_PAGE_TOKEN
    }
  }).then((response) => {
    console.log('GET', 'https://graph.facebook.com/v2.8/' + psid + '?access_token=FB_PAGE_TOKEN');
    return response;
  });
};

module.exports = {
  user: getUserInfo
};
<|endoftext|>


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

var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/wiktionaryToMongo';
var LOG_EVERY = 1000;
var LIMIT = null;
var path = require('path');
var fs = require('fs');
// var lineStream = require('line-stream');

var forkfriend = require('forkfriend');

console.log("FOUND CPUS: ",require('os').cpus());
var numberWorkers  = require('os').cpus().length;

var manager = forkfriend({
  respawnInterval:300,
  maxQueue:numberWorkers * 2
});

var spinupTime = numberWorkers * 500;
manager.add(path.join(__dirname, 'analyze_worker.js'),numberWorkers);

setTimeout(function(){
  MongoClient.connect(url, function(err, db) {

    var col = db.collection('enWiktionaryDump');
    var colOutput = db.collection('enWiktionary');

      var cursor = col.find({}, {title:1, namespace:1}, {timeout:true});
      var index = 0;
      var indexSaved = 0;
      if (LIMIT)
        cursor = cursor.limit(LIMIT);
      cursor.count(function(err, total){
        console.time("total");

        var inputStream = cursor.stream();
        inputStream.pipe(manager).pipe(process.stdout);
        inputStream.on('end', function() {
          // console.log('there will be no more data.');
          // db.close();
          console.log("READ finished");
        });

        manager.on('data', function() {
          indexSaved++
          if (indexSaved % LOG_EVERY==0) {
            console.log("ANALYZED: "+indexSaved+'/'+total);
          }
          if (indexSaved>=total) {
            console.log("EXIT");
            console.timeEnd("total");

            db.close(function(err) {
              manager.stop();
            });
          }
        });
        // manager.removeAllListeners('drain');
        manager.removeAllListeners('end');
        inputStream.on('data', function() {
          index++
          if (index % LOG_EVERY==0) {
            console.log("READ: "+indexSaved+'/'+total);
          }
        });
      });

  });
}, spinupTime);
<commit_msg>throttling of the stream<commit_after>#!/usr/bin/env node

var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/wiktionaryToMongo';
var LOG_EVERY = 100;
var LIMIT = null;
var path = require('path');
var fs = require('fs');
// var lineStream = require('line-stream');

var forkfriend = require('forkfriend');

console.log("FOUND CPUS: ",require('os').cpus());
var numberWorkers  = require('os').cpus().length;
var MAXQUEUE =numberWorkers;

var manager = forkfriend({
  respawnInterval:300,
  maxQueue:numberWorkers * 2
});
var spinupTime = numberWorkers * 500;
manager.add(path.join(__dirname, 'analyze_worker.js'),numberWorkers);

setTimeout(function(){
  MongoClient.connect(url, function(err, db) {

    var col = db.collection('enWiktionaryDump');
    var colOutput = db.collection('enWiktionary');

      var cursor = col.find({}, {title:1, namespace:1}, {timeout:true});
      var index = 0;
      var indexSaved = 0;
      if (LIMIT)
        cursor = cursor.limit(LIMIT);
      cursor.count(function(err, total){
        console.time("total");

        var inputStream = cursor.stream();
        var inputStreamPlayPause = function() {
          if (index - indexSaved<MAXQUEUE)
            inputStream.resume();
          else
            inputStream.pause();
        }
        manager.pipe(process.stdout);
        inputStream.on('data', function(chunk) {
          manager.write(chunk);
          index++
          inputStreamPlayPause();
          if (index % LOG_EVERY==0) {
            console.log("READ: "+index+'/'+total);
          }
        });

        inputStream.on('end', function() {
          // console.log('there will be no more data.');
          // db.close();
          console.log("READ finished");
        });

        manager.on('data', function() {
          indexSaved++
          inputStreamPlayPause();

          if (indexSaved % LOG_EVERY==0) {
            console.log("ANALYZED: "+indexSaved+'/'+total);
          }
          if (indexSaved>=total) {
            console.log("EXIT");
            console.timeEnd("total");

            db.close(function(err) {
              manager.stop();
            });
          }
        });
        // manager.removeAllListeners('drain');
        manager.removeAllListeners('end');

      });

  });
}, spinupTime);
<|endoftext|>


<commit_before>"use strict";

var log_data = [];

function do_the_log(message)
{
    if(LOG_TO_FILE)
    {
        log_data.push(message, "\n");
    }
    else
    {
        console.log(message);
    }
}

/**
 * @type {function((string|number), number=)}
 * @const
 */
var dbg_log = (function()
{
    if(!DEBUG)
    {
        return function() {};
    }

    /** @const @type {Object.<number, string>} */
    var dbg_names = LOG_NAMES.reduce(function(a, x)
    {
        a[x[0]] = x[1];
        return a;
    }, {});

    var log_last_message = "";
    var log_message_repetitions = 0;

    /**
     * @param {number=} level
     */
    function dbg_log_(stuff, level)
    {
        if(!DEBUG) return;

        level = level || 1;

        if(level & LOG_LEVEL)
        {
            var level_name = dbg_names[level] || "",
                message = "[" + v86util.pads(level_name, 4) + "] " + stuff;

            if(message === log_last_message)
            {
                log_message_repetitions++;

                if(log_message_repetitions < 2048)
                {
                    return;
                }
            }

            var now = new Date();
            var time_str = v86util.pad0(now.getHours(), 2) + ":" +
                           v86util.pad0(now.getMinutes(), 2) + ":" +
                           v86util.pad0(now.getSeconds(), 2) + "+" +
                           v86util.pad0(now.getMilliseconds(), 3) + " ";

            if(log_message_repetitions)
            {
                if(log_message_repetitions === 1)
                {
                    do_the_log(time_str + log_last_message);
                }
                else
                {
                    do_the_log("Previous message repeated " + log_message_repetitions + " times");
                }

                log_message_repetitions = 0;
            }

            do_the_log(time_str + message);
            log_last_message = message;
        }
    }

    return dbg_log_;
})();

/**
 * @param {number=} level
 */
function dbg_trace(level)
{
    if(!DEBUG) return;

    dbg_log(Error().stack.replace(/(?:(?:t|t16|t32)\.\(anonymous function\)\.)+/g, "t.(anonymous function)."), level);
}

/**
 * console.assert is fucking slow
 * @param {string=} msg
 * @param {number=} level
 */
function dbg_assert(cond, msg, level)
{
    if(!DEBUG) return;

    if(!cond)
    {
        dbg_assert_failed(msg);
    }
}

function dbg_assert_failed(msg)
{
    debugger;
    console.trace();

    if(msg)
    {
        throw "Assert failed: " + msg;
    }
    else
    {
        throw "Assert failed";
    }
}
<commit_msg>Remove remains of old js cpu code<commit_after>"use strict";

var log_data = [];

function do_the_log(message)
{
    if(LOG_TO_FILE)
    {
        log_data.push(message, "\n");
    }
    else
    {
        console.log(message);
    }
}

/**
 * @type {function((string|number), number=)}
 * @const
 */
var dbg_log = (function()
{
    if(!DEBUG)
    {
        return function() {};
    }

    /** @const @type {Object.<number, string>} */
    var dbg_names = LOG_NAMES.reduce(function(a, x)
    {
        a[x[0]] = x[1];
        return a;
    }, {});

    var log_last_message = "";
    var log_message_repetitions = 0;

    /**
     * @param {number=} level
     */
    function dbg_log_(stuff, level)
    {
        if(!DEBUG) return;

        level = level || 1;

        if(level & LOG_LEVEL)
        {
            var level_name = dbg_names[level] || "",
                message = "[" + v86util.pads(level_name, 4) + "] " + stuff;

            if(message === log_last_message)
            {
                log_message_repetitions++;

                if(log_message_repetitions < 2048)
                {
                    return;
                }
            }

            var now = new Date();
            var time_str = v86util.pad0(now.getHours(), 2) + ":" +
                           v86util.pad0(now.getMinutes(), 2) + ":" +
                           v86util.pad0(now.getSeconds(), 2) + "+" +
                           v86util.pad0(now.getMilliseconds(), 3) + " ";

            if(log_message_repetitions)
            {
                if(log_message_repetitions === 1)
                {
                    do_the_log(time_str + log_last_message);
                }
                else
                {
                    do_the_log("Previous message repeated " + log_message_repetitions + " times");
                }

                log_message_repetitions = 0;
            }

            do_the_log(time_str + message);
            log_last_message = message;
        }
    }

    return dbg_log_;
})();

/**
 * @param {number=} level
 */
function dbg_trace(level)
{
    if(!DEBUG) return;

    dbg_log(Error().stack, level);
}

/**
 * console.assert is fucking slow
 * @param {string=} msg
 * @param {number=} level
 */
function dbg_assert(cond, msg, level)
{
    if(!DEBUG) return;

    if(!cond)
    {
        dbg_assert_failed(msg);
    }
}

function dbg_assert_failed(msg)
{
    debugger;
    console.trace();

    if(msg)
    {
        throw "Assert failed: " + msg;
    }
    else
    {
        throw "Assert failed";
    }
}
<|endoftext|>


<commit_before>'use strict';

module.exports = {

  plugins: [
    'jasmine',
  ],

  extends: [
    'plugin:jasmine/recommended',
  ],

  env: {
    jasmine: true,
  },

  rules: {
    'arrow-body-style': 0,
    'jasmine/no-spec-dupes': [1, 'branch'],
    'jasmine/no-suite-dupes': [1, 'branch'],
  },

};
<commit_msg>Disable retarded jasmine recommended rule<commit_after>'use strict';

module.exports = {

  plugins: [
    'jasmine',
  ],

  extends: [
    'plugin:jasmine/recommended',
  ],

  env: {
    jasmine: true,
  },

  rules: {
    'arrow-body-style': 0,
    'jasmine/newline-before-expect': 0,
    'jasmine/no-spec-dupes': [1, 'branch'],
    'jasmine/no-suite-dupes': [1, 'branch'],
  },

};
<|endoftext|>


<commit_before>import browser from "./browser"
import {domIndex, isEquivalentPosition} from "./dom"
import {hasFocusAndSelection, hasSelection, selectionToDOM} from "./selection"

const observeOptions = {
  childList: true,
  characterData: true,
  characterDataOldValue: true,
  attributes: true,
  attributeOldValue: true,
  subtree: true
}
// IE11 has very broken mutation observers, so we also listen to DOMCharacterDataModified
const useCharData = browser.ie && browser.ie_version <= 11

class SelectionState {
  constructor() {
    this.anchorNode = this.anchorOffset = this.focusNode = this.focusOffset = null
  }

  set(sel) {
    this.anchorNode = sel.anchorNode; this.anchorOffset = sel.anchorOffset
    this.focusNode = sel.focusNode; this.focusOffset = sel.focusOffset
  }

  eq(sel) {
    return sel.anchorNode == this.anchorNode && sel.anchorOffset == this.anchorOffset &&
      sel.focusNode == this.focusNode && sel.focusOffset == this.focusOffset
  }
}

export class DOMObserver {
  constructor(view, handleDOMChange) {
    this.view = view
    this.handleDOMChange = handleDOMChange
    this.queue = []
    this.flushingSoon = false
    this.observer = window.MutationObserver &&
      new window.MutationObserver(mutations => {
        for (let i = 0; i < mutations.length; i++) this.queue.push(mutations[i])
        // IE11 will sometimes (on backspacing out a single character
        // text node after a BR node) call the observer callback
        // before actually updating the DOM, which will cause
        // ProseMirror to miss the change (see #930)
        if (browser.ie && browser.ie_version <= 11 && mutations.some(
          m => m.type == "childList" && m.removedNodes.length ||
               m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length))
          this.flushSoon()
        else
          this.flush()
      })
    this.currentSelection = new SelectionState
    if (useCharData) {
      this.onCharData = e => {
        this.queue.push({target: e.target, type: "characterData", oldValue: e.prevValue})
        this.flushSoon()
      }
    }
    this.onSelectionChange = this.onSelectionChange.bind(this)
    this.suppressingSelectionUpdates = false
  }

  flushSoon() {
    if (!this.flushingSoon) {
      this.flushingSoon = true
      window.setTimeout(() => { this.flushingSoon = false; this.flush() }, 20)
    }
  }

  start() {
    if (this.observer)
      this.observer.observe(this.view.dom, observeOptions)
    if (useCharData)
      this.view.dom.addEventListener("DOMCharacterDataModified", this.onCharData)
    this.connectSelection()
  }

  stop() {
    if (this.observer) {
      let take = this.observer.takeRecords()
      if (take.length) {
        for (let i = 0; i < take.length; i++) this.queue.push(take[i])
        window.setTimeout(() => this.flush(), 20)
      }
      this.observer.disconnect()
    }
    if (useCharData) this.view.dom.removeEventListener("DOMCharacterDataModified", this.onCharData)
    this.disconnectSelection()
  }

  connectSelection() {
    this.view.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange)
  }

  disconnectSelection() {
    this.view.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange)
  }

  suppressSelectionUpdates() {
    this.suppressingSelectionUpdates = true
    setTimeout(() => this.suppressingSelectionUpdates = false, 50)
  }

  onSelectionChange() {
    if (!hasFocusAndSelection(this.view)) return
    if (this.suppressingSelectionUpdates) return selectionToDOM(this.view)
    // Deletions on IE11 fire their events in the wrong order, giving
    // us a selection change event before the DOM changes are
    // reported.
    if (browser.ie && browser.ie_version <= 11 && !this.view.state.selection.empty) {
      let sel = this.view.root.getSelection()
      // Selection.isCollapsed isn't reliable on IE
      if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
        return this.flushSoon()
    }
    this.flush()
  }

  setCurSelection() {
    this.currentSelection.set(this.view.root.getSelection())
  }

  ignoreSelectionChange(sel) {
    if (sel.rangeCount == 0) return true
    let container = sel.getRangeAt(0).commonAncestorContainer
    let desc = this.view.docView.nearestDesc(container)
    return desc && desc.ignoreMutation({type: "selection", target: container.nodeType == 3 ? container.parentNode : container})
  }

  flush() {
    if (!this.view.docView || this.flushingSoon) return
    let mutations = this.observer ? this.observer.takeRecords() : []
    if (this.queue.length) {
      mutations = this.queue.concat(mutations)
      this.queue.length = 0
    }

    let sel = this.view.root.getSelection()
    let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasSelection(this.view) && !this.ignoreSelectionChange(sel)

    let from = -1, to = -1, typeOver = false
    if (this.view.editable) {
      for (let i = 0; i < mutations.length; i++) {
        let result = this.registerMutation(mutations[i])
        if (result) {
          from = from < 0 ? result.from : Math.min(result.from, from)
          to = to < 0 ? result.to : Math.max(result.to, to)
          if (result.typeOver && !this.view.composing) typeOver = true
        }
      }
    }
    if (from > -1 || newSel) {
      if (from > -1) {
        this.view.docView.markDirty(from, to)
        checkCSS(this.view)
      }
      this.handleDOMChange(from, to, typeOver)
      if (this.view.docView.dirty) this.view.updateState(this.view.state)
      else if (!this.currentSelection.eq(sel)) selectionToDOM(this.view)
    }
  }

  registerMutation(mut) {
    let desc = this.view.docView.nearestDesc(mut.target)
    if (mut.type == "attributes" &&
        (desc == this.view.docView || mut.attributeName == "contenteditable" ||
         // Firefox sometimes fires spurious events for null/empty styles
         (mut.attributeName == "style" && !mut.oldValue && !mut.target.getAttribute("style"))))
      return null
    if (!desc || desc.ignoreMutation(mut)) return null

    if (mut.type == "childList") {
      let prev = mut.previousSibling, next = mut.nextSibling
      if (browser.ie && browser.ie_version <= 11 && mut.addedNodes.length) {
        // IE11 gives us incorrect next/prev siblings for some
        // insertions, so if there are added nodes, recompute those
        for (let i = 0; i < mut.addedNodes.length; i++) {
          let {previousSibling, nextSibling} = mut.addedNodes[i]
          if (!previousSibling || Array.prototype.indexOf.call(mut.addedNodes, previousSibling) < 0) prev = previousSibling
          if (!nextSibling || Array.prototype.indexOf.call(mut.addedNodes, nextSibling) < 0) next = nextSibling
        }
      }
      let fromOffset = prev && prev.parentNode == mut.target
          ? domIndex(prev) + 1 : 0
      let from = desc.localPosFromDOM(mut.target, fromOffset, -1)
      let toOffset = next && next.parentNode == mut.target
          ? domIndex(next) : mut.target.childNodes.length
      let to = desc.localPosFromDOM(mut.target, toOffset, 1)
      return {from, to}
    } else if (mut.type == "attributes") {
      return {from: desc.posAtStart - desc.border, to: desc.posAtEnd + desc.border}
    } else { // "characterData"
      return {
        from: desc.posAtStart,
        to: desc.posAtEnd,
        // An event was generated for a text change that didn't change
        // any text. Mark the dom change to fall back to assuming the
        // selection was typed over with an identical value if it can't
        // find another change.
        typeOver: mut.target.nodeValue == mut.oldValue
      }
    }
  }
}

let cssChecked = false

function checkCSS(view) {
  if (cssChecked) return
  cssChecked = true
  if (getComputedStyle(view.dom).whiteSpace == "normal")
    console["warn"]("ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package.")
}
<commit_msg>Ignore mutation records on nodes that were inserted by earlier records<commit_after>import browser from "./browser"
import {domIndex, isEquivalentPosition} from "./dom"
import {hasFocusAndSelection, hasSelection, selectionToDOM} from "./selection"

const observeOptions = {
  childList: true,
  characterData: true,
  characterDataOldValue: true,
  attributes: true,
  attributeOldValue: true,
  subtree: true
}
// IE11 has very broken mutation observers, so we also listen to DOMCharacterDataModified
const useCharData = browser.ie && browser.ie_version <= 11

class SelectionState {
  constructor() {
    this.anchorNode = this.anchorOffset = this.focusNode = this.focusOffset = null
  }

  set(sel) {
    this.anchorNode = sel.anchorNode; this.anchorOffset = sel.anchorOffset
    this.focusNode = sel.focusNode; this.focusOffset = sel.focusOffset
  }

  eq(sel) {
    return sel.anchorNode == this.anchorNode && sel.anchorOffset == this.anchorOffset &&
      sel.focusNode == this.focusNode && sel.focusOffset == this.focusOffset
  }
}

export class DOMObserver {
  constructor(view, handleDOMChange) {
    this.view = view
    this.handleDOMChange = handleDOMChange
    this.queue = []
    this.flushingSoon = false
    this.observer = window.MutationObserver &&
      new window.MutationObserver(mutations => {
        for (let i = 0; i < mutations.length; i++) this.queue.push(mutations[i])
        // IE11 will sometimes (on backspacing out a single character
        // text node after a BR node) call the observer callback
        // before actually updating the DOM, which will cause
        // ProseMirror to miss the change (see #930)
        if (browser.ie && browser.ie_version <= 11 && mutations.some(
          m => m.type == "childList" && m.removedNodes.length ||
               m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length))
          this.flushSoon()
        else
          this.flush()
      })
    this.currentSelection = new SelectionState
    if (useCharData) {
      this.onCharData = e => {
        this.queue.push({target: e.target, type: "characterData", oldValue: e.prevValue})
        this.flushSoon()
      }
    }
    this.onSelectionChange = this.onSelectionChange.bind(this)
    this.suppressingSelectionUpdates = false
  }

  flushSoon() {
    if (!this.flushingSoon) {
      this.flushingSoon = true
      window.setTimeout(() => { this.flushingSoon = false; this.flush() }, 20)
    }
  }

  start() {
    if (this.observer)
      this.observer.observe(this.view.dom, observeOptions)
    if (useCharData)
      this.view.dom.addEventListener("DOMCharacterDataModified", this.onCharData)
    this.connectSelection()
  }

  stop() {
    if (this.observer) {
      let take = this.observer.takeRecords()
      if (take.length) {
        for (let i = 0; i < take.length; i++) this.queue.push(take[i])
        window.setTimeout(() => this.flush(), 20)
      }
      this.observer.disconnect()
    }
    if (useCharData) this.view.dom.removeEventListener("DOMCharacterDataModified", this.onCharData)
    this.disconnectSelection()
  }

  connectSelection() {
    this.view.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange)
  }

  disconnectSelection() {
    this.view.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange)
  }

  suppressSelectionUpdates() {
    this.suppressingSelectionUpdates = true
    setTimeout(() => this.suppressingSelectionUpdates = false, 50)
  }

  onSelectionChange() {
    if (!hasFocusAndSelection(this.view)) return
    if (this.suppressingSelectionUpdates) return selectionToDOM(this.view)
    // Deletions on IE11 fire their events in the wrong order, giving
    // us a selection change event before the DOM changes are
    // reported.
    if (browser.ie && browser.ie_version <= 11 && !this.view.state.selection.empty) {
      let sel = this.view.root.getSelection()
      // Selection.isCollapsed isn't reliable on IE
      if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
        return this.flushSoon()
    }
    this.flush()
  }

  setCurSelection() {
    this.currentSelection.set(this.view.root.getSelection())
  }

  ignoreSelectionChange(sel) {
    if (sel.rangeCount == 0) return true
    let container = sel.getRangeAt(0).commonAncestorContainer
    let desc = this.view.docView.nearestDesc(container)
    return desc && desc.ignoreMutation({type: "selection", target: container.nodeType == 3 ? container.parentNode : container})
  }

  flush() {
    if (!this.view.docView || this.flushingSoon) return
    let mutations = this.observer ? this.observer.takeRecords() : []
    if (this.queue.length) {
      mutations = this.queue.concat(mutations)
      this.queue.length = 0
    }

    let sel = this.view.root.getSelection()
    let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasSelection(this.view) && !this.ignoreSelectionChange(sel)

    let from = -1, to = -1, typeOver = false, added = []
    if (this.view.editable) {
      for (let i = 0; i < mutations.length; i++) {
        let result = this.registerMutation(mutations[i], added)
        if (result) {
          from = from < 0 ? result.from : Math.min(result.from, from)
          to = to < 0 ? result.to : Math.max(result.to, to)
          if (result.typeOver && !this.view.composing) typeOver = true
        }
      }
    }
    if (from > -1 || newSel) {
      if (from > -1) {
        this.view.docView.markDirty(from, to)
        checkCSS(this.view)
      }
      this.handleDOMChange(from, to, typeOver)
      if (this.view.docView.dirty) this.view.updateState(this.view.state)
      else if (!this.currentSelection.eq(sel)) selectionToDOM(this.view)
    }
  }

  registerMutation(mut, added) {
    // Ignore mutations inside nodes that were already noted as inserted
    if (added.indexOf(mut.target) > -1) return null
    let desc = this.view.docView.nearestDesc(mut.target)
    if (mut.type == "attributes" &&
        (desc == this.view.docView || mut.attributeName == "contenteditable" ||
         // Firefox sometimes fires spurious events for null/empty styles
         (mut.attributeName == "style" && !mut.oldValue && !mut.target.getAttribute("style"))))
      return null
    if (!desc || desc.ignoreMutation(mut)) return null

    if (mut.type == "childList") {
      let prev = mut.previousSibling, next = mut.nextSibling
      if (browser.ie && browser.ie_version <= 11 && mut.addedNodes.length) {
        // IE11 gives us incorrect next/prev siblings for some
        // insertions, so if there are added nodes, recompute those
        for (let i = 0; i < mut.addedNodes.length; i++) {
          let {previousSibling, nextSibling} = mut.addedNodes[i]
          if (!previousSibling || Array.prototype.indexOf.call(mut.addedNodes, previousSibling) < 0) prev = previousSibling
          if (!nextSibling || Array.prototype.indexOf.call(mut.addedNodes, nextSibling) < 0) next = nextSibling
        }
      }
      let fromOffset = prev && prev.parentNode == mut.target
          ? domIndex(prev) + 1 : 0
      let from = desc.localPosFromDOM(mut.target, fromOffset, -1)
      let toOffset = next && next.parentNode == mut.target
          ? domIndex(next) : mut.target.childNodes.length
      for (let i = 0; i < mut.addedNodes.length; i++) added.push(mut.addedNodes[i])
      let to = desc.localPosFromDOM(mut.target, toOffset, 1)
      return {from, to}
    } else if (mut.type == "attributes") {
      return {from: desc.posAtStart - desc.border, to: desc.posAtEnd + desc.border}
    } else { // "characterData"
      return {
        from: desc.posAtStart,
        to: desc.posAtEnd,
        // An event was generated for a text change that didn't change
        // any text. Mark the dom change to fall back to assuming the
        // selection was typed over with an identical value if it can't
        // find another change.
        typeOver: mut.target.nodeValue == mut.oldValue
      }
    }
  }
}

let cssChecked = false

function checkCSS(view) {
  if (cssChecked) return
  cssChecked = true
  if (getComputedStyle(view.dom).whiteSpace == "normal")
    console["warn"]("ProseMirror expects the CSS white-space property to be set, preferably to 'pre-wrap'. It is recommended to load style/prosemirror.css from the prosemirror-view package.")
}
<|endoftext|>