<commit_before>// ==UserScript==
// @name        Stack Exchange Pronoun Assistant
// @namespace   https://github.com/Glorfindel83/
// @description Displays users' pronouns (mentioned in their profiles) in chat
// @author      Glorfindel
// @contributor ArtOfCode
// @contributor wizzwizz4
// @updateURL   https://raw.githubusercontent.com/Glorfindel83/SE-Userscripts/master/pronoun-assistant/pronoun-assistant.user.js
// @downloadURL https://raw.githubusercontent.com/Glorfindel83/SE-Userscripts/master/pronoun-assistant/pronoun-assistant.user.js
// @supportURL  https://stackapps.com/questions/8440/pronoun-assistant
// @version     2.1
// @match       *://chat.stackexchange.com/rooms/*
// @match       *://chat.stackoverflow.com/rooms/*
// @match       *://chat.meta.stackexchange.com/rooms/*
// @match       *://*.stackexchange.com/questions/*
// @match       *://*.stackoverflow.com/questions/*
// @match       *://*.superuser.com/questions/*
// @match       *://*.serverfault.com/questions/*
// @match       *://*.askubuntu.com/questions/*
// @match       *://*.stackapps.com/questions/*
// @match       *://*.mathoverflow.net/questions/*
// @exclude     *://*.stackexchange.com/questions/ask
// @exclude     *://*.stackoverflow.com/questions/ask
// @exclude     *://*.superuser.com/questions/ask
// @exclude     *://*.serverfault.com/questions/ask
// @exclude     *://*.askubuntu.com/questions/ask
// @exclude     *://*.stackapps.com/questions/ask
// @exclude     *://*.mathoverflow.net/questions/ask
// @grant       GM_addStyle
// @require     https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @require     https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// ==/UserScript==

/* global $, waitForKeyElements */

GM_addStyle(`
.tiny-signature {
  display: inline-flex;
  flex-direction: row-reverse;
  align-items: center;
  width: 100%;
}

.username {
  height: unset !important;
}

.pronouns {
  color: #777;
  padding-left: 5px;
}
`)

// List of pronouns to look out for
let allPronouns = [
  "him", "his",
  "she", "her?", // that covers 'he' as well
  "they", "them", "their",
  "ze", "hir", "zir",
  "xey", "xem", "xyr"
].join("|");
let pronounListRegex = new RegExp('\\W*((' + allPronouns + ')(\\s*/\\s*(' + allPronouns + '))+)\\W*', 'i');
let myPronounIsRegex = /(https?:\/\/)?(my\.)?pronoun\.is\/[\w/]+/i;
let explicitPronounsRegex = /pronouns:\s*([^.\n)]*)(\.|\n|\)|$)/im;

// Keys:   user IDs
// Values: either a list of DOM elements (specifically, the anchors to chat profiles)
//         or a string with pronouns.
var users = {};

// If we're on a Q&A site, also cache all changes to the `users` object to save on API calls
if (location.hostname.indexOf("chat") === -1) {
  const localStorageData = localStorage.stackPronounAssistant_users;
  const cached = localStorageData ? JSON.parse(localStorage.stackPronounAssistant_users) : {};
  const userData = {};
  Object.keys(cached).forEach(k => {userData[parseInt(k, 10)] = cached[k]});
  users = new Proxy(userData, {
    get: (obj, prop) => obj[prop],
    set: (obj, prop, value) => {
      obj[prop] = value;
      localStorage.stackPronounAssistant_users = JSON.stringify(userData);
    }
  });
}

// Adds pronoun information to a user's 'signature' in chat.
function showPronounsForChat(element, pronouns) {
  if (pronouns == "") {
    return;
  }
  // the element might contain both a tiny and a full signature
  element.find("div.username").each(function (index, usernameElement) {
    usernameElement.innerHTML = '' + usernameElement.innerHTML + '
'
      + '' + pronouns.replace(/(<([^>]+)>)/ig, "") + '';
  });
}

function showPronouns(element, pronouns) {
  if (pronouns == "") {
    return;
  }
  element.after($('' + pronouns.replace(/(<([^>]+)>)/ig, "") + ''));
}

// Check the user's 'about' in their chat profile for pronoun indicators
function getPronouns(aboutMe) {
  // Link to Pronoun Island, e.g.
  // http://my.pronoun.is/she
  var match = myPronounIsRegex.exec(aboutMe);
  if (match != null) {
    return match[0];
  }

  // Explicit pronouns specification, e.g.
  // Pronouns: he/him.
  // The end is indicated by a dot, a newline, or simply the end of the text.
  match = explicitPronounsRegex.exec(aboutMe);
  if (match != null) {
    return match[1];
  }

  // Check for pronouns (see above for the list) joined by a forward slash, e.g.
  // she/her
  // (he/him/his)
  // they / them
  match = pronounListRegex.exec(aboutMe);
  if (match != null) {
    return match[1];
  }

  // No pronouns found
  return "";
}

// Chat signatures
waitForKeyElements("a.signature", function(jNode) {
  let userID = jNode.attr("href").split("/users/")[1];
  if (!users[userID]) {
    users[userID] = [];
    users[userID].push(jNode);
    // Read chat profile
    $.get("https://" + location.host + "/users/thumbs/" + userID + "?showUsage=true", function(data) {
      let pronouns = data.user_message == null ? "" : getPronouns(data.user_message);
      users[userID].forEach(function (element) {
        showPronounsForChat(element, pronouns);
      });
      users[userID] = pronouns;
    });
  } else if (typeof users[userID] == 'string') {
    // We already have the pronouns, we can just use them.
    showPronounsForChat(jNode, users[userID]);
  } else {
    // User appearing multiple times, their profile is already being fetched.
    users[userID].push(jNode);
  }
});

// Q&A site user cards & comment usernames
(async () => {
  const sleep = async (ms) => {
    return new Promise(resolve => {
      setTimeout(resolve, ms);
    });
  };

  const userIds = [];
  const profiles = {};

  const $userElements = $("div.user-details > a, a.comment-user");

  // Grab all the user IDs out of a page first. We'll go back over them later to add pronouns in.
  $userElements.each(function() {
    const link = $(this).attr("href");
    if (!link.startsWith("/users/")) {
      // not a user card, but a community wiki post
      return;
    }
    const userId = parseInt(link.split("/users/")[1]);
    if (userIds.indexOf(userId) === -1) {
      userIds.push(userId);
    }
  });

  // Split the list into 100-item pages and grab profiles for each page.
  // This works because splice modifies the userIds array in-place, removing elements from the front and
  // returning them into the `page` variable. When we've used them all, the array will be empty.
  while (userIds.length > 0) {
    const page = userIds.splice(0, 100);

    const resp = await fetch("https://api.stackexchange.com/2.2/users/" + page.join(';') + "?site=" + location.hostname
                             + "&key=L8n*CvRX3ZsedRQicxnjIA((&filter=!23IboywNfWUzv_nydJbn*&pagesize=100");
    const data = await resp.json();
    if (typeof data.items !== 'undefined') {
      data.items.forEach(i => {
        profiles[i.user_id] = i.about_me;
      });
    }

    if (data.backoff) {
      // Respect backoffs, not just pronouns.
      await sleep(data.backoff * 1000);
    }
  }

  $userElements.each(function() {
    const link = $(this).attr("href");
    const userId = parseInt(link.split("/users/")[1]);
    if (!users[userId]) {
      // No pronouns calculated yet, we need to calculate and store them.
      users[userId] = getPronouns(profiles[userId]);
      showPronouns($(this), users[userId]);
    }
    else {
      // We already have the pronouns, we can just use them.
      showPronouns($(this), users[userId]);
    }
  });
})();
<commit_msg>Pronoun Assistant v2.2, now with local cache<commit_after>// ==UserScript==
// @name        Stack Exchange Pronoun Assistant
// @namespace   https://github.com/Glorfindel83/
// @description Displays users' pronouns (mentioned in their profiles)
// @author      Glorfindel
// @author      ArtOfCode
// @contributor wizzwizz4
// @updateURL   https://raw.githubusercontent.com/Glorfindel83/SE-Userscripts/master/pronoun-assistant/pronoun-assistant.user.js
// @downloadURL https://raw.githubusercontent.com/Glorfindel83/SE-Userscripts/master/pronoun-assistant/pronoun-assistant.user.js
// @supportURL  https://stackapps.com/questions/8440/pronoun-assistant
// @version     2.2
// @match       *://chat.stackexchange.com/rooms/*
// @match       *://chat.stackoverflow.com/rooms/*
// @match       *://chat.meta.stackexchange.com/rooms/*
// @match       *://*.stackexchange.com/questions/*
// @match       *://*.stackoverflow.com/questions/*
// @match       *://*.superuser.com/questions/*
// @match       *://*.serverfault.com/questions/*
// @match       *://*.askubuntu.com/questions/*
// @match       *://*.stackapps.com/questions/*
// @match       *://*.mathoverflow.net/questions/*
// @exclude     *://*.stackexchange.com/questions/ask
// @exclude     *://*.stackoverflow.com/questions/ask
// @exclude     *://*.superuser.com/questions/ask
// @exclude     *://*.serverfault.com/questions/ask
// @exclude     *://*.askubuntu.com/questions/ask
// @exclude     *://*.stackapps.com/questions/ask
// @exclude     *://*.mathoverflow.net/questions/ask
// @grant       GM_addStyle
// @require     https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @require     https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// ==/UserScript==

/* global $, waitForKeyElements */

GM_addStyle(`
.tiny-signature {
  display: inline-flex;
  flex-direction: row-reverse;
  align-items: center;
  width: 100%;
}
.username {
  height: unset !important;
}
.pronouns {
  color: #777;
  padding-left: 5px;
}
`)

// List of pronouns to look out for
let allPronouns = [
  "him", "his",
  "she", "her?", // that covers 'he' as well
  "they", "them", "their",
  "ze", "hir", "zir",
  "xey", "xem", "xyr"
].join("|");
let pronounListRegex = new RegExp('\\W*((' + allPronouns + ')(\\s*/\\s*(' + allPronouns + '))+)\\W*', 'i');
let myPronounIsRegex = /(https?:\/\/)?(my\.)?pronoun\.is\/[\w/]+/i;
let explicitPronounsRegex = /pronouns:\s*([^.\n)]*)(\.|\n|\)|$)/im;

// Keys:   user IDs
// Values: either a list of DOM elements (specifically, the anchors to chat profiles)
//         or a string with pronouns.
var users = {};

// If we're on a Q&A site, also cache all changes to the `users` object to save on API calls
if (location.hostname.indexOf("chat") === -1) {
  const localStorageData = localStorage.stackPronounAssistant_users;
  const cached = localStorageData ? JSON.parse(localStorage.stackPronounAssistant_users) : {};
  const userData = {};
  Object.keys(cached).forEach(k => {userData[parseInt(k, 10)] = cached[k]});
  users = new Proxy(userData, {
    get: (obj, prop) => obj[prop],
    set: (obj, prop, value) => {
      obj[prop] = value;
      localStorage.stackPronounAssistant_users = JSON.stringify(userData);
    }
  });
}

// Adds pronoun information to a user's 'signature' in chat.
function showPronounsForChat(element, pronouns) {
  if (pronouns == "") {
    return;
  }
  // the element might contain both a tiny and a full signature
  element.find("div.username").each(function (index, usernameElement) {
    usernameElement.innerHTML = '' + usernameElement.innerHTML + '
'
      + '' + pronouns.replace(/(<([^>]+)>)/ig, "") + '';
  });
}

function showPronouns(element, pronouns) {
  if (pronouns == "") {
    return;
  }
  // Make sure the pronouns don't end up between the username and the diamond
  if (element.next("span.mod-flair").length != 0) {
    element = element.next("span.mod-flair");
  }
  element.after($('' + pronouns.replace(/(<([^>]+)>)/ig, "") + ''));
}

// Check the user's 'about' in their chat profile for pronoun indicators
function getPronouns(aboutMe) {
  // Link to Pronoun Island, e.g.
  // http://my.pronoun.is/she
  var match = myPronounIsRegex.exec(aboutMe);
  if (match != null) {
    return match[0];
  }

  // Explicit pronouns specification, e.g.
  // Pronouns: he/him.
  // The end is indicated by a dot, a newline, or simply the end of the text.
  match = explicitPronounsRegex.exec(aboutMe);
  if (match != null) {
    return match[1];
  }

  // Check for pronouns (see above for the list) joined by a forward slash, e.g.
  // she/her
  // (he/him/his)
  // they / them
  match = pronounListRegex.exec(aboutMe);
  if (match != null) {
    return match[1];
  }

  // No pronouns found
  return "";
}

// Chat signatures
waitForKeyElements("a.signature", function(jNode) {
  let userID = jNode.attr("href").split("/users/")[1];
  if (!users[userID]) {
    users[userID] = [];
    users[userID].push(jNode);
    // Read chat profile
    $.get("https://" + location.host + "/users/thumbs/" + userID + "?showUsage=true", function(data) {
      let pronouns = data.user_message == null ? "" : getPronouns(data.user_message);
      users[userID].forEach(function (element) {
        showPronounsForChat(element, pronouns);
      });
      users[userID] = pronouns;
    });
  } else if (typeof users[userID] == 'string') {
    // We already have the pronouns, we can just use them.
    showPronounsForChat(jNode, users[userID]);
  } else {
    // User appearing multiple times, their profile is already being fetched.
    users[userID].push(jNode);
  }
});

// Q&A site user cards & comment usernames
(async () => {
  const sleep = async (ms) => {
    return new Promise(resolve => {
      setTimeout(resolve, ms);
    });
  };

  const userIds = [];
  const profiles = {};

  const $userElements = $("div.user-details > a, a.comment-user");

  // Grab all the user IDs out of a page first. We'll go back over them later to add pronouns in.
  $userElements.each(function() {
    const link = $(this).attr("href");
    if (!link.startsWith("/users/")) {
      // not a user card, but a community wiki post
      return;
    }
    const userId = parseInt(link.split("/users/")[1]);
    if (userIds.indexOf(userId) === -1) {
      userIds.push(userId);
    }
  });

  // Split the list into 100-item pages and grab profiles for each page.
  // This works because splice modifies the userIds array in-place, removing elements from the front and
  // returning them into the `page` variable. When we've used them all, the array will be empty.
  while (userIds.length > 0) {
    const page = userIds.splice(0, 100);

    const resp = await fetch("https://api.stackexchange.com/2.2/users/" + page.join(';') + "?site=" + location.hostname
                             + "&key=L8n*CvRX3ZsedRQicxnjIA((&filter=!23IboywNfWUzv_nydJbn*&pagesize=100");
    const data = await resp.json();
    if (typeof data.items !== 'undefined') {
      data.items.forEach(i => {
        profiles[i.user_id] = i.about_me;
      });
    }

    if (data.backoff) {
      // Respect backoffs, not just pronouns.
      await sleep(data.backoff * 1000);
    }
  }

  $userElements.each(function() {
    const link = $(this).attr("href");
    const userId = parseInt(link.split("/users/")[1]);
    if (!users[userId]) {
      // No pronouns calculated yet, we need to calculate and store them.
      users[userId] = getPronouns(profiles[userId]);
      showPronouns($(this), users[userId]);
    }
    else {
      // We already have the pronouns, we can just use them.
      showPronouns($(this), users[userId]);
    }
  });
})();<|endoftext|>


<commit_before>export { WebGLRenderTarget } from 'three/src/renderers/WebGLRenderTarget.js';
export { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js';
export { ShaderLib } from 'three/src/renderers/shaders/ShaderLib.js';
export { UniformsLib } from 'three/src/renderers/shaders/UniformsLib.js';
export { UniformsUtils } from 'three/src/renderers/shaders/UniformsUtils.js';
export { ShaderChunk } from 'three/src/renderers/shaders/ShaderChunk.js';
export { FogExp2 } from 'three/src/scenes/FogExp2.js';
export { Scene } from 'three/src/scenes/Scene.js';
export { Mesh } from 'three/src/objects/Mesh.js';
export { LineSegments } from 'three/src/objects/LineSegments.js';
export { Line } from 'three/src/objects/Line.js';
export { LineLoop } from 'three/src/objects/LineLoop.js';
export { Points } from 'three/src/objects/Points.js';
export { Group } from 'three/src/objects/Group.js';
export { DataTexture } from 'three/src/textures/DataTexture.js';
export { CanvasTexture } from 'three/src/textures/CanvasTexture.js';
export { Texture } from 'three/src/textures/Texture.js';

export { SphereBufferGeometry } from 'three/src/geometries/SphereGeometry.js';
export { RingBufferGeometry } from 'three/src/geometries/RingGeometry.js';
export { PlaneGeometry, PlaneBufferGeometry } from 'three/src/geometries/PlaneGeometry.js';
export { CylinderBufferGeometry } from 'three/src/geometries/CylinderGeometry.js';

export * from 'three/src/materials/Materials.js';
export { TextureLoader } from 'three/src/loaders/TextureLoader.js';
export { DefaultLoadingManager, LoadingManager } from 'three/src/loaders/LoadingManager.js';
export { ImageLoader } from 'three/src/loaders/ImageLoader.js';
export { FileLoader } from 'three/src/loaders/FileLoader.js';
export { Loader } from 'three/src/loaders/Loader.js';
export { LoaderUtils } from 'three/src/loaders/LoaderUtils.js';
export { Cache } from 'three/src/loaders/Cache.js';
export { HemisphereLight } from 'three/src/lights/HemisphereLight.js';
export { DirectionalLight } from 'three/src/lights/DirectionalLight.js';
export { AmbientLight } from 'three/src/lights/AmbientLight.js';
export { Light } from 'three/src/lights/Light.js';
export { StereoCamera } from 'three/src/cameras/StereoCamera.js';
export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
export { OrthographicCamera } from 'three/src/cameras/OrthographicCamera.js';
export { ArrayCamera } from 'three/src/cameras/ArrayCamera.js';
export { Camera } from 'three/src/cameras/Camera.js';
export { Uniform } from 'three/src/core/Uniform.js';
export { InstancedBufferGeometry } from 'three/src/core/InstancedBufferGeometry.js';
export { BufferGeometry } from 'three/src/core/BufferGeometry.js';
export { InstancedBufferAttribute } from 'three/src/core/InstancedBufferAttribute.js';
export * from 'three/src/core/BufferAttribute.js';
export { Object3D } from 'three/src/core/Object3D.js';
export { Raycaster } from 'three/src/core/Raycaster.js';
export { Layers } from 'three/src/core/Layers.js';
export { EventDispatcher } from 'three/src/core/EventDispatcher.js';
export { Triangle } from 'three/src/math/Triangle.js';
export { _Math as Math } from 'three/src/math/Math.js';
export { Spherical } from 'three/src/math/Spherical.js';
export { Plane } from 'three/src/math/Plane.js';
export { Frustum } from 'three/src/math/Frustum.js';
export { Sphere } from 'three/src/math/Sphere.js';
export { Ray } from 'three/src/math/Ray.js';
export { Matrix4 } from 'three/src/math/Matrix4.js';
export { Matrix3 } from 'three/src/math/Matrix3.js';
export { Box3 } from 'three/src/math/Box3.js';
export { Box2 } from 'three/src/math/Box2.js';
export { Euler } from 'three/src/math/Euler.js';
export { Vector4 } from 'three/src/math/Vector4.js';
export { Vector3 } from 'three/src/math/Vector3.js';
export { Vector2 } from 'three/src/math/Vector2.js';
export { Quaternion } from 'three/src/math/Quaternion.js';
export { Color } from 'three/src/math/Color.js';
export * from 'three/src/constants.js';

import { _Math } from 'three/src/math/Math.js';

_Math.generateUUID = function () { return null; };

import { Object3D } from 'three/src/core/Object3D.js';

Object3D.DefaultUp.set( 0, 0, 1 );

Object3D.prototype.addStatic = function ( obj ) {

	obj.matrixAutoUpdate = false;
	obj.updateMatrix();

	this.add( obj );

};
<commit_msg>add CubeTexture import<commit_after>export { WebGLRenderTarget } from 'three/src/renderers/WebGLRenderTarget.js';
export { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js';
export { ShaderLib } from 'three/src/renderers/shaders/ShaderLib.js';
export { UniformsLib } from 'three/src/renderers/shaders/UniformsLib.js';
export { UniformsUtils } from 'three/src/renderers/shaders/UniformsUtils.js';
export { ShaderChunk } from 'three/src/renderers/shaders/ShaderChunk.js';
export { FogExp2 } from 'three/src/scenes/FogExp2.js';
export { Scene } from 'three/src/scenes/Scene.js';
export { Mesh } from 'three/src/objects/Mesh.js';
export { LineSegments } from 'three/src/objects/LineSegments.js';
export { Line } from 'three/src/objects/Line.js';
export { Points } from 'three/src/objects/Points.js';
export { Group } from 'three/src/objects/Group.js';
export { DataTexture } from 'three/src/textures/DataTexture.js';
export { CubeTexture } from 'three/src/textures/CubeTexture.js';
export { CanvasTexture } from 'three/src/textures/CanvasTexture.js';
export { Texture } from 'three/src/textures/Texture.js';

export { SphereBufferGeometry } from 'three/src/geometries/SphereGeometry.js';
export { RingBufferGeometry } from 'three/src/geometries/RingGeometry.js';
export { PlaneGeometry, PlaneBufferGeometry } from 'three/src/geometries/PlaneGeometry.js';
export { CylinderBufferGeometry } from 'three/src/geometries/CylinderGeometry.js';

export * from 'three/src/materials/Materials.js';
export { TextureLoader } from 'three/src/loaders/TextureLoader.js';
export { DefaultLoadingManager, LoadingManager } from 'three/src/loaders/LoadingManager.js';
export { ImageLoader } from 'three/src/loaders/ImageLoader.js';
export { FileLoader } from 'three/src/loaders/FileLoader.js';
export { Loader } from 'three/src/loaders/Loader.js';
export { LoaderUtils } from 'three/src/loaders/LoaderUtils.js';
export { Cache } from 'three/src/loaders/Cache.js';
export { HemisphereLight } from 'three/src/lights/HemisphereLight.js';
export { DirectionalLight } from 'three/src/lights/DirectionalLight.js';
export { AmbientLight } from 'three/src/lights/AmbientLight.js';
export { Light } from 'three/src/lights/Light.js';
export { StereoCamera } from 'three/src/cameras/StereoCamera.js';
export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
export { OrthographicCamera } from 'three/src/cameras/OrthographicCamera.js';
export { ArrayCamera } from 'three/src/cameras/ArrayCamera.js';
export { Camera } from 'three/src/cameras/Camera.js';
export { Uniform } from 'three/src/core/Uniform.js';
export { InstancedBufferGeometry } from 'three/src/core/InstancedBufferGeometry.js';
export { BufferGeometry } from 'three/src/core/BufferGeometry.js';
export { InstancedBufferAttribute } from 'three/src/core/InstancedBufferAttribute.js';
export * from 'three/src/core/BufferAttribute.js';
export { Object3D } from 'three/src/core/Object3D.js';
export { Raycaster } from 'three/src/core/Raycaster.js';
export { Layers } from 'three/src/core/Layers.js';
export { EventDispatcher } from 'three/src/core/EventDispatcher.js';
export { Triangle } from 'three/src/math/Triangle.js';
export { _Math as Math } from 'three/src/math/Math.js';
export { Spherical } from 'three/src/math/Spherical.js';
export { Plane } from 'three/src/math/Plane.js';
export { Frustum } from 'three/src/math/Frustum.js';
export { Sphere } from 'three/src/math/Sphere.js';
export { Ray } from 'three/src/math/Ray.js';
export { Matrix4 } from 'three/src/math/Matrix4.js';
export { Matrix3 } from 'three/src/math/Matrix3.js';
export { Box3 } from 'three/src/math/Box3.js';
export { Box2 } from 'three/src/math/Box2.js';
export { Euler } from 'three/src/math/Euler.js';
export { Vector4 } from 'three/src/math/Vector4.js';
export { Vector3 } from 'three/src/math/Vector3.js';
export { Vector2 } from 'three/src/math/Vector2.js';
export { Quaternion } from 'three/src/math/Quaternion.js';
export { Color } from 'three/src/math/Color.js';
export * from 'three/src/constants.js';

import { _Math } from 'three/src/math/Math.js';

_Math.generateUUID = function () { return null; };

import { Object3D } from 'three/src/core/Object3D.js';

Object3D.DefaultUp.set( 0, 0, 1 );

Object3D.prototype.addStatic = function ( obj ) {

	obj.matrixAutoUpdate = false;
	obj.updateMatrix();

	this.add( obj );

};
<|endoftext|>


<commit_before>//
// 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
//
//     https://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.
//
// ** This file is automatically generated by gapic-generator-typescript. **
// ** https://github.com/googleapis/gapic-generator-typescript **
// ** All changes to this file may be overwritten. **

'use strict';

const path = require('path');
const {assert} = require('chai');
const cp = require('child_process');
const {describe, it} = require('mocha');

const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});

const cwd = path.join(__dirname, '..');

describe('Quickstart', async () => {
  it('should run quickstart', async () => {
    try {
      execSync('node quickstart.js', {cwd});
    } catch (err) {
      // Since we don't have credentials, we need to assert this eror
      assert.match(err, /insufficient authentication scopes/);
    }
  });
});
<commit_msg>Update quickstart.test.js<commit_after>//
// 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
//
//     https://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.
//
// ** This file is automatically generated by gapic-generator-typescript. **
// ** https://github.com/googleapis/gapic-generator-typescript **
// ** All changes to this file may be overwritten. **

'use strict';

const path = require('path');
const {assert} = require('chai');
const cp = require('child_process');
const {describe, it} = require('mocha');

const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});

const cwd = path.join(__dirname, '..');

describe.skip('Quickstart', async () => {
  it('should run quickstart', async () => {
    try {
      execSync('node quickstart.js', {cwd});
    } catch (err) {
      // Since we don't have credentials, we need to assert this eror
      assert.match(err, /insufficient authentication scopes/);
    }
  });
});
<|endoftext|>


<commit_before>'use strict';

var $ = require('./jqueryBacon').$,
    _ = require('lodash'),
    path = require('path'),
    Bacon = require('baconjs'),
    zoneUtils = require('./zoneUtils'),
    zoneTemplate = require('../templates/zone.ejs'),
    audioPlayerTemplate = require('../templates/audioPlayer.ejs');

var deckFinishedBus = new Bacon.Bus(),
    showIntroCard = true;

function init() {
    var cardHolder = $('#card-holder');

    cardHolder.asEventStream('change', 'input[name="quest"]')
            .onValue(enableStartQuest);

    // Allow tapping the image or caption to toggle said caption open or closed.
    cardHolder.on('click', '.card .card-visual', toggleCardContent);
    cardHolder.on('click', '.card .card-content.slider', toggleCardContent);

    // Allow swipe events to move through the card stack.
    cardHolder.on('swipeRight', swipeNavigateCards);
    cardHolder.on('swipeLeft', swipeNavigateCards);
    cardHolder.on('click', '.nextslide', function() {
        cardHolder.trigger('swipeLeft');
    });
    cardHolder.on('click', '.poster', handleVideoTap);
}

function openZoneDeck(zone, activeQuest) {
    var directory = path.join('quests', activeQuest, zone.id),
        context = {
            quest: activeQuest,
            primaryPath: directory + '/primary/',
            secondaryPath: directory + '/secondary/',
            mediaPath: directory + '/media/',
            zone: zone,
            showIntroCard: showIntroCard
        };

    context.audioPlayer = audioPlayerTemplate(context);
    var html = zoneTemplate(context);
    addDeckToPage(html);

    $('#finish-zone').on('click', finishZone);

    deckFinishedBus.push(zone.id);
}

function addDeckToPage(html) {
    $('#card-holder')
        .html(html)
        .find('.overlay')
        .first()
        .fadeIn(400);

        // Now that our card holder has a deck in it prepare audio.
        setUpAudio();

        handleIntroCard();
}

function handleIntroCard() {
    if (showIntroCard) {
        var $introCard = $('#card-holder').find('.card.introcard');
        $introCard.find('button.introbutton').on('click', function() {
            $introCard.fadeOut(200, function() {
                $introCard.remove();
            });

            // We only want to show the intro instruction card on the first
            // zone opened. After that set to false and never show it again.
            // But the user must first click the button to surpress the
            // popup again.
            showIntroCard = false;
        });
    }
}

function setUpAudio() {
    var $audioPlayer = $('#card-holder').find('.card-header'),
        $audioButton = $audioPlayer.find('.audio-control'),
        $audioEl = $('#card-holder').find('audio'),
        sound = $audioEl.get(0),
        playingClass = 'playing';

    // Reset on sound completion.
    $audioEl.on('ended', function() {
        $audioButton.removeClass(playingClass).text('Play Again');
    });

    // Single button audio player.
    $audioButton.on('click', function() {
        if ($(this).hasClass(playingClass)) {
            sound.pause();
            $(this).removeClass(playingClass).text('Play Audio');
        } else {
            sound.play();
            $(this).addClass(playingClass).text('Pause Audio');
        }
    });

    // Audio player can close the deck.
    $audioPlayer.on('click', '.close-deck', function() {
        // Though not a card, passing the player div to the closeDeck function
        // is fine since the card is only used to find the overlay container
        // and hide it. This works just as well for the player div.
        closeDeck($audioPlayer);
    });
}

function closeDeck($card) {
    try {
        // Attempt to stop any sound that is playing before we close.
        $('#card-holder').find('audio').get(0).pause();

        // Null out the audio source to prevent further download.
        $('#card-holder').find('audio source').attr('src', null);

        // Chrome has a weird issue with audio loading resources dynamically.
        // It will just hang forever and queue up new ones that will be listed
        // as "pending" in the network forever. Calling window.stop() kills all
        // the open connections.
        // https://github.com/videojs/video.js/issues/455#issuecomment-122403204
        // https://stackoverflow.com/questions/16137381
        if (window.stop) {
            window.stop();
        }
    } catch (exc) {
        // Expecting: TypeError "Cannot read property 'pause' of undefined"
        if (exc.name !== 'TypeError') {
            throw exc;
        }
    } finally {
        $card.closest('.overlay')
            .fadeOut(400);
    }
}

function enableStartQuest(isDisabled) {
    $('#card-holder .card a[data-start-quest]')
        .removeClass('link-disabled');
}

function finishZone(e) {
    var $activeCard = $(e.currentTarget).closest('.card.active');

    closeDeck($activeCard);
}

function swipeNavigateCards(e) {
    if (showIntroCard) {
        // If the intro card is still visible, cancel out of swipe events.
        return;
    }

    var $target = $(e.currentTarget),
        type = e.type,
        $thisCard = $target.find('.card.active'),
        $video = $target.find('video');

    // On android the video will play after leaving the card so we stop it
    // manually.
    if ($video.length > 0) {
        $video.get(0).pause();
    }

    // In at least one case (the initial screen) the card opens without an
    // active class so we need to find it another way.
    if ($thisCard.length === 0) {
        $thisCard = $target.find('.card').first();
    }

    // Proxy the swipe events to the next and back/close buttons since they have
    // all the logic wired up already.
    if (type === 'swipeLeft') {
        // If there is another card in the stack, move to it.
        if ($thisCard.next().hasClass('card')) {
            $thisCard
                .addClass('prev')
                .removeClass('active')
                .next()
                .addClass('active')
                .removeClass('next');

            if ($thisCard.hasClass('first')) {
                // Remove the alignment message in the header as we move away.
                $target.find('.card-header .alignment-message').fadeOut(200);

                // Attempt to start the audio if it exists.
                try {
                    $target.find('audio').get(0).play();
                } catch (exc) {
                    // Expecting: TypeError "Cannot read property 'play' of undefined"
                    if (exc.name !== 'TypeError') {
                        throw exc;
                    }
                }
            }
        } // No more cards? We are on the exit card, which has a close button.
    } else if (type === 'swipeRight') {
        if ($thisCard.prev().hasClass('card')){
            $thisCard
                .addClass('next')
                .removeClass('active')
                .prev()
                .addClass('active')
                .removeClass('prev');

            if ($thisCard.prev().hasClass('first')) {
                // Remove the alignment message in the header as we move away.
                $target.find('.card-header .alignment-message').fadeIn(200);
            }
        } // If no more cards before this one, do nothing.
    }
}

function handleVideoTap(e) {
    var $poster = $(e.currentTarget),
        $video = $poster.closest('.flex').find('video');

    $poster.hide();
    $video.show();
    $video.get(0).play();

    $video.on('pause', function() {
        $poster.show();
        $video.hide();
    });

    $video.on('ended', function() {
        $poster.show();
        $video.hide();
    });
}

function toggleCardContent(e) {
    // Not the most beautiful but a workable solution. If the tap came from a
    // video, ignore it and move on.
    if (e.target.tagName === 'VIDEO') { return; }

    // Find all current captions and open them.
    var $captions = $('#card-holder .card').find('.slider');
    $captions.each(function() {
        var $caption = $(this);
        var animationSpeed = 200; // ms
        // Toggle the element to slide off the bottom of the frame.
        // Find the height of the item and set the bottom position to the
        // negative value. This effectivly positions it just below the frame.
        // Not truly hidden.
        if ($caption.hasClass('caption-hidden')) {
            $caption.removeClass('caption-hidden');
            $caption.animate({
                bottom: '0'
            }, animationSpeed);
        } else {
            var offset = $caption.height() * -1;
            $caption.addClass('caption-hidden');
            $caption.animate({
                bottom: offset + 'px'
            }, animationSpeed);
        }
    });
}

module.exports = {
    init: init,
    deckFinishedStream: deckFinishedBus.map(_.identity),
    openZoneDeck: openZoneDeck
};
<commit_msg>Adjust audio playing logic.<commit_after>'use strict';

var $ = require('./jqueryBacon').$,
    _ = require('lodash'),
    path = require('path'),
    Bacon = require('baconjs'),
    zoneUtils = require('./zoneUtils'),
    zoneTemplate = require('../templates/zone.ejs'),
    audioPlayerTemplate = require('../templates/audioPlayer.ejs');

var deckFinishedBus = new Bacon.Bus(),
    showIntroCard = true;

function init() {
    var cardHolder = $('#card-holder');

    cardHolder.asEventStream('change', 'input[name="quest"]')
            .onValue(enableStartQuest);

    // Allow tapping the image or caption to toggle said caption open or closed.
    cardHolder.on('click', '.card .card-visual', toggleCardContent);
    cardHolder.on('click', '.card .card-content.slider', toggleCardContent);

    // Allow swipe events to move through the card stack.
    cardHolder.on('swipeRight', swipeNavigateCards);
    cardHolder.on('swipeLeft', swipeNavigateCards);
    cardHolder.on('click', '.nextslide', function() {
        cardHolder.trigger('swipeLeft');
    });
    cardHolder.on('click', '.poster', handleVideoTap);
}

function openZoneDeck(zone, activeQuest) {
    var directory = path.join('quests', activeQuest, zone.id),
        context = {
            quest: activeQuest,
            primaryPath: directory + '/primary/',
            secondaryPath: directory + '/secondary/',
            mediaPath: directory + '/media/',
            zone: zone,
            showIntroCard: showIntroCard
        };

    context.audioPlayer = audioPlayerTemplate(context);
    var html = zoneTemplate(context);
    addDeckToPage(html);

    $('#finish-zone').on('click', finishZone);

    deckFinishedBus.push(zone.id);
}

function addDeckToPage(html) {
    $('#card-holder')
        .html(html)
        .find('.overlay')
        .first()
        .fadeIn(400);

        // Now that our card holder has a deck in it prepare audio.
        setUpAudio();

        handleIntroCard();
}

function handleIntroCard() {
    if (showIntroCard) {
        var $introCard = $('#card-holder').find('.card.introcard');
        $introCard.find('button.introbutton').on('click', function() {
            $introCard.fadeOut(200, function() {
                $introCard.remove();
            });

            // We only want to show the intro instruction card on the first
            // zone opened. After that set to false and never show it again.
            // But the user must first click the button to surpress the
            // popup again.
            showIntroCard = false;
        });
    }
}

function setUpAudio() {
    var $audioPlayer = $('#card-holder').find('.card-header'),
        $audioButton = $audioPlayer.find('.audio-control'),
        $audioEl = $('#card-holder').find('audio'),
        sound = $audioEl.get(0),
        playingClass = 'playing',
        playMessage = 'Play Audio',
        pauseMessage = 'Pause Audio',
        replayMessage = 'Play Again';

    // Update UI on audio events.
    $audioEl.on('ended', function() {
        $audioButton.removeClass(playingClass).text(replayMessage);
    });
    $audioEl.on('playing', function() {
        $audioButton.addClass(playingClass).text(pauseMessage);
    });
    $audioEl.on('pause', function() {
        $audioButton.removeClass(playingClass).text(playMessage);
    });

    // Single button audio player.
    $audioButton.on('click', function() {
        if ($(this).hasClass(playingClass)) {
            sound.pause();
        } else {
            sound.play();
        }
    });

    // Audio player can close the deck.
    $audioPlayer.on('click', '.close-deck', function() {
        // Though not a card, passing the player div to the closeDeck function
        // is fine since the card is only used to find the overlay container
        // and hide it. This works just as well for the player div.
        closeDeck($audioPlayer);
    });
}

function closeDeck($card) {
    try {
        // Attempt to stop any sound that is playing before we close.
        $('#card-holder').find('audio').get(0).pause();

        // Null out the audio source to prevent further download.
        $('#card-holder').find('audio source').attr('src', null);

        // Chrome has a weird issue with audio loading resources dynamically.
        // It will just hang forever and queue up new ones that will be listed
        // as "pending" in the network forever. Calling window.stop() kills all
        // the open connections.
        // https://github.com/videojs/video.js/issues/455#issuecomment-122403204
        // https://stackoverflow.com/questions/16137381
        if (window.stop) {
            window.stop();
        }
    } catch (exc) {
        // Expecting: TypeError "Cannot read property 'pause' of undefined"
        if (exc.name !== 'TypeError') {
            throw exc;
        }
    } finally {
        $card.closest('.overlay')
            .fadeOut(400);
    }
}

function enableStartQuest(isDisabled) {
    $('#card-holder .card a[data-start-quest]')
        .removeClass('link-disabled');
}

function finishZone(e) {
    var $activeCard = $(e.currentTarget).closest('.card.active');

    closeDeck($activeCard);
}

function swipeNavigateCards(e) {
    if (showIntroCard) {
        // If the intro card is still visible, cancel out of swipe events.
        return;
    }

    var $target = $(e.currentTarget),
        type = e.type,
        $thisCard = $target.find('.card.active'),
        $video = $target.find('video');

    // On android the video will play after leaving the card so we stop it
    // manually.
    if ($video.length > 0) {
        $video.get(0).pause();
    }

    // In at least one case (the initial screen) the card opens without an
    // active class so we need to find it another way.
    if ($thisCard.length === 0) {
        $thisCard = $target.find('.card').first();
    }

    // Proxy the swipe events to the next and back/close buttons since they have
    // all the logic wired up already.
    if (type === 'swipeLeft') {
        // If there is another card in the stack, move to it.
        if ($thisCard.next().hasClass('card')) {
            $thisCard
                .addClass('prev')
                .removeClass('active')
                .next()
                .addClass('active')
                .removeClass('next');

            if ($thisCard.hasClass('first')) {
                // Remove the alignment message in the header as we move away.
                $target.find('.card-header .alignment-message').fadeOut(200);

                // Attempt to start the audio if it exists and the
                // circumstances are correct.
                try {
                    // Only play unplayed audio. Determine this by looking at
                    // the current time and the duration of the audio clip. If
                    // they are both zero or undefined, then it is safe to
                    // assume that the audio has never been played.
                    var sound = $target.find('audio').get(0);

                    if (!sound.currentTime && !sound.duration) {
                        sound.play();
                    }
                } catch (exc) {
                    // Expecting: TypeError "Cannot read property ... of undefined"
                    if (exc.name !== 'TypeError') {
                        throw exc;
                    }
                }
            }
        } // No more cards? We are on the exit card, which has a close button.
    } else if (type === 'swipeRight') {
        if ($thisCard.prev().hasClass('card')){
            $thisCard
                .addClass('next')
                .removeClass('active')
                .prev()
                .addClass('active')
                .removeClass('prev');

            if ($thisCard.prev().hasClass('first')) {
                // Remove the alignment message in the header as we move away.
                $target.find('.card-header .alignment-message').fadeIn(200);
            }
        } // If no more cards before this one, do nothing.
    }
}

function handleVideoTap(e) {
    var $poster = $(e.currentTarget),
        $video = $poster.closest('.flex').find('video');

    $poster.hide();
    $video.show();
    $video.get(0).play();

    $video.on('pause', function() {
        $poster.show();
        $video.hide();
    });

    $video.on('ended', function() {
        $poster.show();
        $video.hide();
    });
}

function toggleCardContent(e) {
    // Not the most beautiful but a workable solution. If the tap came from a
    // video, ignore it and move on.
    if (e.target.tagName === 'VIDEO') { return; }

    // Find all current captions and open them.
    var $captions = $('#card-holder .card').find('.slider');
    $captions.each(function() {
        var $caption = $(this);
        var animationSpeed = 200; // ms
        // Toggle the element to slide off the bottom of the frame.
        // Find the height of the item and set the bottom position to the
        // negative value. This effectivly positions it just below the frame.
        // Not truly hidden.
        if ($caption.hasClass('caption-hidden')) {
            $caption.removeClass('caption-hidden');
            $caption.animate({
                bottom: '0'
            }, animationSpeed);
        } else {
            var offset = $caption.height() * -1;
            $caption.addClass('caption-hidden');
            $caption.animate({
                bottom: offset + 'px'
            }, animationSpeed);
        }
    });
}

module.exports = {
    init: init,
    deckFinishedStream: deckFinishedBus.map(_.identity),
    openZoneDeck: openZoneDeck
};
<|endoftext|>


<commit_before>/*
 * Copyright [1999-2016] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
 *
 * 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.
 */

Ensembl.Panel.ThousandGenomeForm = Ensembl.Panel.ToolsForm.extend({

  init: function() {
    var panel = this;

    this.base.apply(this, arguments);

    this.elLk.speciesDropdown = this.elLk.form.find('._sdd');
    this.elLk.collection      = this.elLk.form.find('select[name=collection_format]');
    this.elLk.region          = this.elLk.form.find('input[name=region]');
    this.elLk.sample_url      = this.elLk.form.find('input[name=custom_sample_url]');
    this.elLk.file_url        = this.elLk.form.find('input[name=custom_file_url]');
    this.readSampleFile       = this.params['read_sample_file'];
    this.fileRestURL          = this.params['genome_file_rest_url'];

    //this.resetSpecies(this.defaultSpecies);
    this.editExisting();

    panel.elLk.region.change(function () {
      var collection_value = panel.elLk.collection.val();
      var r = panel.elLk.region.val().match(/^([^:]+):\s?([0-9\,]+)(-|_|\.\.)([0-9\,]+)$/);

      if (!r || r.length !== 5 || r[4] - r[2] < 0) {
        panel.showError('Please enter a valid region for e.g: 1:1-50000', 'Invalid Region');
        $(panel.elLk.form).data('valid', false);
        return;
      }

      if(((parseFloat(r[4].replace(/,/gi,"")) - parseFloat(r[2].replace(/,/gi,""))) + 1) >= 100000000) {
        panel.elLk.region.parent().find('label.invalid').remove(); //remove the warning its already there before appending
        panel.elLk.region.parent().append('Please note that with this size of genomic region, the job may take a long time (> 6h) to run');
      } else {
        panel.elLk.region.parent().find('label.invalid').remove(); //just a precaution in case someone change the region again
      }

      //getting the file url from 1KG rest if user input region and data collection is either phase1 or phase3
      if(collection_value != 'custom') {
        panel.getFileURL(r[1],collection_value);
      }

      //show sample population file url based on data collection selection (we have a specific file for human chrY)
      if(panel.elLk.region.val().match(/y:/gi) && collection_value === 'phase3') {
        panel.updatePopulation("","_stt_phase3_male");
        panel.elLk.form.find('[class^="_sample_url_"]').hide();
        panel.elLk.form.find('span._sample_url_phase3_male').show();
      } else {
        panel.elLk.form.find('span._stt_phase3_male').hide();
        if(collection_value != 'custom') {
console.log(collection_value);
          panel.elLk.form.find('span._stt_'+collection_value).show();
          panel.elLk.form.find('span._sample_url_phase3_male').hide();
        }
      }
    });

    panel.elLk.collection.change(function () {
      var r = panel.elLk.region.val().match(/^([^:]+):\s?([0-9\,]+)(-|_|\.\.)([0-9\,]+)$/);
      if(panel.elLk.collection.val() != 'custom') {
        panel.elLk.form.find('div.custom_population').hide();
      }

      if(panel.elLk.collection.val() === 'custom' && panel.elLk.sample_url.val()) {
        panel.elLk.form.find('div.custom_population').show();
      }

      if(panel.elLk.collection.val() != 'custom' && panel.elLk.region.val()) {
        panel.getFileURL(r[1],panel.elLk.collection.val());
      }

//      if(panel.elLk.speciesDropdown.find('input[name=species]:checked').val() === "Homo_sapiens") { //commenting this out for now as we only have human as species
      if(panel.elLk.collection.val() === 'phase3' && panel.elLk.region.val().match(/y:/gi)) {
        panel.updatePopulation("","_stt_phase3_male");
        panel.elLk.form.find('[class^="_sample_url_"]').hide();
        panel.elLk.form.find('span._sample_url_phase3_male').show();
      } else {
        panel.elLk.form.find('div._stt_phase3_male').hide();
        panel.elLk.form.find('span._sample_url_phase3_male').hide();
      }
//      }
    });

    panel.elLk.sample_url.change(function () {
      var el = $(this);
      //validating for empty value before updating population url
      if (!panel.elLk.sample_url.val()) {
        panel.showError('Please provide a sample population URL', 'No sample population URL');
        $(panel.elLk.form).data('valid', false);
        return;
      }

      el.parents('form').validate(); //trigger the generic validate here because of the delay in 00_jquery_validate.js which was causing other event to happen before validation

      if(!el.data('valid')) {
        panel.elLk.form.find('div.custom_population select').html(''); //precautionary measure in case a user entered a valid sample url first and then reenter a not valid one
        panel.elLk.form.find('div.population').hide();
      } else {
        panel.updatePopulation(panel.elLk.sample_url.val().replace(/^\s+|\s+$/g, ''),"custom_populations");
      }
    });

    // Add validate event to the form which gets triggered before submitting it
    this.elLk.form.on('validate', function(e) {
      if (!panel.elLk.region.val()) {
        panel.showError('Please enter a region', 'No region entered');
        $(this).data('valid', false);
        return;
      }

      if(panel.elLk.collection.val() === "custom") {
        if (!panel.elLk.file_url.val()) {
          panel.showError('Please provide a file URL', 'No file URL');
          $(this).data('valid', false);
          return;
        }

        if (!panel.elLk.sample_url.val()) {
          panel.showError('Please provide a sample population URL', 'No sample population URL');
          $(this).data('valid', false);
          return;
        }
      }
    });
  },

  getFileURL: function(region, collection) {
    this.base.apply(this, arguments);
    var panel = this;
    var url;

    region = "chr"+region+"\\.";
    collection = "1000 Genomes phase "+collection.replace("phase","")+" release";

    $.ajax({
      'type'    : "POST",
      'url'     : panel.fileRestURL,
      'data'    : JSON.stringify({'query':{'constant_score':{'filter':{'bool':{'must':[{'term':{'dataCollections':collection}},{'term':{'dataType':'variants'}}]}}}}, 'size': '100'}), //need to remove the size once returning all is supported by the rest
      'beforeSend' : function() { panel.toggleSpinner(true); },
      'success' : function(data) {
        if(!data.hits || !data.hits.total) {
          panel.elLk.form.find('span._span_url').html('Genotype file URL: There was an error in retrieving the file URL, please report the issue to helpdesk@ensembl.org');
          panel.elLk.form.find('input[name=generated_file_url]').val("");
        } else {
          $.each (data.hits.hits, function (index,el) {
            if(el._source.url && !el._source.url.match(/tbi$/gi) && el._source.url.match(new RegExp(region, 'i'))) {
              url = el._source.url;
            }
          });
          panel.elLk.form.find('span._span_url').html("Genotype file URL: "+url);
          panel.elLk.form.find('input[name=generated_file_url]').val(url);
        }
      },
      'complete' :  function () { panel.toggleSpinner(false); },
      'error'     : function () {
        panel.toggleSpinner(false);
        panel.elLk.form.find('span._span_url').html('Genotype file URL: There was an error in retrieving the file URL, please report the issue to helpdesk@ensembl.org');
        panel.elLk.form.find('input[name=generated_file_url]').val("");
      }
    });
  },

  populateForm: function(jobsData) {
    if (jobsData && jobsData.length) {
      this.base(jobsData);
      //this.resetSpecies(jobsData[0]['species']);
      var upload_type = jobsData[0].upload_type;

      if(jobsData[0].job_desc) {
        this.elLk.form.find('input[name=name]').val(jobsData[0].job_desc);
      }

      if(jobsData[0].region) {
        var r = jobsData[0].region.match(/^([^:]+):\s?([0-9\,]+)(-|_|\.\.)([0-9\,]+)$/);

        if(((parseFloat(r[4].replace(/,/gi,"")) - parseFloat(r[2].replace(/,/gi,""))) + 1) >= 100000) {
          this.elLk.form.find('input[name=region]').parent().find('label.invalid').remove();
          this.elLk.form.find('input[name=region]').parent().append('Please note that with this size of genomic region, the job may take a long time (> 6h) to run');
        } else {
          this.elLk.form.find('input[name=region]').parent().find('label.invalid').remove(); //just a precaution in case someone change the region again
        }
      }

      if (upload_type === 'custom') {
        this.elLk.form.find('select[name=collection_format] option').removeAttr("selected");
        this.elLk.form.find('select[name=collection_format]').find('option[value=custom]').prop('selected', true).end().selectToToggle('trigger');
        this.elLk.form.find('input[name=custom_file_url]').val(jobsData[0].file_url);
        this.elLk.form.find('input[name=custom_sample_url]').val(jobsData[0].sample_panel);
        this.updatePopulation(jobsData[0].sample_panel,"custom_population", jobsData[0].population); //show population listbox
      } else {
        var population = this.elLk.form.find('input[name=region]').val().match(/y:/gi) && upload_type === "phase3" ? "phase3_male" : upload_type;
        this.elLk.form.find('select[name=collection_format] option').removeAttr("selected");
        this.elLk.form.find('select[name=collection_format]').find('option[value=' + upload_type + ']').prop('selected', true).end().selectToToggle('trigger');
        this.elLk.form.find('span._span_url').html("Genotype file URL: " + jobsData[0].file_url);
        this.elLk.form.find('input[name=generated_file_url]').val(jobsData[0].file_url);
        this.elLk.form.find('[class^="_sample_url_"]').hide(); //just a sanity check to hide everything first so that nothing is shown by mistake
        this.elLk.form.find('span._sample_url_'+population).show();
        this.updatePopulation("","_stt_"+population,jobsData[0].population);
      }
    }
  },

  reset: function() {
    this.base.apply(this, arguments);

    this.elLk.region.parent().find('label.invalid').remove();
    this.elLk.form.find('div.population').hide();
    this.elLk.form.find('select[name=collection_format]').find('option[value=phase3]').prop('selected', true).end().selectToToggle('trigger');
	this.elLk.form.find('span._span_url').html('Genotype file URL: ').show();
	this.elLk.form.find('input[name=generated_file_url]').val("");
  },

  updatePopulation: function(panel_url, panel_name, selected_value) {
  //create population listbox from panel file url or show hidden population listbox
    this.base.apply(this, arguments);
    var panel = this;

    if(!panel_url) {
      this.elLk.form.find('div.population').hide();
      this.elLk.form.find('div.'+panel_name).show();
      if(selected_value) {
        var population_listbox = panel_name.replace("_stt_","") + "_populations";
        this.elLk.form.find('select[name=' + population_listbox + '] option').removeAttr("selected");
        this.elLk.form.find('select[name=' + population_listbox + ']').find('option[value=' + selected_value + ']').prop('selected', true).end();
      }
    } else {
      panel.ajax({
        'comet'   : true,
        'type'    : 'POST',
        'url'     : panel.readSampleFile,
        'data'    : { population_url: panel_url },
        'spinner' : true,
        'success' : function(json) {
          var listbox  ="";
          var selected = "";
          if(json.error) {
            panel.showError('The sample population url is either invalid or not reachable', 'Invalid sample population URL');
            $(panel.elLk.form).data('valid', false);
            panel.ajax.spinner = 'false';
          } else {
            $.each (json.populations, function (index,el) {
              if(el.value) {
                if(el.value.match(/sample/gi)) { next; } //skip if  there is a header
                selected = selected_value && selected_value === el.value ? 'selected="selected"' : '';
                listbox += '<option value="' + el.value + '"' + selected +'>' + el.caption + '</option>';
              }
            });
            panel.elLk.form.find('div.custom_population').show();
            panel.elLk.form.find('div.custom_population select').html('').append(listbox);
          }
        }
      });
    }
  }
});
<commit_msg>ENSWEb-2594: allele frequency, change limit to 100meg for warning<commit_after>/*
 * Copyright [1999-2016] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
 *
 * 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.
 */

Ensembl.Panel.ThousandGenomeForm = Ensembl.Panel.ToolsForm.extend({

  init: function() {
    var panel = this;

    this.base.apply(this, arguments);

    this.elLk.speciesDropdown = this.elLk.form.find('._sdd');
    this.elLk.collection      = this.elLk.form.find('select[name=collection_format]');
    this.elLk.region          = this.elLk.form.find('input[name=region]');
    this.elLk.sample_url      = this.elLk.form.find('input[name=custom_sample_url]');
    this.elLk.file_url        = this.elLk.form.find('input[name=custom_file_url]');
    this.readSampleFile       = this.params['read_sample_file'];
    this.fileRestURL          = this.params['genome_file_rest_url'];

    //this.resetSpecies(this.defaultSpecies);
    this.editExisting();

    panel.elLk.region.change(function () {
      var collection_value = panel.elLk.collection.val();
      var r = panel.elLk.region.val().match(/^([^:]+):\s?([0-9\,]+)(-|_|\.\.)([0-9\,]+)$/);

      if (!r || r.length !== 5 || r[4] - r[2] < 0) {
        panel.showError('Please enter a valid region for e.g: 1:1-50000', 'Invalid Region');
        $(panel.elLk.form).data('valid', false);
        return;
      }

      if(((parseFloat(r[4].replace(/,/gi,"")) - parseFloat(r[2].replace(/,/gi,""))) + 1) >= 100000000) {
        panel.elLk.region.parent().find('label.invalid').remove(); //remove the warning its already there before appending
        panel.elLk.region.parent().append('Please note that with this size of genomic region, the job may take a long time (> 6h) to run');
      } else {
        panel.elLk.region.parent().find('label.invalid').remove(); //just a precaution in case someone change the region again
      }

      //getting the file url from 1KG rest if user input region and data collection is either phase1 or phase3
      if(collection_value != 'custom') {
        panel.getFileURL(r[1],collection_value);
      }

      //show sample population file url based on data collection selection (we have a specific file for human chrY)
      if(panel.elLk.region.val().match(/y:/gi) && collection_value === 'phase3') {
        panel.updatePopulation("","_stt_phase3_male");
        panel.elLk.form.find('[class^="_sample_url_"]').hide();
        panel.elLk.form.find('span._sample_url_phase3_male').show();
      } else {
        panel.elLk.form.find('span._stt_phase3_male').hide();
        if(collection_value != 'custom') {
console.log(collection_value);
          panel.elLk.form.find('span._stt_'+collection_value).show();
          panel.elLk.form.find('span._sample_url_phase3_male').hide();
        }
      }
    });

    panel.elLk.collection.change(function () {
      var r = panel.elLk.region.val().match(/^([^:]+):\s?([0-9\,]+)(-|_|\.\.)([0-9\,]+)$/);
      if(panel.elLk.collection.val() != 'custom') {
        panel.elLk.form.find('div.custom_population').hide();
      }

      if(panel.elLk.collection.val() === 'custom' && panel.elLk.sample_url.val()) {
        panel.elLk.form.find('div.custom_population').show();
      }

      if(panel.elLk.collection.val() != 'custom' && panel.elLk.region.val()) {
        panel.getFileURL(r[1],panel.elLk.collection.val());
      }

//      if(panel.elLk.speciesDropdown.find('input[name=species]:checked').val() === "Homo_sapiens") { //commenting this out for now as we only have human as species
      if(panel.elLk.collection.val() === 'phase3' && panel.elLk.region.val().match(/y:/gi)) {
        panel.updatePopulation("","_stt_phase3_male");
        panel.elLk.form.find('[class^="_sample_url_"]').hide();
        panel.elLk.form.find('span._sample_url_phase3_male').show();
      } else {
        panel.elLk.form.find('div._stt_phase3_male').hide();
        panel.elLk.form.find('span._sample_url_phase3_male').hide();
      }
//      }
    });

    panel.elLk.sample_url.change(function () {
      var el = $(this);
      //validating for empty value before updating population url
      if (!panel.elLk.sample_url.val()) {
        panel.showError('Please provide a sample population URL', 'No sample population URL');
        $(panel.elLk.form).data('valid', false);
        return;
      }

      el.parents('form').validate(); //trigger the generic validate here because of the delay in 00_jquery_validate.js which was causing other event to happen before validation

      if(!el.data('valid')) {
        panel.elLk.form.find('div.custom_population select').html(''); //precautionary measure in case a user entered a valid sample url first and then reenter a not valid one
        panel.elLk.form.find('div.population').hide();
      } else {
        panel.updatePopulation(panel.elLk.sample_url.val().replace(/^\s+|\s+$/g, ''),"custom_populations");
      }
    });

    // Add validate event to the form which gets triggered before submitting it
    this.elLk.form.on('validate', function(e) {
      if (!panel.elLk.region.val()) {
        panel.showError('Please enter a region', 'No region entered');
        $(this).data('valid', false);
        return;
      }

      if(panel.elLk.collection.val() === "custom") {
        if (!panel.elLk.file_url.val()) {
          panel.showError('Please provide a file URL', 'No file URL');
          $(this).data('valid', false);
          return;
        }

        if (!panel.elLk.sample_url.val()) {
          panel.showError('Please provide a sample population URL', 'No sample population URL');
          $(this).data('valid', false);
          return;
        }
      }
    });
  },

  getFileURL: function(region, collection) {
    this.base.apply(this, arguments);
    var panel = this;
    var url;

    region = "chr"+region+"\\.";
    collection = "1000 Genomes phase "+collection.replace("phase","")+" release";

    $.ajax({
      'type'    : "POST",
      'url'     : panel.fileRestURL,
      'data'    : JSON.stringify({'query':{'constant_score':{'filter':{'bool':{'must':[{'term':{'dataCollections':collection}},{'term':{'dataType':'variants'}}]}}}}, 'size': '100'}), //need to remove the size once returning all is supported by the rest
      'beforeSend' : function() { panel.toggleSpinner(true); },
      'success' : function(data) {
        if(!data.hits || !data.hits.total) {
          panel.elLk.form.find('span._span_url').html('Genotype file URL: There was an error in retrieving the file URL, please report the issue to helpdesk@ensembl.org');
          panel.elLk.form.find('input[name=generated_file_url]').val("");
        } else {
          $.each (data.hits.hits, function (index,el) {
            if(el._source.url && !el._source.url.match(/tbi$/gi) && el._source.url.match(new RegExp(region, 'i'))) {
              url = el._source.url;
            }
          });
          panel.elLk.form.find('span._span_url').html("Genotype file URL: "+url);
          panel.elLk.form.find('input[name=generated_file_url]').val(url);
        }
      },
      'complete' :  function () { panel.toggleSpinner(false); },
      'error'     : function () {
        panel.toggleSpinner(false);
        panel.elLk.form.find('span._span_url').html('Genotype file URL: There was an error in retrieving the file URL, please report the issue to helpdesk@ensembl.org');
        panel.elLk.form.find('input[name=generated_file_url]').val("");
      }
    });
  },

  populateForm: function(jobsData) {
    if (jobsData && jobsData.length) {
      this.base(jobsData);
      //this.resetSpecies(jobsData[0]['species']);
      var upload_type = jobsData[0].upload_type;

      if(jobsData[0].job_desc) {
        this.elLk.form.find('input[name=name]').val(jobsData[0].job_desc);
      }

      if(jobsData[0].region) {
        var r = jobsData[0].region.match(/^([^:]+):\s?([0-9\,]+)(-|_|\.\.)([0-9\,]+)$/);

        if(((parseFloat(r[4].replace(/,/gi,"")) - parseFloat(r[2].replace(/,/gi,""))) + 1) >= 100000000) {
          this.elLk.form.find('input[name=region]').parent().find('label.invalid').remove();
          this.elLk.form.find('input[name=region]').parent().append('Please note that with this size of genomic region, the job may take a long time (> 6h) to run');
        } else {
          this.elLk.form.find('input[name=region]').parent().find('label.invalid').remove(); //just a precaution in case someone change the region again
        }
      }

      if (upload_type === 'custom') {
        this.elLk.form.find('select[name=collection_format] option').removeAttr("selected");
        this.elLk.form.find('select[name=collection_format]').find('option[value=custom]').prop('selected', true).end().selectToToggle('trigger');
        this.elLk.form.find('input[name=custom_file_url]').val(jobsData[0].file_url);
        this.elLk.form.find('input[name=custom_sample_url]').val(jobsData[0].sample_panel);
        this.updatePopulation(jobsData[0].sample_panel,"custom_population", jobsData[0].population); //show population listbox
      } else {
        var population = this.elLk.form.find('input[name=region]').val().match(/y:/gi) && upload_type === "phase3" ? "phase3_male" : upload_type;
        this.elLk.form.find('select[name=collection_format] option').removeAttr("selected");
        this.elLk.form.find('select[name=collection_format]').find('option[value=' + upload_type + ']').prop('selected', true).end().selectToToggle('trigger');
        this.elLk.form.find('span._span_url').html("Genotype file URL: " + jobsData[0].file_url);
        this.elLk.form.find('input[name=generated_file_url]').val(jobsData[0].file_url);
        this.elLk.form.find('[class^="_sample_url_"]').hide(); //just a sanity check to hide everything first so that nothing is shown by mistake
        this.elLk.form.find('span._sample_url_'+population).show();
        this.updatePopulation("","_stt_"+population,jobsData[0].population);
      }
    }
  },

  reset: function() {
    this.base.apply(this, arguments);

    this.elLk.region.parent().find('label.invalid').remove();
    this.elLk.form.find('div.population').hide();
    this.elLk.form.find('select[name=collection_format]').find('option[value=phase3]').prop('selected', true).end().selectToToggle('trigger');
	this.elLk.form.find('span._span_url').html('Genotype file URL: ').show();
	this.elLk.form.find('input[name=generated_file_url]').val("");
  },

  updatePopulation: function(panel_url, panel_name, selected_value) {
  //create population listbox from panel file url or show hidden population listbox
    this.base.apply(this, arguments);
    var panel = this;

    if(!panel_url) {
      this.elLk.form.find('div.population').hide();
      this.elLk.form.find('div.'+panel_name).show();
      if(selected_value) {
        var population_listbox = panel_name.replace("_stt_","") + "_populations";
        this.elLk.form.find('select[name=' + population_listbox + '] option').removeAttr("selected");
        this.elLk.form.find('select[name=' + population_listbox + ']').find('option[value=' + selected_value + ']').prop('selected', true).end();
      }
    } else {
      panel.ajax({
        'comet'   : true,
        'type'    : 'POST',
        'url'     : panel.readSampleFile,
        'data'    : { population_url: panel_url },
        'spinner' : true,
        'success' : function(json) {
          var listbox  ="";
          var selected = "";
          if(json.error) {
            panel.showError('The sample population url is either invalid or not reachable', 'Invalid sample population URL');
            $(panel.elLk.form).data('valid', false);
            panel.ajax.spinner = 'false';
          } else {
            $.each (json.populations, function (index,el) {
              if(el.value) {
                if(el.value.match(/sample/gi)) { next; } //skip if  there is a header
                selected = selected_value && selected_value === el.value ? 'selected="selected"' : '';
                listbox += '<option value="' + el.value + '"' + selected +'>' + el.caption + '</option>';
              }
            });
            panel.elLk.form.find('div.custom_population').show();
            panel.elLk.form.find('div.custom_population select').html('').append(listbox);
          }
        }
      });
    }
  }
});
<|endoftext|>


<commit_before>var Cookiebar = (function(doc) {

    function _(el) {
        if (!(this instanceof _)) {
            return new _(el);
        }

        var first = el.charAt(0);

        if (first === "#") {
            this.el = doc.getElementById(el.substr(1));
        } else if (first === ".") {
            this.el = doc.getElementsByClassName(el.substr(1));
        } else {
            this.el = doc.getElementsByTagName(el);
        }
    }

    _.prototype.fade = function fade(type, ms, dis) {
        var isIn = type === 'in',
            opacity = isIn ? 0 : 1,
            interval = 50,
            duration = ms,
            gap = interval / duration,
            display = dis ? dis : 'inline',
            self = this;

        if (isIn) {
            self.el.style.display = display;
            self.el.style.opacity = opacity;
        }

        function func() {
            opacity = isIn ? opacity + gap : opacity - gap;
            self.el.style.opacity = opacity;

            if (opacity <= 0) self.el.style.display = 'none';
            if (opacity <= 0 || opacity >= 1) window.clearInterval(fading);
        }

        var fading = window.setInterval(func, interval);
    };

    var Vanilla = function() {};

    Vanilla.prototype.extend = function(target) {
        for (var i = 1; i < arguments.length; ++i) {
            var from = arguments[i];
            if (typeof from !== 'object') continue;
            for (var j in from) {
                if (from.hasOwnProperty(j)) {
                    target[j] = typeof from[j] === 'object' ?
                        this.extend({}, target[j], from[j]) : from[j];
                }
            }
        }
        return target;
    };

    Vanilla.prototype.trigger = function(el, eventName) {
        var event = doc.createEvent('Event');
        event.initEvent(eventName, true, true);
        el.dispatchEvent(event);
    };

    /**
     * Vanilla JavaScript support IE8+.
     *
     * @link https://plainjs.com
     */

    Vanilla.prototype.addEvent = function(el, type, handler) {
        if (el.attachEvent) el.attachEvent('on' + type, handler);
        else el.addEventListener(type, handler);
    };

    Vanilla.prototype.removeEvent = function(el, type, handler) {
        if (el.detachEvent) el.detachEvent('on' + type, handler);
        else el.removeEventListener(type, handler);
    };

    Vanilla.prototype.parseTemplate = function(str, data) {
        return str.replace(/\$\{(\w+)\}/gi, function(match, parensMatch) {
            if (data[parensMatch] !== undefined) {
                return data[parensMatch];
            }

            return match;
        });
    };

    var v = new Vanilla();

    var Cookiebar = function(opt) {
        this.opt = v.extend({
            id: "cookiebar",
            cls: "cookiebar",
            cookie: "cookiebar",
            content: {
                description: "Az oldal sütiket használ a működéshez. Szolgáltatásaink igénybevételével Ön beleegyezik a sütik használatába!",
                link: "További információk",
                href: "http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm",
                button: "Elfogadom",
                more: "Az EU-s jogszabályok értelmében fel kell hívnunk a figyelmét, hogy oldalaink sütiket (cookie) használnak. Ezek miniatűr, ártalmatlan fájlok, melyeket az ön gépére helyezünk el, hogy a szolgáltatásaink használatát egyszerűbbé tegyük az ön számára. A sütiket természetesen letilthatja a böngészőjében, azonban ha az Elfogadom feliratú gombra kattint, akkor elfogadja azok használatát."
            },
            fade: {
                type: "in",
                ms: "500",
                display: "inline"
            },
            debug: 0,
            exits: true
        }, opt || {});
        this.data = this.opt;
        this.bodyMargBotBackup = doc.body.style.marginBottom || "";
        this.visible = false;

        //Initialize
        this.init();
    };

    Cookiebar.prototype.init = function() {
        var self = this;
        if (self.data.debug) {
            self.setCookie('debug_cookibar', "test", 365, function() {
                self.delCookie(self.data.id);
                self.checkCookie();
            });
        } else {
            self.checkCookie();
        }
    };

    Cookiebar.prototype.exitsCookie = function() {
        return this.getCookie(this.data.cookie) === "true";
    };

    Cookiebar.prototype.getCookie = function(cname) {
        var name = cname + "=";
        var ca = doc.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) === 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    };

    Cookiebar.prototype.setCookie = function(cname, value, exdays, cb) {
        var ex = new Date();
        ex.setDate(ex.getDate() + exdays);

        var cvalue = escape(value) + (
            exdays === null ? "" : "; expires=" + ex.toUTCString() + "; path=/;"
        );

        doc.cookie = cname + "=" + cvalue;

        if (typeof cb === "function") {
            cb();
        }
    };

    Cookiebar.prototype.delCookie = function(cname) {
        doc.cookie = cname + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
    };

    Cookiebar.prototype.html = function() {
        var self = this,
            html = '
' +
            '
${des}
' +
            '
' +
            '${link}' +
            '
' +
            '
' +
            '<button type="button" name="${cls}-button" class="${cls}-btn">${btn}</button>' +
            '
' +
            '
${more}
' +
            '
';

        return v.parseTemplate(html, {
            cls: self.data.cls,
            href: self.data.content.href,
            link: self.data.content.link,
            more: self.data.content.more,
            btn: self.data.content.button,
            des: self.data.content.description
        });
    };

    Cookiebar.prototype.draw = function() {
        var self = this,
            bar = doc.createElement('div');

        bar.id = self.data.id;
        bar.className = self.data.cls;
        bar.innerHTML = self.html();

        doc.body.insertBefore(bar, doc.body.firstChild);

        var btn = bar.getElementsByClassName(self.data.cls + '-btn')[0];

        v.addEvent(btn, 'click', function(e) {
            if (typeof e.preventDefault !== "undefined") {
                e.preventDefault();
            } else {
                e.returnValue = false;
            }

            this.visible = false;
            v.removeEvent(window, 'resize');
            self.setCookie(self.data.cookie, true, 365);
            bar.style.display = 'none';

            if (doc.body.style.marginBottom !== self.bodyMargBotBackup) {
                doc.body.style.marginBottom = self.bodyMargBotBackup;
            }
        });

        v.addEvent(window, 'resize', function() {
            var height = bar.offsetHeight;
            if (self.visible) {
                doc.body.style.marginBottom = height + "px";
            }
        });

        v.trigger(window, 'resize');
    };

    Cookiebar.prototype.checkCookie = function() {
        if (!this.exitsCookie()) {
            this.draw();
            _("#" + this.data.id).fade(this.data.fade.type, this.data.fade.ms);
            this.setCookie(this.data.cookie, null, 365);
            this.visible = true;
        } else {
            this.visible = false;
        }
    };

    return Cookiebar;

})(document);
<commit_msg>Update cookiebar.js<commit_after>var Cookiebar = (function(doc) {

    function _(el) {
        if (!(this instanceof _)) {
            return new _(el);
        }

        var first = el.charAt(0);

        if (first === "#") {
            this.el = doc.getElementById(el.substr(1));
        } else if (first === ".") {
            this.el = doc.getElementsByClassName(el.substr(1));
        } else {
            this.el = doc.getElementsByTagName(el);
        }
    }

    _.prototype.fade = function fade(type, ms, dis) {
        var isIn = type === 'in',
            opacity = isIn ? 0 : 1,
            interval = 50,
            duration = ms,
            gap = interval / duration,
            display = dis ? dis : 'inline',
            self = this;

        if (isIn) {
            self.el.style.display = display;
            self.el.style.opacity = opacity;
        }

        function func() {
            opacity = isIn ? opacity + gap : opacity - gap;
            self.el.style.opacity = opacity;

            if (opacity <= 0) self.el.style.display = 'none';
            if (opacity <= 0 || opacity >= 1) window.clearInterval(fading);
        }

        var fading = window.setInterval(func, interval);
    };

    var Vanilla = function() {};

    Vanilla.prototype.extend = function(target) {
        for (var i = 1; i < arguments.length; ++i) {
            var from = arguments[i];
            if (typeof from !== 'object') continue;
            for (var j in from) {
                if (from.hasOwnProperty(j)) {
                    target[j] = typeof from[j] === 'object' ?
                        this.extend({}, target[j], from[j]) : from[j];
                }
            }
        }
        return target;
    };

    Vanilla.prototype.trigger = function(el, eventName) {
        var event = doc.createEvent('Event');
        event.initEvent(eventName, true, true);
        el.dispatchEvent(event);
    };

    /**
     * Vanilla JavaScript support IE8+.
     *
     * @link https://plainjs.com
     */

    Vanilla.prototype.addEvent = function(el, type, handler) {
        return (el[window.attachEvent ? 'attachEvent' : 'addEventListener'](
            (window.attachEvent ? 'on' : '')+type, handler, true
        ));
    };

    Vanilla.prototype.removeEvent = function(el, type, handler) {
        if (el.detachEvent) el.detachEvent('on' + type, handler);
        else el.removeEventListener(type, handler);
    };

    Vanilla.prototype.parseTemplate = function(str, data) {
        return str.replace(/\$\{(\w+)\}/gi, function(match, parensMatch) {
            if (data[parensMatch] !== undefined) {
                return data[parensMatch];
            }

            return match;
        });
    };

    var v = new Vanilla();

    var Cookiebar = function(opt) {
        var self = this;
        this.opt = v.extend({
            id: "cookiebar",
            cls: "cookiebar",
            cookie: "cookiebar",
            content: {
                description: "Az oldal sütiket használ a működéshez. Szolgáltatásaink igénybevételével Ön beleegyezik a sütik használatába!",
                link: "További információk",
                href: "http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm",
                button: "Elfogadom",
                more: "Az EU-s jogszabályok értelmében fel kell hívnunk a figyelmét, hogy oldalaink sütiket (cookie) használnak. Ezek miniatűr, ártalmatlan fájlok, melyeket az ön gépére helyezünk el, hogy a szolgáltatásaink használatát egyszerűbbé tegyük az ön számára. A sütiket természetesen letilthatja a böngészőjében, azonban ha az Elfogadom feliratú gombra kattint, akkor elfogadja azok használatát."
            },
            fade: {
                type: "in",
                ms: "500",
                display: "inline"
            },
            debug: 0,
            exits: true
        }, opt || {});

        this.bar = null;
        this.data = this.opt;
        this.bodyMargBotBackup = doc.body.style.marginBottom || "";
        this.accepted = false;
        this.events = {
            btnClick: function(e) {
                if (e && e.preventDefault) e.preventDefault();
                else if (typeof e === 'object') e.returnValue = false;

                self.accept();
            },
            winResize: function() {
                if (self.accepted) { return; }
                doc.body.style.marginBottom = self.bar.offsetHeight + "px";
            }
        };
        //Initialize
        this.init();
    };

    Cookiebar.prototype.init = function() {
        var self = this;

        if (self.data.debug) {
            self.setCookie('debug_cookibar', "test", 365, function() {
                self.delCookie(self.data.id);
                self.checkCookie();
            });
        } else {
            self.checkCookie();
        }
    };

    Cookiebar.prototype.getCookie = function(cname) {
        var name = cname + "=";
        var ca = doc.cookie.split(';');

        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) === 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    };

    Cookiebar.prototype.setCookie = function(cname, value, exdays, cb) {
        var ex = new Date();
        ex.setDate(ex.getDate() + exdays);

        var cvalue = escape(value) + (
            exdays === null ? "" : "; expires=" + ex.toUTCString() + "; path=/;"
        );

        doc.cookie = cname + "=" + cvalue;

        if (typeof cb === "function") {
            cb.call(this);
        }
    };

    Cookiebar.prototype.delCookie = function(cname) {
        doc.cookie = cname + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
    };

    Cookiebar.prototype.html = function() {
        var html = '
' +
            '
${des}
' +
            '
' +
            '${link}' +
            '
' +
            '
' +
            '<button type="button" name="${cls}-button" class="${cls}-btn">${btn}</button>' +
            '
' +
            '
${more}
' +
            '
';

        return v.parseTemplate(html, {
            cls: this.data.cls,
            href: this.data.content.href,
            link: this.data.content.link,
            more: this.data.content.more,
            btn: this.data.content.button,
            des: this.data.content.description
        });
    };

    Cookiebar.prototype.denny = function() {
        this.delCookie(this.data.id);
        this.accepted = false;
    };

    Cookiebar.prototype.accept = function() {
        this.accepted = true;
        this.setCookie(this.data.cookie, true, 365);

        v.removeEvent(window, 'resize', this.events.winResize);

        if (this.bar) {
            this.bar.style.display = 'none';
        }
        if (doc.body.style.marginBottom !== this.bodyMargBotBackup) {
            doc.body.style.marginBottom = this.bodyMargBotBackup;
        }
    };

    Cookiebar.prototype.draw = function() {
        var self = this, btn;

        if (self.accepted) { return; }

        if (!self.bar) {
            self.bar = doc.createElement('div');
            self.bar.id = self.data.id;
            self.bar.className = self.data.cls;
            self.bar.innerHTML = self.html();
            doc.body.insertBefore(self.bar, doc.body.firstChild);
            btn = self.bar.getElementsByClassName(self.data.cls + '-btn')[0];
            v.addEvent(btn, 'click', self.events.btnClick);
        }

        v.addEvent(window, 'resize', self.events.winResize);
        v.trigger(window, 'resize');

        _("#" + self.data.id).fade(self.data.fade.type, self.data.fade.ms);

        self.setCookie(self.data.cookie, null, 365);
    };

    Cookiebar.prototype.checkCookie = function() {
        this.accepted = this.getCookie(this.data.cookie) === "true";

        if (!this.accepted) { this.draw(); }
    };

    Cookiebar.prototype.getStatus = function() {
        return this.accepted;
    };

    return Cookiebar;
})(document);
<|endoftext|>


<commit_before>
function Enemy(game, x, y, health) {
  Phaser.Sprite.call(this, game, x, y, 'enemy');
  this.scale.setTo(0.25,0.25);
  this.game   = game;
  this.health = health;
}

Enemy.prototype = Object.create(Phaser.Sprite.prototype);

Enemy.prototype.update = function() {

}<commit_msg>Make sure Enemy has its own private scope<commit_after>(function() {
  "use strict";

  function Enemy(game, x, y, health) {
    Phaser.Sprite.call(this, game, x, y, 'enemy');
    this.scale.setTo(0.25,0.25);
    this.game   = game;
    this.health = health;
  }

  Enemy.prototype = Object.create(Phaser.Sprite.prototype);

  Enemy.prototype.update = function() {

  }

  window.Darwinator = window.Darwinator || {};
  window.Darwinator.Enemy = Enemy;

}());<|endoftext|>


<commit_before><commit_msg>Renamed test<commit_after><|endoftext|>


<commit_before>/* CAMERA.JS
 * Contains camera information and effects (zoom, shake, etc.).
 */

"use strict"

////////////////////////////////////////////////////////////////////////////////

var Camera = {
	x: 0,		// tiles
	y: 0,		// tiles
	width: 14	// tiles
}

Camera.getHalfWidth = function(){ return Camera.getWidth()/2; };
Camera.getHalfHeight = function(){ return Camera.getHeight()/2; };

Camera.getWidth = function(){
	return Camera.width;
}
Camera.getHeight = function(){
	return Camera.width * Camera.getAspectRatio();
}

Camera.getAspectRatio = function(){
	return WINDOW_HEIGHT / WINDOW_WIDTH
}

Camera.getScale = function(){
	return Camera.width / WINDOW_WIDTH;
}

/* CAMERA.CONTAINS
 * Whether or not a point is visible (has a padding so points a bit outside the
 * screen are visible too)
 */
Camera.contains = function(x, y){
	var xsep = Camera.x - x;
	var ysep = Camera.y - y;
	var maxx = Camera.getHalfWidth(); // Maximum magnitudes
	var maxy = Camera.getHalfHeight();
	return Math.abs(xsep) < maxx + 2 && Math.abs(ysep) < maxy + 2;
}

/* CAMERA.TRANSFORM
 * Transforms the given context to reflect the viewing angle specified by
 * camera.
 */
Camera.transform = function(ctx) {
	var scale = 1/Camera.getScale();
	ctx.scale(scale, scale);

	// Center camera on screen
	ctx.translate(
		-(Camera.x - Camera.getHalfWidth()),
		-(Camera.y - Camera.getHalfHeight())
	);
}

/* CAMERA.FROMSCREEN
 * Converts position (sx,sy) on the HTML canvas to world (tile) coordinates
 * Returns coordinates as array [x,y].
 */
Camera.fromScreen = function(sx,sy) {
	sx -= WINDOW_WIDTH / 2;
	sy -= WINDOW_HEIGHT / 2;
	var worldX = sx * Camera.getWidth() / WINDOW_WIDTH + Camera.x;
	var worldY = sy * Camera.getHeight() / WINDOW_HEIGHT + Camera.y;
	return [worldX,worldY];
}

//// CAMERA EFFECTS ////////////////////////////////////////////////////////////

Camera.shake = function(){

}<commit_msg>Camera Transform Option for Various Widths<commit_after>/* CAMERA.JS
 * Contains camera information and effects (zoom, shake, etc.).
 */

"use strict"

////////////////////////////////////////////////////////////////////////////////

var Camera = {
	x: 0,		// tiles
	y: 0,		// tiles
	width: 14	// tiles
}

Camera.getHalfWidth = function(){ return Camera.getWidth()/2; };
Camera.getHalfHeight = function(){ return Camera.getHeight()/2; };

Camera.getWidth = function(){
	return Camera.width;
}
Camera.getHeight = function(){
	return Camera.width * Camera.getAspectRatio();
}

Camera.getAspectRatio = function(){
	return WINDOW_HEIGHT / WINDOW_WIDTH
}

Camera.getScale = function(){
	return Camera.width / WINDOW_WIDTH;
}

/* CAMERA.CONTAINS
 * Whether or not a point is visible (has a padding so points a bit outside the
 * screen are visible too)
 */
Camera.contains = function(x, y){
	var xsep = Camera.x - x;
	var ysep = Camera.y - y;
	var maxx = Camera.getHalfWidth(); // Maximum magnitudes
	var maxy = Camera.getHalfHeight();
	return Math.abs(xsep) < maxx + 2 && Math.abs(ysep) < maxy + 2;
}

/* CAMERA.TRANSFORM
 * Transforms the given context to reflect the viewing angle specified by
 * camera.
 */
Camera.transform = function(ctx , winx) {
	var scale = (winx || WINDOW_WIDTH) / Camera.width;
	ctx.scale(scale, scale);

	// Center camera on screen
	ctx.translate(
		-(Camera.x - Camera.getHalfWidth()),
		-(Camera.y - Camera.getHalfHeight())
	);
}

/* CAMERA.FROMSCREEN
 * Converts position (sx,sy) on the HTML canvas to world (tile) coordinates
 * Returns coordinates as array [x,y].
 */
Camera.fromScreen = function(sx,sy) {
	sx -= WINDOW_WIDTH / 2;
	sy -= WINDOW_HEIGHT / 2;
	var worldX = sx * Camera.getWidth() / WINDOW_WIDTH + Camera.x;
	var worldY = sy * Camera.getHeight() / WINDOW_HEIGHT + Camera.y;
	return [worldX,worldY];
}

//// CAMERA EFFECTS ////////////////////////////////////////////////////////////

Camera.shake = function(){

}<|endoftext|>