<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Eric Leong
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

//
// constructor
//
var Pixelmap = function(canvas) {
	var gl = this.initWebGL(canvas);      // Initialize the GL context

	// Only continue if WebGL is available and working

	if (gl) {
		this.gl = gl;

		this.gl.enable(this.gl.BLEND);
		this.gl.disable(this.gl.DEPTH_TEST);
		this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);

		// Initialize the shaders; this is where all the lighting for the
		// vertices and so forth is established.

		this.initShaders();

		// Here's where we call the routine that builds all the objects
		// we'll be drawing.

		this.initBuffers();

		// Load and set up the textures we'll be using.

		this.initTextures();
	}
}

//
// initWebGL
//
// Initialize WebGL, returning the GL context or null if
// WebGL isn't available or could not be initialized.
//
Pixelmap.prototype.initWebGL = function(canvas) {
	var gl = null;

	try {
		gl = canvas.getContext('experimental-webgl', {
			depth: false,
			preserveDrawingBuffer: true
		});
	} catch(e) {
		gl = null;
	}

	return gl;
}

//
// create gl program
//
Pixelmap.prototype.createProgram = function(gl) {

	var vertexShader = Pixelmap.prototype.getShader(gl, this.getVertexShader(), gl.VERTEX_SHADER);
	var fragmentShader = Pixelmap.prototype.getShader(gl, this.getFragmentShader(), gl.FRAGMENT_SHADER);

	// Create the shader programs

	var program = gl.createProgram();
	gl.attachShader(program, vertexShader);
	gl.attachShader(program, fragmentShader);
	gl.linkProgram(program);

	// If creating the shader program failed, alert

	if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
		alert('Unable to initialize the shader program.');
	}

	return program;
}

Pixelmap.prototype.getVertexShader = function() {
	return 'attribute vec3 aVertexPosition;\
			attribute vec2 aTextureCoord;\
\
			varying highp vec2 vTextureCoord;\
\
			void main(void) {\
				gl_Position = vec4(aVertexPosition, 1.0);\
\
				vTextureCoord = aTextureCoord;\
			}';
}

Pixelmap.prototype.getFragmentShader = function() {
	return 'precision mediump float;\
\
			varying highp vec2 vTextureCoord;\
\
			uniform sampler2D uImage;\
			uniform sampler2D uMap;\
\
			void main(void) {\
				gl_FragColor = texture2D(uImage, texture2D(uMap, vTextureCoord).xy);\
			}';
}

//
// getShader
//
Pixelmap.prototype.getShader = function(gl, source, type) {
	// Now figure out what type of shader script we have,
	// based on its MIME type.

	var shader = gl.createShader(type);

	// Send the source to the shader object

	gl.shaderSource(shader, source);

	// Compile the shader program

	gl.compileShader(shader);

	// See if it compiled successfully

	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
		return null;
	}

	return shader;
}

//
// initShaders
//
Pixelmap.prototype.initShaders = function() {

	// create program
	this.program = this.createProgram(this.gl);

	// textures
	this.uImage = this.gl.getUniformLocation(this.program, 'uImage');
	this.uMap = this.gl.getUniformLocation(this.program, 'uMap');

	// vertex attributes
	this.aVertexPosition = this.gl.getAttribLocation(this.program, 'aVertexPosition');
	this.gl.enableVertexAttribArray(this.aVertexPosition);

	this.aTextureCoord = this.gl.getAttribLocation(this.program, 'aTextureCoord');
	this.gl.enableVertexAttribArray(this.aTextureCoord);
}

//
// initBuffers
//
Pixelmap.prototype.initBuffers = function() {

	// Map the texture onto the rect's face.
	this.rectVerticesTextureCoordBuffer = this.gl.createBuffer();
	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesTextureCoordBuffer);

	var textureCoordinates = [
		// Front
		0.0, 1.0,
		1.0, 1.0,
		0.0, 0.0,
		1.0, 0.0
	];

	this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), this.gl.STATIC_DRAW);

	// Create a buffer for the rect's vertices.

	this.rectVerticesBuffer = this.gl.createBuffer();

	// Select the this.rectVerticesBuffer as the one to apply vertex
	// operations to from here out.

	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesBuffer);

	// Now create an array of vertices for the rect. Note that the Z
	// coordinate is always 0 here.

	var vertices = [
		-1.0, -1.0, 0.0,
		1.0, -1.0, 0.0,
		-1.0, 1.0, 0.0,
		1.0, 1.0, 0.0
	];

	// Now pass the list of vertices into WebGL to build the shape. We
	// do this by creating a Float32Array from the JavaScript array,
	// then use it to fill the current vertex buffer.

	this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
}

//
// initialize textures
//
Pixelmap.prototype.initTextures = function() {
	this.imageTexture = this.initTexture();
	this.mapTexture = this.initTexture();
}

//
// initialize texture
//
Pixelmap.prototype.initTexture = function() {
	var texture = this.gl.createTexture();
	this.gl.bindTexture(this.gl.TEXTURE_2D, texture);

	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);

	this.gl.bindTexture(this.gl.TEXTURE_2D, null);

	return texture;
}

//
// update viewport
//
Pixelmap.prototype.setViewport = function(width, height) {
	this.gl.viewport(0, 0, width, height);
}

//
// clear
//
Pixelmap.prototype.clear = function() {
	this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
	this.gl.clear(this.gl.COLOR_BUFFER_BIT);
}

//
// draw
//
Pixelmap.prototype.draw = function(image, map) {

	this.gl.useProgram(this.program);

	// Draw the rect by binding the array buffer to the rect's vertices
	// array, setting attributes, and pushing it to this.GL.
	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesBuffer);
	this.gl.vertexAttribPointer(this.aVertexPosition, 3, this.gl.FLOAT, false, 0, 0);

	// Set the texture coordinates attribute for the vertices.
	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesTextureCoordBuffer);
	this.gl.vertexAttribPointer(this.aTextureCoord, 2, this.gl.FLOAT, false, 0, 0);

	// Specify the texture to map onto the face.
	this.gl.uniform1i(this.uImage, 0);

	this.gl.activeTexture(this.gl.TEXTURE0);
	this.gl.bindTexture(this.gl.TEXTURE_2D, this.imageTexture);

	this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);

	// Specify the map texture.
	this.gl.uniform1i(this.uMap, 1);

	this.gl.activeTexture(this.gl.TEXTURE1);
	this.gl.bindTexture(this.gl.TEXTURE_2D, this.mapTexture);

	this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, map);

	// Draw!
	this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
}<commit_msg>Add displacement map option.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Eric Leong
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

//
// constructor
//
var Pixelmap = function(canvas, mapType) {
	var gl = this.initWebGL(canvas);      // Initialize the GL context

	mapType = mapType || 'distort';

	// Only continue if WebGL is available and working

	if (gl) {
		this.gl = gl;

		this.gl.enable(this.gl.BLEND);
		this.gl.disable(this.gl.DEPTH_TEST);
		this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);

		// Initialize the shaders; this is where all the lighting for the
		// vertices and so forth is established.

		this.initShaders(this.getShaderForType(mapType));

		// Here's where we call the routine that builds all the objects
		// we'll be drawing.

		this.initBuffers();

		// Load and set up the textures we'll be using.

		this.initTextures();
	}
}

//
// initWebGL
//
// Initialize WebGL, returning the GL context or null if
// WebGL isn't available or could not be initialized.
//
Pixelmap.prototype.initWebGL = function(canvas) {
	var gl = null;

	try {
		gl = canvas.getContext('experimental-webgl', {
			depth: false,
			preserveDrawingBuffer: true
		});
	} catch(e) {
		gl = null;
	}

	return gl;
}

//
// create gl program
//
Pixelmap.prototype.getShaderForType = function(mapType) {
	if (mapType == 'displace') {
		return 'gl_FragColor = texture2D(uImage, vTextureCoord - (texture2D(uMap, vTextureCoord).xy - vec2(0.5, 0.5)));'
	} else if (mapType == 'distort') {
		return 'gl_FragColor = texture2D(uImage, texture2D(uMap, vTextureCoord).xy);'
	} else {
		return 'gl_FragColor = texture2D(uImage, vTextureCoord);'
	}
}

//
// create gl program
//
Pixelmap.prototype.createProgram = function(gl, shader) {

	var vertexShader = Pixelmap.prototype.getShader(gl, this.getVertexShader(), gl.VERTEX_SHADER);
	var fragmentShader = Pixelmap.prototype.getShader(gl, this.getFragmentShader(shader), gl.FRAGMENT_SHADER);

	// Create the shader programs

	var program = gl.createProgram();
	gl.attachShader(program, vertexShader);
	gl.attachShader(program, fragmentShader);
	gl.linkProgram(program);

	// If creating the shader program failed, alert

	if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
		alert('Unable to initialize the shader program.');
	}

	return program;
}

Pixelmap.prototype.getVertexShader = function() {
	return 'attribute vec3 aVertexPosition;\
			attribute vec2 aTextureCoord;\
\
			varying highp vec2 vTextureCoord;\
\
			void main(void) {\
				gl_Position = vec4(aVertexPosition, 1.0);\
\
				vTextureCoord = aTextureCoord;\
			}';
}

Pixelmap.prototype.getFragmentShader = function(shader) {
	return 'precision mediump float;\
\
			varying highp vec2 vTextureCoord;\
\
			uniform sampler2D uImage;\
			uniform sampler2D uMap;\
\
			void main(void) {\
				' + shader + '\
			}';
}

//
// getShader
//
Pixelmap.prototype.getShader = function(gl, source, mapType) {
	// Now figure out what type of shader script we have,
	// based on its MIME type.

	var shader = gl.createShader(mapType);

	// Send the source to the shader object

	gl.shaderSource(shader, source);

	// Compile the shader program

	gl.compileShader(shader);

	// See if it compiled successfully

	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
		return null;
	}

	return shader;
}

//
// initShaders
//
Pixelmap.prototype.initShaders = function(shader) {

	// create program
	this.program = this.createProgram(this.gl, shader);

	// textures
	this.uImage = this.gl.getUniformLocation(this.program, 'uImage');
	this.uMap = this.gl.getUniformLocation(this.program, 'uMap');

	// vertex attributes
	this.aVertexPosition = this.gl.getAttribLocation(this.program, 'aVertexPosition');
	this.gl.enableVertexAttribArray(this.aVertexPosition);

	this.aTextureCoord = this.gl.getAttribLocation(this.program, 'aTextureCoord');
	this.gl.enableVertexAttribArray(this.aTextureCoord);
}

//
// initBuffers
//
Pixelmap.prototype.initBuffers = function() {

	// Map the texture onto the rect's face.
	this.rectVerticesTextureCoordBuffer = this.gl.createBuffer();
	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesTextureCoordBuffer);

	var textureCoordinates = [
		// Front
		0.0, 1.0,
		1.0, 1.0,
		0.0, 0.0,
		1.0, 0.0
	];

	this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), this.gl.STATIC_DRAW);

	// Create a buffer for the rect's vertices.

	this.rectVerticesBuffer = this.gl.createBuffer();

	// Select the this.rectVerticesBuffer as the one to apply vertex
	// operations to from here out.

	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesBuffer);

	// Now create an array of vertices for the rect. Note that the Z
	// coordinate is always 0 here.

	var vertices = [
		-1.0, -1.0, 0.0,
		1.0, -1.0, 0.0,
		-1.0, 1.0, 0.0,
		1.0, 1.0, 0.0
	];

	// Now pass the list of vertices into WebGL to build the shape. We
	// do this by creating a Float32Array from the JavaScript array,
	// then use it to fill the current vertex buffer.

	this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
}

//
// initialize textures
//
Pixelmap.prototype.initTextures = function() {
	this.imageTexture = this.initTexture();
	this.mapTexture = this.initTexture();
}

//
// initialize texture
//
Pixelmap.prototype.initTexture = function() {
	var texture = this.gl.createTexture();
	this.gl.bindTexture(this.gl.TEXTURE_2D, texture);

	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
	this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);

	this.gl.bindTexture(this.gl.TEXTURE_2D, null);

	return texture;
}

//
// update viewport
//
Pixelmap.prototype.setViewport = function(width, height) {
	this.gl.viewport(0, 0, width, height);
}

//
// clear
//
Pixelmap.prototype.clear = function() {
	this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
	this.gl.clear(this.gl.COLOR_BUFFER_BIT);
}

//
// draw
//
Pixelmap.prototype.draw = function(image, map) {

	this.gl.useProgram(this.program);

	// Draw the rect by binding the array buffer to the rect's vertices
	// array, setting attributes, and pushing it to this.GL.
	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesBuffer);
	this.gl.vertexAttribPointer(this.aVertexPosition, 3, this.gl.FLOAT, false, 0, 0);

	// Set the texture coordinates attribute for the vertices.
	this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectVerticesTextureCoordBuffer);
	this.gl.vertexAttribPointer(this.aTextureCoord, 2, this.gl.FLOAT, false, 0, 0);

	// Specify the texture to map onto the face.
	this.gl.uniform1i(this.uImage, 0);

	this.gl.activeTexture(this.gl.TEXTURE0);
	this.gl.bindTexture(this.gl.TEXTURE_2D, this.imageTexture);

	this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);

	// Specify the map texture.
	this.gl.uniform1i(this.uMap, 1);

	this.gl.activeTexture(this.gl.TEXTURE1);
	this.gl.bindTexture(this.gl.TEXTURE_2D, this.mapTexture);

	this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, map);

	// Draw!
	this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
}<|endoftext|>


<commit_before>// Timer stuff
// https://twitter.com/Totalbiscuit/status/580915908345987072
// 25.03.2015 at 7:15 pm PDT = 26.03.2015 at 2:15 am UTC = 1427336100000ms since since 1970

var START_TIME = 1427336100000;

printTimeSince();
var timerId = setInterval(printTimeSince, 1000);

function printTimeSince()
{
    //Split the time into 4 parts
    var currentTime = Date.now();
    var secondsLeft = Math.abs(currentTime - START_TIME) / 1000;
    var days = Math.floor(secondsLeft / 86400);
    secondsLeft -= days * 86400;
    var hours = Math.floor(secondsLeft / 3600) % 24;
    secondsLeft -= hours * 3600;
    var minutes = Math.floor(secondsLeft / 60) % 60;
    secondsLeft -= minutes * 60;
    var seconds = Math.round(secondsLeft);

    //Add leading zeroes if necessary
    if (seconds < 10) seconds = "0" + seconds;
    if (minutes < 10) minutes = "0" + minutes;
    if (hours < 10) hours = "0" + hours;
    if (days < 10) days = "00" + days;
    else if (days < 100) days = "0" + days;
    else if (days > 999) days = "999";

    updateView($('#day > .timedigit')[0], days.toString());
    updateView($('#hrs > .timedigit')[0], hours.toString());
    updateView($('#min > .timedigit')[0], minutes.toString());
    updateView($('#sec > .timedigit')[0], seconds.toString());
}

function updateView(el, text)
{
    el.innerHTML = "";
    for (var i = 0; i < text.length; i++)
    {
        el.innerHTML += '' + text[i] + '';
    }
}

//About stuff
$('#aboutbutton').on('click', function ()
{
    $('#aboutcontent').fadeIn(100);
});

$('#aboutcontent').on('click', function ()
{
    $('#aboutcontent').fadeOut(100);
});<commit_msg>EDIT new twitter drama, timer reset<commit_after>// Timer stuff
// https://twitter.com/Totalbiscuit/status/586494130085330945
// 10.04.2015 at 4:41 am PDT = 10.04.2015 at 11:41 am UTC = 1428666060000ms since since 1970

var START_TIME = 1428666060000;

printTimeSince();
var timerId = setInterval(printTimeSince, 1000);

function printTimeSince()
{
    //Split the time into 4 parts
    var currentTime = Date.now();
    var secondsLeft = Math.abs(currentTime - START_TIME) / 1000;
    var days = Math.floor(secondsLeft / 86400);
    secondsLeft -= days * 86400;
    var hours = Math.floor(secondsLeft / 3600) % 24;
    secondsLeft -= hours * 3600;
    var minutes = Math.floor(secondsLeft / 60) % 60;
    secondsLeft -= minutes * 60;
    var seconds = Math.round(secondsLeft);

    //Add leading zeroes if necessary
    if (seconds < 10) seconds = "0" + seconds;
    if (minutes < 10) minutes = "0" + minutes;
    if (hours < 10) hours = "0" + hours;
    if (days < 10) days = "00" + days;
    else if (days < 100) days = "0" + days;
    else if (days > 999) days = "999";

    updateView($('#day > .timedigit')[0], days.toString());
    updateView($('#hrs > .timedigit')[0], hours.toString());
    updateView($('#min > .timedigit')[0], minutes.toString());
    updateView($('#sec > .timedigit')[0], seconds.toString());
}

function updateView(el, text)
{
    el.innerHTML = "";
    for (var i = 0; i < text.length; i++)
    {
        el.innerHTML += '' + text[i] + '';
    }
}

//About stuff
$('#aboutbutton').on('click', function ()
{
    $('#aboutcontent').fadeIn(100);
});

$('#aboutcontent').on('click', function ()
{
    $('#aboutcontent').fadeOut(100);
});<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.media.SegmentIndex');

goog.require('shaka.asserts');
goog.require('shaka.media.SegmentReference');
goog.require('shaka.util.Error');
goog.require('shaka.util.IDestroyable');

/**
 * Creates a SegmentIndex.
 *
 * @param {!Array.<!shaka.media.SegmentReference>} references The list of
 *     SegmentReferences, which must be sorted first by their start times
 *     (ascending) and second by their end times (ascending), and have
 *     continuous, increasing positions.
 *
 * @constructor
 * @struct
 * @implements {shaka.util.IDestroyable}
 * @export
 */
shaka.media.SegmentIndex = function(references) {
  if (!COMPILED) {
    shaka.media.SegmentIndex.assertCorrectReferences_(references);
  }

  /** @private {Array.<!shaka.media.SegmentReference>} */
  this.references_ = references;
};

/** @override */
shaka.media.SegmentIndex.prototype.destroy = function() {
  this.references_ = null;
  return Promise.resolve();
};

/**
 * Finds the position of the segment for the given time, in seconds, relative
 * to the start of the presentation. Returns the position of the segment with
 * the largest end time if more than one segment is known for the given time.
 *
 * @param {number} time
 * @return {?number} The position of the segment, or null
 *     if the position of the segment could not be determined.
 */
shaka.media.SegmentIndex.prototype.find = function(time) {
  // For live streams, searching from the end is faster. For VOD, it balances
  // out either way. In both cases, references_.length is small enough that the
  // difference isn't huge.
  for (var i = this.references_.length - 1; i >= 0; --i) {
    var r = this.references_[i];
    // Note that a segment ends immediately before the end time.
    if ((time >= r.startTime) && (time < r.endTime)) {
      return r.position;
    }
  }
  return null;
};

/**
 * Gets the SegmentReference for the segment at the given position.
 *
 * @param {number} position The position of the segment.
 * @return {shaka.media.SegmentReference} The SegmentReference, or null if
 *     no such SegmentReference exists.
 */
shaka.media.SegmentIndex.prototype.get = function(position) {
  if (this.references_.length == 0)
    return null;

  var index = position - this.references_[0].position;
  if (index < 0 || index >= this.references_.length)
    return null;

  return this.references_[index];
};

/**
 * Merges the given SegmentReferences.
 *
 * @param {!Array.<!shaka.media.SegmentReference>} references The list of
 *     SegmentReferences, which must be sorted first by their start times
 *     (ascending) and second by their end times (ascending), and have
 *     continuous, increasing positions.
 */
shaka.media.SegmentIndex.prototype.merge = function(references) {
  if (!COMPILED) {
    shaka.media.SegmentIndex.assertCorrectReferences_(references);
  }

  var newReferences = [];
  var i = 0;
  var j = 0;

  while ((i < this.references_.length) && (j < references.length)) {
    var r1 = this.references_[i];
    var r2 = references[j];

    if (r1.position < r2.position) {
      newReferences.push(r1);
      i++;
    } else if (r1.position > r2.position) {
      newReferences.push(r2);
      j++;
    } else {
      // Drop the old reference if there's a new reference with the same
      // position.
      newReferences.push(r2);
      i++;
      j++;
    }
  }

  while (i < this.references_.length) {
    newReferences.push(this.references_[i++]);
  }

  while (j < references.length) {
    newReferences.push(references[j++]);
  }

  if (!COMPILED) {
    shaka.media.SegmentIndex.assertCorrectReferences_(newReferences);
  }

  this.references_ = newReferences;
};

/**
 * Removes all SegmentReferences that end before the given time.
 *
 * @param {number} time The time in seconds.
 */
shaka.media.SegmentIndex.prototype.evict = function(time) {
  for (var i = 0; i < this.references_.length; ++i) {
    if (this.references_[i].endTime > time)
      break;
  }
  this.references_.splice(0, i);
};

if (!COMPILED) {
  /**
   * Asserts that the given SegmentReferences are sorted and have continuous,
   * increasing positions.
   *
   * @param {!Array.<shaka.media.SegmentReference>} references
   * @private
   */
  shaka.media.SegmentIndex.assertCorrectReferences_ = function(references) {
    shaka.asserts.assert(references.every(function(r2, i) {
      if (i == 0) return true;
      var r1 = references[i - 1];
      if (r2.position != r1.position + 1) return false;
      if (r1.startTime < r2.startTime) {
        return true;
      } else if (r1.startTime > r2.startTime) {
        return false;
      } else {
        if (r1.endTime <= r2.endTime) {
          return true;
        } else {
          return false;
        }
      }
    }), 'SegmentReferences are incorrect');
  };
}

<commit_msg>Fix build error for unused require<commit_after>/**
 * @license
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.media.SegmentIndex');

goog.require('shaka.asserts');
goog.require('shaka.media.SegmentReference');
goog.require('shaka.util.IDestroyable');

/**
 * Creates a SegmentIndex.
 *
 * @param {!Array.<!shaka.media.SegmentReference>} references The list of
 *     SegmentReferences, which must be sorted first by their start times
 *     (ascending) and second by their end times (ascending), and have
 *     continuous, increasing positions.
 *
 * @constructor
 * @struct
 * @implements {shaka.util.IDestroyable}
 * @export
 */
shaka.media.SegmentIndex = function(references) {
  if (!COMPILED) {
    shaka.media.SegmentIndex.assertCorrectReferences_(references);
  }

  /** @private {Array.<!shaka.media.SegmentReference>} */
  this.references_ = references;
};

/** @override */
shaka.media.SegmentIndex.prototype.destroy = function() {
  this.references_ = null;
  return Promise.resolve();
};

/**
 * Finds the position of the segment for the given time, in seconds, relative
 * to the start of the presentation. Returns the position of the segment with
 * the largest end time if more than one segment is known for the given time.
 *
 * @param {number} time
 * @return {?number} The position of the segment, or null
 *     if the position of the segment could not be determined.
 */
shaka.media.SegmentIndex.prototype.find = function(time) {
  // For live streams, searching from the end is faster. For VOD, it balances
  // out either way. In both cases, references_.length is small enough that the
  // difference isn't huge.
  for (var i = this.references_.length - 1; i >= 0; --i) {
    var r = this.references_[i];
    // Note that a segment ends immediately before the end time.
    if ((time >= r.startTime) && (time < r.endTime)) {
      return r.position;
    }
  }
  return null;
};

/**
 * Gets the SegmentReference for the segment at the given position.
 *
 * @param {number} position The position of the segment.
 * @return {shaka.media.SegmentReference} The SegmentReference, or null if
 *     no such SegmentReference exists.
 */
shaka.media.SegmentIndex.prototype.get = function(position) {
  if (this.references_.length == 0)
    return null;

  var index = position - this.references_[0].position;
  if (index < 0 || index >= this.references_.length)
    return null;

  return this.references_[index];
};

/**
 * Merges the given SegmentReferences.
 *
 * @param {!Array.<!shaka.media.SegmentReference>} references The list of
 *     SegmentReferences, which must be sorted first by their start times
 *     (ascending) and second by their end times (ascending), and have
 *     continuous, increasing positions.
 */
shaka.media.SegmentIndex.prototype.merge = function(references) {
  if (!COMPILED) {
    shaka.media.SegmentIndex.assertCorrectReferences_(references);
  }

  var newReferences = [];
  var i = 0;
  var j = 0;

  while ((i < this.references_.length) && (j < references.length)) {
    var r1 = this.references_[i];
    var r2 = references[j];

    if (r1.position < r2.position) {
      newReferences.push(r1);
      i++;
    } else if (r1.position > r2.position) {
      newReferences.push(r2);
      j++;
    } else {
      // Drop the old reference if there's a new reference with the same
      // position.
      newReferences.push(r2);
      i++;
      j++;
    }
  }

  while (i < this.references_.length) {
    newReferences.push(this.references_[i++]);
  }

  while (j < references.length) {
    newReferences.push(references[j++]);
  }

  if (!COMPILED) {
    shaka.media.SegmentIndex.assertCorrectReferences_(newReferences);
  }

  this.references_ = newReferences;
};

/**
 * Removes all SegmentReferences that end before the given time.
 *
 * @param {number} time The time in seconds.
 */
shaka.media.SegmentIndex.prototype.evict = function(time) {
  for (var i = 0; i < this.references_.length; ++i) {
    if (this.references_[i].endTime > time)
      break;
  }
  this.references_.splice(0, i);
};

if (!COMPILED) {
  /**
   * Asserts that the given SegmentReferences are sorted and have continuous,
   * increasing positions.
   *
   * @param {!Array.<shaka.media.SegmentReference>} references
   * @private
   */
  shaka.media.SegmentIndex.assertCorrectReferences_ = function(references) {
    shaka.asserts.assert(references.every(function(r2, i) {
      if (i == 0) return true;
      var r1 = references[i - 1];
      if (r2.position != r1.position + 1) return false;
      if (r1.startTime < r2.startTime) {
        return true;
      } else if (r1.startTime > r2.startTime) {
        return false;
      } else {
        if (r1.endTime <= r2.endTime) {
          return true;
        } else {
          return false;
        }
      }
    }), 'SegmentReferences are incorrect');
  };
}

<|endoftext|>


<commit_before>import Animated from '../../apis/Animated';
import applyNativeMethods from '../../modules/applyNativeMethods';
import Easing from 'animated/lib/Easing';
import StyleSheet from '../../apis/StyleSheet';
import View from '../View';
import React, { Component, PropTypes } from 'react';

const rotationInterpolation = { inputRange: [ 0, 1 ], outputRange: [ '0deg', '360deg' ] };

class ActivityIndicator extends Component {
  static displayName = 'ActivityIndicator';

  static propTypes = {
    ...View.propTypes,
    animating: PropTypes.bool,
    color: PropTypes.string,
    hidesWhenStopped: PropTypes.bool,
    size: PropTypes.oneOfType([ PropTypes.oneOf([ 'small', 'large' ]), PropTypes.number ])
  };

  static defaultProps = {
    animating: true,
    color: '#1976D2',
    hidesWhenStopped: true,
    size: 'small'
  };

  constructor(props) {
    super(props);
    this.state = {
      animation: new Animated.Value(0)
    };
  }

  componentDidMount() {
    this._manageAnimation();
  }

  componentDidUpdate() {
    this._manageAnimation();
  }

  render() {
    const {
      animating,
      color,
      hidesWhenStopped,
      size,
      style,
      ...other
    } = this.props;

    const { animation } = this.state;

    const svg = (
      <svg height='100%' viewBox='0 0 32 32' width='100%'>
        <circle
          cx='16'
          cy='16'
          fill='none'
          r='14'
          strokeWidth='4'
          style={{
            stroke: color,
            opacity: 0.2
          }}
        />
        <circle
          cx='16'
          cy='16'
          fill='none'
          r='14'
          strokeWidth='4'
          style={{
            stroke: color,
            strokeDasharray: 80,
            strokeDashoffset: 60
          }}
        />
      </svg>
    );

    return (
      <View {...other} style={[
        styles.container,
        style,
        size && { height: size, width: size }
      ]}>
        <Animated.View
          children={svg}
          style={[
            indicatorStyles[size],
            hidesWhenStopped && !animating && styles.hidesWhenStopped,
            {
              transform: [
                { rotate: animation.interpolate(rotationInterpolation) }
              ]
            }
          ]}
        />
      </View>
    );
  }

  _manageAnimation() {
    const { animation } = this.state;

    const cycleAnimation = () => {
      animation.setValue(0);
      Animated.timing(animation, {
        duration: 750,
        easing: Easing.inOut(Easing.linear),
        toValue: 1
      }).start((event) => {
        if (event.finished) {
          cycleAnimation();
        }
      });
    };

    if (this.props.animating) {
      cycleAnimation();
    } else {
      animation.stopAnimation();
    }
  }
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    justifyContent: 'center'
  },
  hidesWhenStopped: {
    visibility: 'hidden'
  }
});

const indicatorStyles = StyleSheet.create({
  small: {
    width: 20,
    height: 20
  },
  large: {
    width: 36,
    height: 36
  }
});

module.exports = applyNativeMethods(ActivityIndicator);
<commit_msg>[fix] ActivtyIndicator accessibility props<commit_after>import Animated from '../../apis/Animated';
import applyNativeMethods from '../../modules/applyNativeMethods';
import Easing from 'animated/lib/Easing';
import StyleSheet from '../../apis/StyleSheet';
import View from '../View';
import React, { Component, PropTypes } from 'react';

const rotationInterpolation = { inputRange: [ 0, 1 ], outputRange: [ '0deg', '360deg' ] };

class ActivityIndicator extends Component {
  static displayName = 'ActivityIndicator';

  static propTypes = {
    ...View.propTypes,
    animating: PropTypes.bool,
    color: PropTypes.string,
    hidesWhenStopped: PropTypes.bool,
    size: PropTypes.oneOfType([ PropTypes.oneOf([ 'small', 'large' ]), PropTypes.number ])
  };

  static defaultProps = {
    animating: true,
    color: '#1976D2',
    hidesWhenStopped: true,
    size: 'small'
  };

  constructor(props) {
    super(props);
    this.state = {
      animation: new Animated.Value(0)
    };
  }

  componentDidMount() {
    this._manageAnimation();
  }

  componentDidUpdate() {
    this._manageAnimation();
  }

  render() {
    const {
      animating,
      color,
      hidesWhenStopped,
      size,
      style,
      ...other
    } = this.props;

    const { animation } = this.state;

    const svg = (
      <svg height='100%' viewBox='0 0 32 32' width='100%'>
        <circle
          cx='16'
          cy='16'
          fill='none'
          r='14'
          strokeWidth='4'
          style={{
            stroke: color,
            opacity: 0.2
          }}
        />
        <circle
          cx='16'
          cy='16'
          fill='none'
          r='14'
          strokeWidth='4'
          style={{
            stroke: color,
            strokeDasharray: 80,
            strokeDashoffset: 60
          }}
        />
      </svg>
    );

    return (
      <View {...other}
        accessibilityRole='progressbar'
        aria-valuemax='1'
        aria-valuemin='0'
        style={[
          styles.container,
          style,
          size && { height: size, width: size }
        ]}
      >
        <Animated.View
          children={svg}
          style={[
            indicatorStyles[size],
            hidesWhenStopped && !animating && styles.hidesWhenStopped,
            {
              transform: [
                { rotate: animation.interpolate(rotationInterpolation) }
              ]
            }
          ]}
        />
      </View>
    );
  }

  _manageAnimation() {
    const { animation } = this.state;

    const cycleAnimation = () => {
      animation.setValue(0);
      Animated.timing(animation, {
        duration: 750,
        easing: Easing.inOut(Easing.linear),
        toValue: 1
      }).start((event) => {
        if (event.finished) {
          cycleAnimation();
        }
      });
    };

    if (this.props.animating) {
      cycleAnimation();
    } else {
      animation.stopAnimation();
    }
  }
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    justifyContent: 'center'
  },
  hidesWhenStopped: {
    visibility: 'hidden'
  }
});

const indicatorStyles = StyleSheet.create({
  small: {
    width: 20,
    height: 20
  },
  large: {
    width: 36,
    height: 36
  }
});

module.exports = applyNativeMethods(ActivityIndicator);
<|endoftext|>


<commit_before>export default class CommonAudio {
  static handleTrackChange(fraction) {
    const { file, update } = this.props; // eslint-disable-line no-shadow

    update({
      progress: fraction * 100,
      currentTime: fraction * file.duration
    });

    file.currentTime = fraction * file.duration;
  }

  static handleFileLoad(file) {
    const { update } = this.props; // eslint-disable-line no-shadow

    // Preload file
    file.setAttribute('preload', 'auto');

    const onLoadeddata = () => {
      // Default current time to zero. This will change
      file.currentTime = 0; // eslint-disable-line no-param-reassign

      update({
        duration: file.duration
      });
    };

    const onTimeupdate = () => {
      const progress = file.currentTime / file.duration * 100;

      update({
        progress,
        currentTime: file.currentTime,
        isPlaying: !file.paused
      });
    };

    const onEnded = () => {
      const { shouldRepeat, shouldContinuous, shouldRandom } = this.props;

      if (shouldRepeat) {
        file.pause();
        file.currentTime = 0; // eslint-disable-line no-param-reassign
        file.play();
      } else if (shouldContinuous) {
        const { surah, surahs, qari } = this.props; // eslint-disable-line no-shadow
        this.props.load({ surah: Object.values(surahs)[surah.id], qari: qari });
      } else if (shouldRandom) {
        const { surahs, qari } = this.props; // eslint-disable-line no-shadow
        const randomSurah = Math.floor(Math.random() * (113 + 1));
        this.props.load({
          surah: Object.values(surahs)[randomSurah],
          qari: qari
        });
      } else {
        if (file.readyState >= 3 && file.paused) {
          file.pause();
        }

        update({
          surah: null,
          isPlaying: false
        });
      }
    };

    const onPlay = () => {};

    file.onloadeddata = onLoadeddata;
    file.ontimeupdate = onTimeupdate;
    file.onplay = onPlay;
    file.onended = onEnded;
  }

  static handleRemoveFileListeneres(file) {
    if (file) {
      file.pause();
      file.onloadeddata = null;
      file.ontimeupdate = null;
      file.onplay = null;
      file.onended = null;
    }
  }

  static isPlayPreviousDisabled() {
    const { surah, surahPage, qari } = this.props; // eslint-disable-line no-shadow
    const disableBasedOnSurah = surah ? surah.id === 1 && true : true;
    const disabled = surahPage ? qari.id === 1 && true : disableBasedOnSurah;
    return disabled;
  }

  static isPlayNextDisabled() {
    const { surah, qaris, surahPage, qari } = this.props; // eslint-disable-line no-shadow
    const disableBasedOnSurah = surah ? surah.id === 114 && true : true;
    const disabled = surahPage
      ? qari.id === Object.keys(qaris).length
      : disableBasedOnSurah;
    return disabled;
  }

  static handleKeyboardEvent(event) {
    const { code } = event;
    const { previous, next, playPause, surahs } = this.props; // eslint-disable-line no-shadow
    if (code === 'Space') {
      event.preventDefault();
      playPause();
    } else if (
      (code === 'ArrowRight' || code === 'ArrowDown') &&
      !this.isPlayNextDisabled()
    ) {
      event.preventDefault();
      next({ surahs: Object.values(surahs) });
    } else if (
      (code === 'ArrowLeft' || code === 'ArrowUp') &&
      !this.isPlayPreviousDisabled()
    ) {
      event.preventDefault();
      previous({ surahs: Object.values(surahs) });
    }
  }
}
<commit_msg>Added support for the Chrome Media Session API (#96)<commit_after>/* global MediaMetadata */

export default class CommonAudio {
  static handleTrackChange(fraction) {
    const { file, update } = this.props; // eslint-disable-line no-shadow

    update({
      progress: fraction * 100,
      currentTime: fraction * file.duration
    });

    file.currentTime = fraction * file.duration;
  }

  static handleFileLoad(file) {
    const { update } = this.props; // eslint-disable-line no-shadow

    // Preload file
    file.setAttribute('preload', 'auto');

    const onLoadeddata = () => {
      const { qari, surah, previous, next, playPause, surahs } = this.props;

      // Default current time to zero. This will change
      file.currentTime = 0; // eslint-disable-line no-param-reassign

      update({
        duration: file.duration
      });

      if ('mediaSession' in navigator) {
        navigator.mediaSession.metadata = new MediaMetadata({
          title: `${surah.name.simple} (${surah.name.english})`,
          artist: qari.name,
          album: 'The Holy Quran'
        });

        const previousTrackHandler = this.isPlayPreviousDisabled()
          ? null
          : () => previous({ surahs: Object.values(surahs) });
        const nextTrackHandler = this.isPlayNextDisabled()
          ? null
          : () => next({ surahs: Object.values(surahs) });

        navigator.mediaSession.setActionHandler('play', playPause);
        navigator.mediaSession.setActionHandler('pause', playPause);
        navigator.mediaSession.setActionHandler(
          'previoustrack',
          previousTrackHandler
        );
        navigator.mediaSession.setActionHandler('nexttrack', nextTrackHandler);
      }
    };

    const onTimeupdate = () => {
      const progress = file.currentTime / file.duration * 100;

      update({
        progress,
        currentTime: file.currentTime,
        isPlaying: !file.paused
      });
    };

    const onEnded = () => {
      const { shouldRepeat, shouldContinuous, shouldRandom } = this.props;

      if (shouldRepeat) {
        file.pause();
        file.currentTime = 0; // eslint-disable-line no-param-reassign
        file.play();
      } else if (shouldContinuous) {
        const { surah, surahs, qari } = this.props; // eslint-disable-line no-shadow
        this.props.load({ surah: Object.values(surahs)[surah.id], qari: qari });
      } else if (shouldRandom) {
        const { surahs, qari } = this.props; // eslint-disable-line no-shadow
        const randomSurah = Math.floor(Math.random() * (113 + 1));
        this.props.load({
          surah: Object.values(surahs)[randomSurah],
          qari: qari
        });
      } else {
        if (file.readyState >= 3 && file.paused) {
          file.pause();
        }

        update({
          surah: null,
          isPlaying: false
        });
      }
    };

    const onPlay = () => {};

    file.onloadeddata = onLoadeddata;
    file.ontimeupdate = onTimeupdate;
    file.onplay = onPlay;
    file.onended = onEnded;
  }

  static handleRemoveFileListeneres(file) {
    if (file) {
      file.pause();
      file.onloadeddata = null;
      file.ontimeupdate = null;
      file.onplay = null;
      file.onended = null;
    }
  }

  static isPlayPreviousDisabled() {
    const { surah, surahPage, qari } = this.props; // eslint-disable-line no-shadow
    const disableBasedOnSurah = surah.id === 1;
    const disabled = surahPage ? qari.id === 1 && true : disableBasedOnSurah;
    return disabled;
  }

  static isPlayNextDisabled() {
    const { surah, qaris, surahPage, qari } = this.props; // eslint-disable-line no-shadow
    const disableBasedOnSurah = surah.id === 114;
    const disabled = surahPage
      ? qari.id === Object.keys(qaris).length
      : disableBasedOnSurah;
    return disabled;
  }

  static handleKeyboardEvent(event) {
    const { code } = event;
    const { previous, next, playPause, surahs } = this.props; // eslint-disable-line no-shadow
    if (code === 'Space') {
      event.preventDefault();
      playPause();
    } else if (
      (code === 'ArrowRight' || code === 'ArrowDown') &&
      !this.isPlayNextDisabled()
    ) {
      event.preventDefault();
      next({ surahs: Object.values(surahs) });
    } else if (
      (code === 'ArrowLeft' || code === 'ArrowUp') &&
      !this.isPlayPreviousDisabled()
    ) {
      event.preventDefault();
      previous({ surahs: Object.values(surahs) });
    }
  }
}
<|endoftext|>


<commit_before>/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue, JSON */
'use strict';

// //////////////////////////////////////////////////////////////////////////////
// / @brief Spec for Foxx manager
// /
// / @file
// /
// / DISCLAIMER
// /
// / Copyright 2014 ArangoDB GmbH, Cologne, Germany
// /
// / Licensed under the Apache License, Version 2.0 (the "License")
// / you may not use this file except in compliance with the License.
// / You may obtain a copy of the License at
// /
// /     http://www.apache.org/licenses/LICENSE-2.0
// /
// / Unless required by applicable law or agreed to in writing, software
// / distributed under the License is distributed on an "AS IS" BASIS,
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// / See the License for the specific language governing permissions and
// / limitations under the License.
// /
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
// /
// / @author Simon Grätzer
// / @author Copyright 2017, ArangoDB GmbH, Cologne, Germany
// //////////////////////////////////////////////////////////////////////////////

var jsunity = require("jsunity");
var db = require("@arangodb").db;
var graph_module = require("@arangodb/general-graph");
var internal = require("internal");
var console = require("console");
var EPS = 0.0001;
let pregel = require("@arangodb/pregel");

const graphName = "UnitTest_pregel";
var vColl = "UnitTest_pregel_v", eColl = "UnitTest_pregel_e";

function testAlgo(a, p) {
  var pid = pregel.start(a, graphName, p);
  var i = 10000;
  do {
    internal.wait(0.2);
    var stats = pregel.status(pid);
    if (stats.state !== "running") {
      assertEqual(stats.vertexCount, 11, stats);
      assertEqual(stats.edgeCount, 17, stats);

      db[vColl].all().toArray()
      .forEach(function(d) {
                 if (d[a] && d[a] !== -1) {
                   var diff = Math.abs(d[a] - d.result);
                   if (diff > EPS) {
                     console.log("Error on " + JSON.stringify(d));
                     assertTrue(false);// peng
                   }
                 }
               });
      break;
    }
  } while(i-- >= 0);
  if (i === 0) {
    assertTrue(false, "timeout in pregel execution");
  }
}

function basicTestSuite () {
  'use strict';
  return {

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief set up
    ////////////////////////////////////////////////////////////////////////////////

    setUp : function () {

      var exists = graph_module._list().indexOf("demo") !== -1;
      if (exists || db.demo_v) {
        return;
      }
      var graph = graph_module._create(graphName);
      db._create(vColl, {numberOfShards: 4});
      graph._addVertexCollection(vColl);
      db._createEdgeCollection(eColl, {
                               numberOfShards: 4,
                               replicationFactor: 1,
                               shardKeys:["vertex"],
                               distributeShardsLike:vColl});

      var rel = graph_module._relation(eColl, [vColl], [vColl]);
      graph._extendEdgeDefinitions(rel);

      var vertices = db[vColl];
      var edges = db[eColl];

      var A = vertices.insert({_key:'A', sssp:3, pagerank:0.027645934})._id;
      var B = vertices.insert({_key:'B', sssp:2, pagerank:0.3241496})._id;
      var C = vertices.insert({_key:'C', sssp:3, pagerank:0.289220})._id;
      var D = vertices.insert({_key:'D', sssp:2, pagerank:0.0329636})._id;
      var E = vertices.insert({_key:'E', sssp:1, pagerank:0.0682141})._id;
      var F = vertices.insert({_key:'F', sssp:2, pagerank:0.0329636})._id;
      var G = vertices.insert({_key:'G', sssp:-1, pagerank:0.0136363})._id;
      var H = vertices.insert({_key:'H', sssp:-1, pagerank:0.01363636})._id;
      var I = vertices.insert({_key:'I', sssp:-1, pagerank:0.01363636})._id;
      var J = vertices.insert({_key:'J', sssp:-1, pagerank:0.01363636})._id;
      var K = vertices.insert({_key:'K', sssp:0, pagerank:0.013636363})._id;

      edges.insert({_from:B, _to:C, vertex:'B'});
      edges.insert({_from:C, _to:B, vertex:'C'});
      edges.insert({_from:D, _to:A, vertex:'D'});
      edges.insert({_from:D, _to:B, vertex:'D'});
      edges.insert({_from:E, _to:B, vertex:'E'});
      edges.insert({_from:E, _to:D, vertex:'E'});
      edges.insert({_from:E, _to:F, vertex:'E'});
      edges.insert({_from:F, _to:B, vertex:'F'});
      edges.insert({_from:F, _to:E, vertex:'F'});
      edges.insert({_from:G, _to:B, vertex:'G'});
      edges.insert({_from:G, _to:E, vertex:'G'});
      edges.insert({_from:H, _to:B, vertex:'H'});
      edges.insert({_from:H, _to:E, vertex:'H'});
      edges.insert({_from:I, _to:B, vertex:'I'});
      edges.insert({_from:I, _to:E, vertex:'I'});
      edges.insert({_from:J, _to:E, vertex:'J'});
      edges.insert({_from:K, _to:E, vertex:'K'});
    },

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief tear down
    ////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      graph_module._drop(graphName, true);
    },

    testSSSPNormal: function () {
      testAlgo("sssp", {async:false, source:vColl + "/K", resultField: "result"});
    },

    testSSSPAsync: function () {
      testAlgo("sssp", {async:true, source:vColl + "/K", resultField: "result"});
    },

    testPageRank: function () {
      // should test correct convergence behaviour, might fail if EPS is too low
      testAlgo("pagerank", {threshold:EPS / 10, resultField: "result"});
    },

    testPageRankSeeded: function() {
      // test that pagerank picks the seed value
      testAlgo("pagerank", {maxGSS:1,  sourceField: "pagerank", resultField: "result"});
      // since we already use converged values this should not change anything
      testAlgo("pagerank", {maxGSS:5, sourceField: "pagerank", resultField: "result"});
    },

    // test the PREGEL_RESULT AQL function
    testPageRankAQLResult: function() {
      var pid = pregel.start("pagerank", graphName, {threshold:EPS / 10, store:false});
      var i = 10000;
      do {
        internal.wait(0.2);
        var stats = pregel.status(pid);
        if (stats.state !== "running") {
          assertEqual(stats.vertexCount, 11, stats);
          assertEqual(stats.edgeCount, 17, stats);

          let vertices = db._collection(vColl);
          // no result was written to the default result field
          vertices.all().toArray().forEach( d => assertTrue(!d.result));

          let cursor = db._query("RETURN PREGEL_RESULT(@id)", {"id": pid});
          let array = cursor.toArray();
          assertEqual(array.length, 1);
          let results = array[0];
          assertEqual(results.length, 11);

          // verify results
          results.forEach(function(d) {
            let v = vertices.document(d._key);
            assertTrue(v !== null);
            assertTrue(Math.abs(v.pagerank - d.result) < EPS);
          });
          break;
        }
      } while(i-- >= 0);
      if (i === 0) {
        assertTrue(false, "timeout in pregel execution");
      }
    }
  };
};

function exampleTestSuite () {
  'use strict';
  return {

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief set up
    ////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var examples = require("@arangodb/graph-examples/example-graph.js");
      var graph = examples.loadGraph("social");
    },

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief tear down
    ////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      graph_module._drop("social", true);
    },

    testSocial: function () {
      var key = db._pregelStart("effectivecloseness",
                                ['female', 'male'], ['relation'],
                                {resultField: "closeness"});
      var i = 10000;
      do {
        internal.wait(0.2);
        var stats = db._pregelStatus(key);
        if (stats.state !== "running") {
          assertEqual(stats.vertexCount, 4, stats);
          assertEqual(stats.edgeCount, 4, stats);
          break;
        }
      } while(i-- >= 0);
      if (i === 0) {
        assertTrue(false, "timeout in pregel execution");
      }
    }
  };
};

jsunity.run(basicTestSuite);
jsunity.run(exampleTestSuite);

return jsunity.done();
<commit_msg>added log output for pregel job status (#8673)<commit_after>/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue, JSON */
'use strict';

// //////////////////////////////////////////////////////////////////////////////
// / @brief Spec for Foxx manager
// /
// / @file
// /
// / DISCLAIMER
// /
// / Copyright 2014 ArangoDB GmbH, Cologne, Germany
// /
// / Licensed under the Apache License, Version 2.0 (the "License")
// / you may not use this file except in compliance with the License.
// / You may obtain a copy of the License at
// /
// /     http://www.apache.org/licenses/LICENSE-2.0
// /
// / Unless required by applicable law or agreed to in writing, software
// / distributed under the License is distributed on an "AS IS" BASIS,
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// / See the License for the specific language governing permissions and
// / limitations under the License.
// /
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
// /
// / @author Simon Grätzer
// / @author Copyright 2017, ArangoDB GmbH, Cologne, Germany
// //////////////////////////////////////////////////////////////////////////////

var jsunity = require("jsunity");
var db = require("@arangodb").db;
var graph_module = require("@arangodb/general-graph");
var internal = require("internal");
var console = require("console");
var EPS = 0.0001;
let pregel = require("@arangodb/pregel");

const graphName = "UnitTest_pregel";
var vColl = "UnitTest_pregel_v", eColl = "UnitTest_pregel_e";

function testAlgo(a, p) {
  var pid = pregel.start(a, graphName, p);
  var i = 10000;
  let stats = pregel.status(pid);
  console.debug("topic=pregel", "initial stats: " + JSON.stringify(stats));
  do {
    internal.wait(0.2, false);
    stats = pregel.status(pid);
    if (stats.state !== "running") {
      assertEqual(stats.vertexCount, 11, stats);
      assertEqual(stats.edgeCount, 17, stats);

      db[vColl].all().toArray()
      .forEach(function(d) {
                 if (d[a] && d[a] !== -1) {
                   var diff = Math.abs(d[a] - d.result);
                   if (diff > EPS) {
                     console.log("Error on " + JSON.stringify(d));
                     assertTrue(false);// peng
                   }
                 }
               });
      break;
    }
    if (i % 100 === 0) {
      console.info("topic=pregel", "pregel stats: " + JSON.stringify(stats));
    }
  } while (i-- >= 0);
  if (i === 0) {
    assertTrue(false, "timeout in pregel execution");
  }
}

function basicTestSuite () {
  'use strict';
  return {

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief set up
    ////////////////////////////////////////////////////////////////////////////////

    setUp : function () {

      var exists = graph_module._list().indexOf("demo") !== -1;
      if (exists || db.demo_v) {
        return;
      }
      var graph = graph_module._create(graphName);
      db._create(vColl, {numberOfShards: 4});
      graph._addVertexCollection(vColl);
      db._createEdgeCollection(eColl, {
                               numberOfShards: 4,
                               replicationFactor: 1,
                               shardKeys:["vertex"],
                               distributeShardsLike:vColl});

      var rel = graph_module._relation(eColl, [vColl], [vColl]);
      graph._extendEdgeDefinitions(rel);

      var vertices = db[vColl];
      var edges = db[eColl];

      var A = vertices.insert({_key:'A', sssp:3, pagerank:0.027645934})._id;
      var B = vertices.insert({_key:'B', sssp:2, pagerank:0.3241496})._id;
      var C = vertices.insert({_key:'C', sssp:3, pagerank:0.289220})._id;
      var D = vertices.insert({_key:'D', sssp:2, pagerank:0.0329636})._id;
      var E = vertices.insert({_key:'E', sssp:1, pagerank:0.0682141})._id;
      var F = vertices.insert({_key:'F', sssp:2, pagerank:0.0329636})._id;
      var G = vertices.insert({_key:'G', sssp:-1, pagerank:0.0136363})._id;
      var H = vertices.insert({_key:'H', sssp:-1, pagerank:0.01363636})._id;
      var I = vertices.insert({_key:'I', sssp:-1, pagerank:0.01363636})._id;
      var J = vertices.insert({_key:'J', sssp:-1, pagerank:0.01363636})._id;
      var K = vertices.insert({_key:'K', sssp:0, pagerank:0.013636363})._id;

      edges.insert({_from:B, _to:C, vertex:'B'});
      edges.insert({_from:C, _to:B, vertex:'C'});
      edges.insert({_from:D, _to:A, vertex:'D'});
      edges.insert({_from:D, _to:B, vertex:'D'});
      edges.insert({_from:E, _to:B, vertex:'E'});
      edges.insert({_from:E, _to:D, vertex:'E'});
      edges.insert({_from:E, _to:F, vertex:'E'});
      edges.insert({_from:F, _to:B, vertex:'F'});
      edges.insert({_from:F, _to:E, vertex:'F'});
      edges.insert({_from:G, _to:B, vertex:'G'});
      edges.insert({_from:G, _to:E, vertex:'G'});
      edges.insert({_from:H, _to:B, vertex:'H'});
      edges.insert({_from:H, _to:E, vertex:'H'});
      edges.insert({_from:I, _to:B, vertex:'I'});
      edges.insert({_from:I, _to:E, vertex:'I'});
      edges.insert({_from:J, _to:E, vertex:'J'});
      edges.insert({_from:K, _to:E, vertex:'K'});
    },

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief tear down
    ////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      graph_module._drop(graphName, true);
    },

    testSSSPNormal: function () {
      testAlgo("sssp", {async:false, source:vColl + "/K", resultField: "result"});
    },

    testSSSPAsync: function () {
      testAlgo("sssp", {async:true, source:vColl + "/K", resultField: "result"});
    },

    testPageRank: function () {
      // should test correct convergence behaviour, might fail if EPS is too low
      testAlgo("pagerank", {threshold:EPS / 10, resultField: "result"});
    },

    testPageRankSeeded: function() {
      // test that pagerank picks the seed value
      testAlgo("pagerank", {maxGSS:1,  sourceField: "pagerank", resultField: "result"});
      // since we already use converged values this should not change anything
      testAlgo("pagerank", {maxGSS:5, sourceField: "pagerank", resultField: "result"});
    },

    // test the PREGEL_RESULT AQL function
    testPageRankAQLResult: function() {
      var pid = pregel.start("pagerank", graphName, {threshold:EPS / 10, store:false});
      var i = 10000;
      let stats = pregel.status(pid);
      console.debug("topic=pregel", "initial stats: " + JSON.stringify(stats));
      do {
        internal.wait(0.2, false);
        stats = pregel.status(pid);
        if (stats.state !== "running") {
          assertEqual(stats.vertexCount, 11, stats);
          assertEqual(stats.edgeCount, 17, stats);

          let vertices = db._collection(vColl);
          // no result was written to the default result field
          vertices.all().toArray().forEach( d => assertTrue(!d.result));

          let cursor = db._query("RETURN PREGEL_RESULT(@id)", {"id": pid});
          let array = cursor.toArray();
          assertEqual(array.length, 1);
          let results = array[0];
          assertEqual(results.length, 11);

          // verify results
          results.forEach(function(d) {
            let v = vertices.document(d._key);
            assertTrue(v !== null);
            assertTrue(Math.abs(v.pagerank - d.result) < EPS);
          });
          break;
        }
        if (i % 100 === 0) {
          console.info("topic=pregel", "pregel stats: " + JSON.stringify(stats));
        }
      } while (i-- >= 0);
      if (i === 0) {
        assertTrue(false, "timeout in pregel execution");
      }
    }
  };
};

function exampleTestSuite () {
  'use strict';
  return {

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief set up
    ////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var examples = require("@arangodb/graph-examples/example-graph.js");
      var graph = examples.loadGraph("social");
    },

    ////////////////////////////////////////////////////////////////////////////////
    /// @brief tear down
    ////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      graph_module._drop("social", true);
    },

    testSocial: function () {
      var key = db._pregelStart("effectivecloseness",
                                ['female', 'male'], ['relation'],
                                {resultField: "closeness"});
      var i = 10000;
      let stats = db._pregelStatus(key);
      console.debug("topic=pregel", "initial stats: " + JSON.stringify(stats));
      do {
        internal.wait(0.2, false);
        stats = db._pregelStatus(key);
        if (stats.state !== "running") {
          assertEqual(stats.vertexCount, 4, stats);
          assertEqual(stats.edgeCount, 4, stats);
          break;
        }
        if (i % 100 === 0) {
          console.info("topic=pregel", "pregel stats: " + JSON.stringify(stats));
        }
      } while(i-- >= 0);
      if (i === 0) {
        assertTrue(false, "timeout in pregel execution");
      }
    }
  };
};

jsunity.run(basicTestSuite);
jsunity.run(exampleTestSuite);

return jsunity.done();
<|endoftext|>


<commit_before>function UserShowTempChartCircles(svgObj, optionsObj){
  this.data = svgObj.data;
  this.svg = svgObj.svg;
  this.x = svgObj.x;
  this.y = svgObj.y;
  this.violations = svgObj.violations;
  this.circleRadius = optionsObj.circleRadius || 4;
  this.hasTransitions = optionsObj.hasTransitions || false;
  this.transitionDuration = optionsObj.transitionDuration || 1000;
  this.hasToolTips = optionsObj.hasToolTips || false;
  this.dataCirclesGroup = this.setDataCirclesGroup();
  this.dataCircles = this.setDataCircles();
};

UserShowTempChartCircles.prototype.setDataCirclesGroup = function(){
  return this.svg.append('svg:g');
};

UserShowTempChartCircles.prototype.setDataCircles = function(){
  return this.dataCirclesGroup
    .selectAll('.data-point')
    .data(this.data);
};

UserShowTempChartCircles.prototype.addCirclesWithTransitions = function(){
  var self = this;
  self.dataCircles.enter()
    .append('svg:circle')
    .attr('class', 'data-point')
    .style('opacity', 1)
    .attr('cx', function(d) { return self.x(d.date) })
    .attr('cy', function() { return self.y(0) })
    .attr('r', function(d) {
      return d.violation ? self.circleRadius : 0;
    })
    .attr('class', function(d) {
      return d.violation ? "violation" : ""
    })
    .transition()
    .duration(self.transitionDuration)
    .style('opacity', 1)
    .attr('cx', function(d) { return self.x(d.date) })
    .attr('cy', function(d) { return self.y(d.temp) });
};

UserShowTempChartCircles.prototype.addCirclesWithoutTransitions = function(){
  var self = this;
  self.dataCircles.enter()
    .append('svg:circle')
    .attr('class', 'data-point')
    .attr('cx', function(d) { return self.x(d.date) })
    .attr('cy', function(d) { return self.y(d.temp) })
    .attr('r', function(d) {
      return d.violation ? self.circleRadius : 0;
    });
};

UserShowTempChartCircles.prototype.addToolTips = function(){
  if ( this.hasToolTips ) {
    var toolTips = new UserShowTempChartToolTips;
    toolTips.addToChart();
  }
};

UserShowTempChartCircles.prototype.addToChart = function (){
  if ( this.violations ) {
    if ( this.hasTransitions ) {
      this.addCirclesWithTransitions();
    } else {
      this.addCirclesWithoutTransitions();
    }
    this.addToolTips();
  }
};
<commit_msg>Restore the redness of the violations on the chart<commit_after>function UserShowTempChartCircles(svgObj, optionsObj){
  this.data = svgObj.data;
  this.svg = svgObj.svg;
  this.x = svgObj.x;
  this.y = svgObj.y;
  this.violations = svgObj.violations;
  this.circleRadius = optionsObj.circleRadius || 4;
  this.hasTransitions = optionsObj.hasTransitions || false;
  this.transitionDuration = optionsObj.transitionDuration || 1000;
  this.hasToolTips = optionsObj.hasToolTips || false;
  this.dataCirclesGroup = this.setDataCirclesGroup();
  this.dataCircles = this.setDataCircles();
};

UserShowTempChartCircles.prototype.setDataCirclesGroup = function(){
  return this.svg.append('svg:g');
};

UserShowTempChartCircles.prototype.setDataCircles = function(){
  return this.dataCirclesGroup
    .selectAll('.data-point')
    .data(this.data);
};

UserShowTempChartCircles.prototype.addCirclesWithTransitions = function(){
  var self = this;
  self.dataCircles.enter()
    .append('svg:circle')
    .attr('class', function(d) {
      return d.violation ? "data-point violation" : "data-point";
    })
    .style('opacity', 1)
    .attr('cx', function(d) { return self.x(d.date) })
    .attr('cy', function() { return self.y(0) })
    .attr('r', function(d) {
      return d.violation ? self.circleRadius : 0;
    })
    .transition()
    .duration(self.transitionDuration)
    .style('opacity', 1)
    .attr('cx', function(d) { return self.x(d.date) })
    .attr('cy', function(d) { return self.y(d.temp) });
};

UserShowTempChartCircles.prototype.addCirclesWithoutTransitions = function(){
  var self = this;
  self.dataCircles.enter()
    .append('svg:circle')
    .attr('class', 'data-point')
    .attr('cx', function(d) { return self.x(d.date) })
    .attr('cy', function(d) { return self.y(d.temp) })
    .attr('r', function(d) {
      return d.violation ? self.circleRadius : 0;
    });
};

UserShowTempChartCircles.prototype.addToolTips = function(){
  if ( this.hasToolTips ) {
    var toolTips = new UserShowTempChartToolTips;
    toolTips.addToChart();
  }
};

UserShowTempChartCircles.prototype.addToChart = function (){
  if ( this.violations ) {
    if ( this.hasTransitions ) {
      this.addCirclesWithTransitions();
    } else {
      this.addCirclesWithoutTransitions();
    }
    this.addToolTips();
  }
};
<|endoftext|>


<commit_before>const {wrapItem, blockTypeItem, Dropdown, DropdownSubmenu, joinUpItem, liftItem,
       selectParentNodeItem, undoItem, redoItem, icons, MenuItem} = require("prosemirror-menu")
const {toggleMark} = require("prosemirror-commands")
const {wrapInList} = require("prosemirror-schema-list")
const {TextField, SelectField, openPrompt} = require("./prompt")
const {ImageSelectorField, MultiSelectField} = require("./prompt-extra")

// Helpers to create specific types of items

function canInsert(state, nodeType, attrs) {
  let $from = state.selection.$from
  for (let d = $from.depth; d >= 0; d--) {
    let index = $from.index(d)
    if ($from.node(d).canReplaceWith(index, index, nodeType, attrs)) return true
  }
  return false
}

function insertImageItem(nodeType) {
    return new MenuItem({
        title: "Insert image",
        label: "Image",
        select(state) { return canInsert(state, nodeType) },
        run(state, _, view) {
            let {node} = state.selection, attrs = nodeType && node &&
                    node.type == nodeType && node.attrs;
            const uploadUrl = `/api/narrations/${view.props.narrationId}/images`;

            openPrompt({
                title: "Choose an image",
                fields: {
                    image: new ImageSelectorField({
                        label: "Image",
                        required: true,
                        selected: attrs && attrs.src,
                        images: view.props.images,
                        uploadUrl: uploadUrl,
                        addImageCallback: name => {
                            view.props.images.push(name);
                        }
                    })
                },
                // FIXME this (and similar uses) won't have the current state
                // when it runs, leading to problems in, for example, a
                // collaborative setup
                callback(attrs) {
                    const imageName = attrs.image;
                    const imageUrl = `/static/narrations/${view.props.narrationId}/images/${imageName}`;
                    view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill({src: imageUrl})));
                    view.focus();
                }
            });
        }
    });
}

function positiveInteger(value) {
  if (!/^[1-9]\d*$/.test(value)) return "Should be a positive integer"
}

function cmdItem(cmd, options) {
  let passedOptions = {
    label: options.title,
    run: cmd,
    select(state) { return cmd(state) }
  }
  for (let prop in options) passedOptions[prop] = options[prop]
  return new MenuItem(passedOptions)
}

function markActive(state, type) {
  let {from, $from, to, empty} = state.selection
  if (empty) return type.isInSet(state.storedMarks || $from.marks())
  else return state.doc.rangeHasMark(from, to, type)
}

function markItem(markType, options) {
  let passedOptions = {
    active(state) { return markActive(state, markType) }
  }
  for (let prop in options) passedOptions[prop] = options[prop]
  return cmdItem(toggleMark(markType), passedOptions)
}

function linkItem(markType) {
  return new MenuItem({
    title: "Add or remove link",
    icon: icons.link,
    active(state) { return markActive(state, markType) },
    select(state) { return !state.selection.empty },
    onDeselected: "disable",
    run(state, dispatch, view) {
      if (markActive(state, markType)) {
        toggleMark(markType)(state, dispatch)
        return true
      }
      openPrompt({
        title: "Create a link",
        fields: {
          href: new TextField({
            label: "Link target",
            required: true,
            clean: (val) => {
              if (!/^https?:\/\//i.test(val))
                val = 'http://' + val
              return val
            }
          }),
          title: new TextField({label: "Title"})
        },
        callback(attrs) {
          toggleMark(markType, attrs)(view.state, view.dispatch)
          view.focus()
        }
      })
    }
  })
}

function fetchCharacter(characterList, cId) {
    const matches = characterList.filter(c => c.id === parseInt(cId, 10));
    return matches.length ? matches[0] : null;
}

/* Copied from prosemirror-commands because it's not exported */
function markApplies(doc, ranges, type) {
  for (let i = 0; i < ranges.length; i++) {
    let {$from, $to} = ranges[i]
    let can = $from.depth == 0 ? doc.contentMatchAt(0).allowsMark(type) : false
    doc.nodesBetween($from.pos, $to.pos, node => {
      if (can) return false
      can = node.inlineContent && node.contentMatchAt(0).allowsMark(type)
    })
    if (can) return true
  }
  return false
}

function updateMentionMark(markType, targetCharacters, state, dispatch) {
    const {empty, $cursor, ranges} = state.selection;
    const attrs = {mentionTargets: targetCharacters};
    if ((empty && !$cursor) || !markApplies(state.doc, ranges, markType)) return false;
    if (dispatch) {
        if ($cursor) {
            if (markType.isInSet(state.storedMarks || $cursor.marks())) {
                state.tr.removeStoredMark(markType);
            }

            if (targetCharacters.length) {
                state.tr.addStoredMark(markType.create(attrs));
            }

            dispatch(state.tr.scrollIntoView());
        } else {
            let has = false, tr = state.tr;
            for (let i = 0; !has && i < ranges.length; i++) {
                let {$from, $to} = ranges[i];
                has = state.doc.rangeHasMark($from.pos, $to.pos, markType);
            }
            for (let i = 0; i < ranges.length; i++) {
                let {$from, $to} = ranges[i];
                if (has) {
                    tr.removeMark($from.pos, $to.pos, markType);
                }

                if (targetCharacters.length) {
                    tr.addMark($from.pos, $to.pos, markType.create(attrs));
                }
            }
            dispatch(tr.scrollIntoView());
        }
    }
    return true;
}

function markItemPrivate(markType) {
    return markItem(markType, {
        title: "Private text",
        icon: {css: "background-image: url('/img/private.png'); " +
                        "height: 16px; width: 16px; display: inline-block"},
        run(state, onAction, view) {
            let {from, $from, to, empty} = state.selection;
            const activeMark = markType.isInSet(state.storedMarks || $from.marks());
            const markAttrs = activeMark && activeMark.attrs ||
                  {mentionTargets: []};

            openPrompt({
                title: "Choose the characters who will read the private text",
                fields: {
                    targetCharacters: new MultiSelectField({
                        label: "Targets",
                        required: true,
                        selected: markAttrs.mentionTargets.map(t => t.id),
                        options: view.props.participants.map(c => ({value: c.id,
                                                                    label: c.name}))
                    })
                },
                // FIXME this (and similar uses) won't have the current state
                // when it runs, leading to problems in, for example, a
                // collaborative setup
                callback(attrs) {
                    const targetCharacters = attrs.targetCharacters.map(
                        c => fetchCharacter(view.props.participants, c)
                    );

                    updateMentionMark(markType, targetCharacters, state, onAction);
                }
            });
        }
    });
}

function wrapListItem(nodeType, options) {
  return cmdItem(wrapInList(nodeType, options.attrs), options)
}

// :: (Schema) → Object
// Given a schema, look for default mark and node types in it and
// return an object with relevant menu items relating to those marks:
//
// **`toggleStrong`**`: MenuItem`
//   : A menu item to toggle the [strong mark](#schema-basic.StrongMark).
//
// **`toggleEm`**`: MenuItem`
//   : A menu item to toggle the [emphasis mark](#schema-basic.EmMark).
//
// **`toggleCode`**`: MenuItem`
//   : A menu item to toggle the [code font mark](#schema-basic.CodeMark).
//
// **`toggleLink`**`: MenuItem`
//   : A menu item to toggle the [link mark](#schema-basic.LinkMark).
//
// **`insertImage`**`: MenuItem`
//   : A menu item to insert an [image](#schema-basic.Image).
//
// **`wrapBulletList`**`: MenuItem`
//   : A menu item to wrap the selection in a [bullet list](#schema-list.BulletList).
//
// **`wrapOrderedList`**`: MenuItem`
//   : A menu item to wrap the selection in an [ordered list](#schema-list.OrderedList).
//
// **`wrapBlockQuote`**`: MenuItem`
//   : A menu item to wrap the selection in a [block quote](#schema-basic.BlockQuote).
//
// **`makeParagraph`**`: MenuItem`
//   : A menu item to set the current textblock to be a normal
//     [paragraph](#schema-basic.Paragraph).
//
// **`makeCodeBlock`**`: MenuItem`
//   : A menu item to set the current textblock to be a
//     [code block](#schema-basic.CodeBlock).
//
// **`insertTable`**`: MenuItem`
//   : An item to insert a [table](#schema-table).
//
// **`addRowBefore`**, **`addRowAfter`**, **`removeRow`**, **`addColumnBefore`**, **`addColumnAfter`**, **`removeColumn`**`: MenuItem`
//   : Table-manipulation items.
//
// **`makeHead[N]`**`: MenuItem`
//   : Where _N_ is 1 to 6. Menu items to set the current textblock to
//     be a [heading](#schema-basic.Heading) of level _N_.
//
// **`insertHorizontalRule`**`: MenuItem`
//   : A menu item to insert a horizontal rule.
//
// The return value also contains some prefabricated menu elements and
// menus, that you can use instead of composing your own menu from
// scratch:
//
// **`insertMenu`**`: Dropdown`
//   : A dropdown containing the `insertImage` and
//     `insertHorizontalRule` items.
//
// **`typeMenu`**`: Dropdown`
//   : A dropdown containing the items for making the current
//     textblock a paragraph, code block, or heading.
//
// **`fullMenu`**`: [[MenuElement]]`
//   : An array of arrays of menu elements for use as the full menu
//     for, for example the [menu bar](#menu.MenuBarEditorView).
function buildMenuItems(schema) {
  let r = {}, type
  if (type = schema.marks.strong)
    r.toggleStrong = markItem(type, {title: "Toggle strong style", icon: icons.strong})
  if (type = schema.marks.em)
    r.toggleEm = markItem(type, {title: "Toggle emphasis", icon: icons.em})
  if (type = schema.marks.code)
    r.toggleCode = markItem(type, {title: "Toggle code font", icon: icons.code})
  if (type = schema.marks.link)
    r.toggleLink = linkItem(type)

  if (type = schema.nodes.image)
    r.insertImage = insertImageItem(type)
  if (type = schema.marks.mention)
    r.togglePrivate = markItemPrivate(type)
  if (type = schema.nodes.bullet_list)
    r.wrapBulletList = wrapListItem(type, {
      title: "Wrap in bullet list",
      icon: icons.bulletList
    })
  if (type = schema.nodes.ordered_list)
    r.wrapOrderedList = wrapListItem(type, {
      title: "Wrap in ordered list",
      icon: icons.orderedList
    })
  if (type = schema.nodes.blockquote)
    r.wrapBlockQuote = wrapItem(type, {
      title: "Wrap in block quote",
      icon: icons.blockquote
    })
  if (type = schema.nodes.paragraph)
    r.makeParagraph = blockTypeItem(type, {
      title: "Change to paragraph",
      label: "Plain"
    })
  if (type = schema.nodes.code_block)
    r.makeCodeBlock = blockTypeItem(type, {
      title: "Change to code block",
      label: "Code"
    })
  if (type = schema.nodes.heading)
    for (let i = 1; i <= 10; i++)
      r["makeHead" + i] = blockTypeItem(type, {
        title: "Change to heading " + i,
        label: "Level " + i,
        attrs: {level: i}
      })
  if (type = schema.nodes.horizontal_rule) {
    let hr = type
    r.insertHorizontalRule = new MenuItem({
      title: "Insert horizontal rule",
      label: "Horizontal rule",
      select(state) { return canInsert(state, hr) },
      run(state, dispatch) { dispatch(state.tr.replaceSelectionWith(hr.create())) }
    })
  }

  let cut = arr => arr.filter(x => x)
  r.insertMenu = new Dropdown(cut([r.insertImage, r.insertHorizontalRule, r.insertTable]), {label: "Insert"})
  r.typeMenu = new Dropdown(cut([r.makeParagraph, r.makeCodeBlock, r.makeHead1 && new DropdownSubmenu(cut([
    r.makeHead1, r.makeHead2, r.makeHead3, r.makeHead4, r.makeHead5, r.makeHead6
  ]), {label: "Heading"})]), {label: "Type..."})
  let tableItems = cut([r.addRowBefore, r.addRowAfter, r.removeRow, r.addColumnBefore, r.addColumnAfter, r.removeColumn])
  if (tableItems.length)
    r.tableMenu = new Dropdown(tableItems, {label: "Table"})

  r.inlineMenu = [cut([r.toggleStrong, r.toggleEm, r.toggleCode, r.toggleLink]), cut([r.togglePrivate]), [r.insertMenu]]
  r.blockMenu = [cut([r.typeMenu, r.tableMenu, r.wrapBulletList, r.wrapOrderedList, r.wrapBlockQuote, joinUpItem,
                      liftItem, selectParentNodeItem])]
  r.fullMenu = r.inlineMenu.concat(r.blockMenu).concat([[undoItem, redoItem]])

  return r
}
exports.buildMenuItems = buildMenuItems
<commit_msg>Fix private text option<commit_after>const {wrapItem, blockTypeItem, Dropdown, DropdownSubmenu, joinUpItem, liftItem,
       selectParentNodeItem, undoItem, redoItem, icons, MenuItem} = require("prosemirror-menu")
const {toggleMark} = require("prosemirror-commands")
const {wrapInList} = require("prosemirror-schema-list")
const {TextField, SelectField, openPrompt} = require("./prompt")
const {ImageSelectorField, MultiSelectField} = require("./prompt-extra")

// Helpers to create specific types of items

function canInsert(state, nodeType, attrs) {
  let $from = state.selection.$from
  for (let d = $from.depth; d >= 0; d--) {
    let index = $from.index(d)
    if ($from.node(d).canReplaceWith(index, index, nodeType, attrs)) return true
  }
  return false
}

function insertImageItem(nodeType) {
    return new MenuItem({
        title: "Insert image",
        label: "Image",
        select(state) { return canInsert(state, nodeType) },
        run(state, _, view) {
            let {node} = state.selection, attrs = nodeType && node &&
                    node.type == nodeType && node.attrs;
            const uploadUrl = `/api/narrations/${view.props.narrationId}/images`;

            openPrompt({
                title: "Choose an image",
                fields: {
                    image: new ImageSelectorField({
                        label: "Image",
                        required: true,
                        selected: attrs && attrs.src,
                        images: view.props.images,
                        uploadUrl: uploadUrl,
                        addImageCallback: name => {
                            view.props.images.push(name);
                        }
                    })
                },
                // FIXME this (and similar uses) won't have the current state
                // when it runs, leading to problems in, for example, a
                // collaborative setup
                callback(attrs) {
                    const imageName = attrs.image;
                    const imageUrl = `/static/narrations/${view.props.narrationId}/images/${imageName}`;
                    view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill({src: imageUrl})));
                    view.focus();
                }
            });
        }
    });
}

function positiveInteger(value) {
  if (!/^[1-9]\d*$/.test(value)) return "Should be a positive integer"
}

function cmdItem(cmd, options) {
  let passedOptions = {
    label: options.title,
    run: cmd,
    select(state) { return cmd(state) }
  }
  for (let prop in options) passedOptions[prop] = options[prop]
  return new MenuItem(passedOptions)
}

function markActive(state, type) {
  let {from, $from, to, empty} = state.selection
  if (empty) return type.isInSet(state.storedMarks || $from.marks())
  else return state.doc.rangeHasMark(from, to, type)
}

function markItem(markType, options) {
  let passedOptions = {
    active(state) { return markActive(state, markType) }
  }
  for (let prop in options) passedOptions[prop] = options[prop]
  return cmdItem(toggleMark(markType), passedOptions)
}

function linkItem(markType) {
  return new MenuItem({
    title: "Add or remove link",
    icon: icons.link,
    active(state) { return markActive(state, markType) },
    select(state) { return !state.selection.empty },
    onDeselected: "disable",
    run(state, dispatch, view) {
      if (markActive(state, markType)) {
        toggleMark(markType)(state, dispatch)
        return true
      }
      openPrompt({
        title: "Create a link",
        fields: {
          href: new TextField({
            label: "Link target",
            required: true,
            clean: (val) => {
              if (!/^https?:\/\//i.test(val))
                val = 'http://' + val
              return val
            }
          }),
          title: new TextField({label: "Title"})
        },
        callback(attrs) {
          toggleMark(markType, attrs)(view.state, view.dispatch)
          view.focus()
        }
      })
    }
  })
}

function fetchCharacter(characterList, cId) {
    const matches = characterList.filter(c => c.id === parseInt(cId, 10));
    return matches.length ? matches[0] : null;
}

/* Copied from prosemirror-commands because it's not exported */
function markApplies(doc, ranges, type) {
  for (let i = 0; i < ranges.length; i++) {
    let {$from, $to} = ranges[i]
    let can = $from.depth == 0 ? doc.type.allowsMarkType(type) : false
    doc.nodesBetween($from.pos, $to.pos, node => {
      if (can) return false
      can = node.inlineContent && node.type.allowsMarkType(type)
    })
    if (can) return true
  }
  return false
}

function updateMentionMark(markType, targetCharacters, state, dispatch) {
    const {empty, $cursor, ranges} = state.selection;
    const attrs = {mentionTargets: targetCharacters};
    if ((empty && !$cursor) || !markApplies(state.doc, ranges, markType)) return false;
    if (dispatch) {
        if ($cursor) {
            if (markType.isInSet(state.storedMarks || $cursor.marks())) {
                state.tr.removeStoredMark(markType);
            }

            if (targetCharacters.length) {
                state.tr.addStoredMark(markType.create(attrs));
            }

            dispatch(state.tr.scrollIntoView());
        } else {
            let has = false, tr = state.tr;
            for (let i = 0; !has && i < ranges.length; i++) {
                let {$from, $to} = ranges[i];
                has = state.doc.rangeHasMark($from.pos, $to.pos, markType);
            }
            for (let i = 0; i < ranges.length; i++) {
                let {$from, $to} = ranges[i];
                if (has) {
                    tr.removeMark($from.pos, $to.pos, markType);
                }

                if (targetCharacters.length) {
                    tr.addMark($from.pos, $to.pos, markType.create(attrs));
                }
            }
            dispatch(tr.scrollIntoView());
        }
    }
    return true;
}

function markItemPrivate(markType) {
    return markItem(markType, {
        title: "Private text",
        icon: {css: "background-image: url('/img/private.png'); " +
                        "height: 16px; width: 16px; display: inline-block"},
        run(state, onAction, view) {
            let {from, $from, to, empty} = state.selection;
            const activeMark = markType.isInSet(state.storedMarks || $from.marks());
            const markAttrs = activeMark && activeMark.attrs ||
                  {mentionTargets: []};

            openPrompt({
                title: "Choose the characters who will read the private text",
                fields: {
                    targetCharacters: new MultiSelectField({
                        label: "Targets",
                        required: true,
                        selected: markAttrs.mentionTargets.map(t => t.id),
                        options: view.props.participants.map(c => ({value: c.id,
                                                                    label: c.name}))
                    })
                },
                // FIXME this (and similar uses) won't have the current state
                // when it runs, leading to problems in, for example, a
                // collaborative setup
                callback(attrs) {
                    const targetCharacters = attrs.targetCharacters.map(
                        c => fetchCharacter(view.props.participants, c)
                    );

                    updateMentionMark(markType, targetCharacters, state, onAction);
                }
            });
        }
    });
}

function wrapListItem(nodeType, options) {
  return cmdItem(wrapInList(nodeType, options.attrs), options)
}

// :: (Schema) → Object
// Given a schema, look for default mark and node types in it and
// return an object with relevant menu items relating to those marks:
//
// **`toggleStrong`**`: MenuItem`
//   : A menu item to toggle the [strong mark](#schema-basic.StrongMark).
//
// **`toggleEm`**`: MenuItem`
//   : A menu item to toggle the [emphasis mark](#schema-basic.EmMark).
//
// **`toggleCode`**`: MenuItem`
//   : A menu item to toggle the [code font mark](#schema-basic.CodeMark).
//
// **`toggleLink`**`: MenuItem`
//   : A menu item to toggle the [link mark](#schema-basic.LinkMark).
//
// **`insertImage`**`: MenuItem`
//   : A menu item to insert an [image](#schema-basic.Image).
//
// **`wrapBulletList`**`: MenuItem`
//   : A menu item to wrap the selection in a [bullet list](#schema-list.BulletList).
//
// **`wrapOrderedList`**`: MenuItem`
//   : A menu item to wrap the selection in an [ordered list](#schema-list.OrderedList).
//
// **`wrapBlockQuote`**`: MenuItem`
//   : A menu item to wrap the selection in a [block quote](#schema-basic.BlockQuote).
//
// **`makeParagraph`**`: MenuItem`
//   : A menu item to set the current textblock to be a normal
//     [paragraph](#schema-basic.Paragraph).
//
// **`makeCodeBlock`**`: MenuItem`
//   : A menu item to set the current textblock to be a
//     [code block](#schema-basic.CodeBlock).
//
// **`insertTable`**`: MenuItem`
//   : An item to insert a [table](#schema-table).
//
// **`addRowBefore`**, **`addRowAfter`**, **`removeRow`**, **`addColumnBefore`**, **`addColumnAfter`**, **`removeColumn`**`: MenuItem`
//   : Table-manipulation items.
//
// **`makeHead[N]`**`: MenuItem`
//   : Where _N_ is 1 to 6. Menu items to set the current textblock to
//     be a [heading](#schema-basic.Heading) of level _N_.
//
// **`insertHorizontalRule`**`: MenuItem`
//   : A menu item to insert a horizontal rule.
//
// The return value also contains some prefabricated menu elements and
// menus, that you can use instead of composing your own menu from
// scratch:
//
// **`insertMenu`**`: Dropdown`
//   : A dropdown containing the `insertImage` and
//     `insertHorizontalRule` items.
//
// **`typeMenu`**`: Dropdown`
//   : A dropdown containing the items for making the current
//     textblock a paragraph, code block, or heading.
//
// **`fullMenu`**`: [[MenuElement]]`
//   : An array of arrays of menu elements for use as the full menu
//     for, for example the [menu bar](#menu.MenuBarEditorView).
function buildMenuItems(schema) {
  let r = {}, type
  if (type = schema.marks.strong)
    r.toggleStrong = markItem(type, {title: "Toggle strong style", icon: icons.strong})
  if (type = schema.marks.em)
    r.toggleEm = markItem(type, {title: "Toggle emphasis", icon: icons.em})
  if (type = schema.marks.code)
    r.toggleCode = markItem(type, {title: "Toggle code font", icon: icons.code})
  if (type = schema.marks.link)
    r.toggleLink = linkItem(type)

  if (type = schema.nodes.image)
    r.insertImage = insertImageItem(type)
  if (type = schema.marks.mention)
    r.togglePrivate = markItemPrivate(type)
  if (type = schema.nodes.bullet_list)
    r.wrapBulletList = wrapListItem(type, {
      title: "Wrap in bullet list",
      icon: icons.bulletList
    })
  if (type = schema.nodes.ordered_list)
    r.wrapOrderedList = wrapListItem(type, {
      title: "Wrap in ordered list",
      icon: icons.orderedList
    })
  if (type = schema.nodes.blockquote)
    r.wrapBlockQuote = wrapItem(type, {
      title: "Wrap in block quote",
      icon: icons.blockquote
    })
  if (type = schema.nodes.paragraph)
    r.makeParagraph = blockTypeItem(type, {
      title: "Change to paragraph",
      label: "Plain"
    })
  if (type = schema.nodes.code_block)
    r.makeCodeBlock = blockTypeItem(type, {
      title: "Change to code block",
      label: "Code"
    })
  if (type = schema.nodes.heading)
    for (let i = 1; i <= 10; i++)
      r["makeHead" + i] = blockTypeItem(type, {
        title: "Change to heading " + i,
        label: "Level " + i,
        attrs: {level: i}
      })
  if (type = schema.nodes.horizontal_rule) {
    let hr = type
    r.insertHorizontalRule = new MenuItem({
      title: "Insert horizontal rule",
      label: "Horizontal rule",
      select(state) { return canInsert(state, hr) },
      run(state, dispatch) { dispatch(state.tr.replaceSelectionWith(hr.create())) }
    })
  }

  let cut = arr => arr.filter(x => x)
  r.insertMenu = new Dropdown(cut([r.insertImage, r.insertHorizontalRule, r.insertTable]), {label: "Insert"})
  r.typeMenu = new Dropdown(cut([r.makeParagraph, r.makeCodeBlock, r.makeHead1 && new DropdownSubmenu(cut([
    r.makeHead1, r.makeHead2, r.makeHead3, r.makeHead4, r.makeHead5, r.makeHead6
  ]), {label: "Heading"})]), {label: "Type..."})
  let tableItems = cut([r.addRowBefore, r.addRowAfter, r.removeRow, r.addColumnBefore, r.addColumnAfter, r.removeColumn])
  if (tableItems.length)
    r.tableMenu = new Dropdown(tableItems, {label: "Table"})

  r.inlineMenu = [cut([r.toggleStrong, r.toggleEm, r.toggleCode, r.toggleLink]), cut([r.togglePrivate]), [r.insertMenu]]
  r.blockMenu = [cut([r.typeMenu, r.tableMenu, r.wrapBulletList, r.wrapOrderedList, r.wrapBlockQuote, joinUpItem,
                      liftItem, selectParentNodeItem])]
  r.fullMenu = r.inlineMenu.concat(r.blockMenu).concat([[undoItem, redoItem]])

  return r
}
exports.buildMenuItems = buildMenuItems
<|endoftext|>