<commit_before>// Copyright 2012 Software Freedom Conservancy. All Rights Reserved.
//
// 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.

/**
 * @fileoverview Defines utilities for exchanging messages between the
 * sandboxed SafariDriver injected script and its corresponding content page.
 */

goog.provide('safaridriver.inject.page');

goog.require('bot.Error');
goog.require('bot.ErrorCode');
goog.require('bot.dom');
goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.dom.classes');
goog.require('safaridriver.console');
goog.require('safaridriver.message');
goog.require('webdriver.CommandName');
goog.require('webdriver.error');
goog.require('webdriver.promise');

/**
 * @define {boolean} Whether this script is being used by the extension or has
 *     been injected into the web page.
 */
safaridriver.inject.page.EXTENSION = true;

/**
 * Class name assigned to the SCRIPT element used to insert the compiled form of
 * this script into the web page.
 * @type {string}
 * @const
 * @private
 */
safaridriver.inject.page.SCRIPT_CLASS_NAME_ = 'safari-driver';

/**
 * @type {!goog.debug.Logger}
 * @const
 * @private
 */
safaridriver.inject.page.LOG_ = goog.debug.Logger.getLogger(
    'safaridriver.inject.page.' +
        (safaridriver.inject.page.EXTENSION ? 'extension' : 'webpage'));

/**
 * Initializes this script. When included in the SafariDriver extension, this
 * appends a SCRIPT element to the DOM that loads the page script. When
 * included as the page script, this sends a LOADED message to the injected
 * script, informing it that the page script has been successfully loaded.
 */
safaridriver.inject.page.init = function() {
  var script;
  if (safaridriver.inject.page.EXTENSION) {
    safaridriver.inject.page.LOG_.info('Initializing for extension');

    script = document.createElement('script');
    script.className = safaridriver.inject.page.SCRIPT_CLASS_NAME_;
    script.type = 'text/javascript';
    script.src = safari.extension.baseURI + 'page.js';
    document.documentElement.appendChild(script);
  } else {
    safaridriver.console.init();
    safaridriver.inject.page.LOG_.info('Initializing for page');

    window.addEventListener('message', safaridriver.inject.page.onMessage_,
        true);

    var message = new safaridriver.message.Message(
        safaridriver.message.Type.LOADED);
    safaridriver.inject.page.LOG_.info('Sending ' + message);
    message.send(window);

    script = document.querySelector(
        'script.' + safaridriver.inject.page.SCRIPT_CLASS_NAME_ +
            ':last-child');
    // If we find the script running this script, remove it.
    if (script) {
      goog.dom.removeNode(script);
    }
  }
};

if (!safaridriver.inject.page.EXTENSION) {
  goog.exportSymbol('init', safaridriver.inject.page.init);
}

/**
 * Responds to messages from the injected script.
 * @param {Event} e The message event.
 * @private
 */
safaridriver.inject.page.onMessage_ = function(e) {
  try {
    var message = safaridriver.message.Message.fromEvent(
        (/** @type {!MessageEvent} */e));
  } catch (ex) {
    // Silently ignore parse failure; message may not have origininated from the
    // injected script.
    return;
  }

  // Ignore messages that are from this context. How would we receive our own
  // messages?  Simple - when we post a message to the page, in addition to
  // going to the page, it will be posted back on our own window.
  if (message.getOrigin() === safaridriver.message.ORIGIN) {
    return;
  }

  safaridriver.inject.page.LOG_.info('onMessage: ' + JSON.stringify(message));
  switch (message.getType()) {
    case safaridriver.message.Type.COMMAND:
      safaridriver.inject.page.onCommand_(
          (/** @type {!safaridriver.message.CommandMessage} */message));
      return;

    default:
      return;  // Ignore unknown message type.
  }
};

/**
 * Handles command messages from the injected script.
 * @param {!safaridriver.message.CommandMessage} message The command message.
 * @throws {Error} If the command is not supported by this script.
 * @private
 */
safaridriver.inject.page.onCommand_ = function(message) {
  var command = message.getCommand();
  switch (command.getName()) {
    case webdriver.CommandName.EXECUTE_ASYNC_SCRIPT:
      safaridriver.inject.page.executeAsyncScript_(command);
      break;

    case webdriver.CommandName.EXECUTE_SCRIPT:
      safaridriver.inject.page.executeScript_(command);
      return;

    default:
      throw Error('Unknown command: ' + command.getName());
  }
};

/**
 * Locates an element by XPath.
 * @param {string} xpath The XPath expression.
 * @return {Element} The located element or {@code null}.
 * @private
 */
safaridriver.inject.page.getElementByXpath_ = function(xpath) {
  return document.evaluate(xpath, document, null,
      XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
};

/**
 * Computes the canonical XPath locator for an element.
 * @param {!Element} element The element to compute an XPath expression for.
 * @return {string} The element's XPath locator.
 * @private
 */
safaridriver.inject.page.getElementXPath_ = function(element) {
  var path = '';
  for(; element; element = bot.dom.getParentElement(element)) {
    var index = 1;
    for (var sibling = element.previousSibling; sibling;
        sibling = sibling.previousSibling) {
      if (sibling.nodeType == goog.dom.NodeType.ELEMENT &&
          sibling.tagName == element.tagName) {
        index++;
      }
    }
    var tmp = '/' + element.tagName;
    if (index > 1) {
      tmp += '[' + index + ']';
    }
    path = tmp + path;
  }
  return path;
};

/**
 * Key used in an object literal to indicate it is the encoded representation of
 * a DOM element. The corresponding property's value will be a CSS selector for
 * the encoded elmeent.
 * @type {string}
 * @const
 * @private
 */
safaridriver.inject.page.ENCODED_ELEMENT_KEY_ = 'WebElement';

/**
 * Encodes a value so it may be included in a message exchanged between the
 * document and sandboxed injected script. Any DOM element references will
 * be replaced with an object literal whose sole key is t
 * @param {*} value The value to encode.
 * @return {*} The encoded value.
 * @throws {Error} If the value is cannot be encoded (e.g. it is a function, or
 *     an array or object with a cyclical reference).
 */
safaridriver.inject.page.encodeValue = function(value) {
  var type = goog.typeOf(value);
  switch (type) {
    case 'boolean':
    case 'number':
    case 'string':
      return value;

    case 'null':
    case 'undefined':
      return null;

    case 'array':
      return goog.array.map((/** @type {!Array} */value),
          safaridriver.inject.page.encodeValue);

    case 'object':
      if (bot.dom.isElement(value)) {
        // We don't permit elements belong to another document because we
        // wouldn't be able to find them again on the other side when the
        // element was decoded.
        if (value.ownerDocument !== document) {
          throw Error('The element does not belong to this document: ' +
              safaridriver.inject.page.getElementCssSelector_(value));
        }

        var encoded = {};
        encoded[safaridriver.inject.page.ENCODED_ELEMENT_KEY_] =
            safaridriver.inject.page.getElementCssSelector_(value);
        return encoded;
      }
      return goog.object.map((/** @type {!Object} */value),
          safaridriver.inject.page.encodeValue);

    case 'function':
    default:
      throw Error('Invalid value type: ' + type + ' => ' + value);
  }
};

/**
 * Decodes a value. Any object literals whose sole key is
 * {@link safaridriver.inject.page.ENCODED_ELEMENT_KEY_} will be considered an
 * encoded reference to a DOM element. The corresponding value for this key will
 * be used as a CSS selector to locate the element.
 * @param {*} value The value to decode.
 * @return {*} The decoded value.
 * @throws {bot.Error} If an encoded DOM element cannot be located on the page.
 * @throws {Error} If the value is an invalid type, or an array or object with
 *     cyclical references.
 */
safaridriver.inject.page.decodeValue = function(value) {
  var type = goog.typeOf(value);
  switch (type) {
    case 'boolean':
    case 'number':
    case 'string':
      return value;

    case 'null':
    case 'undefined':
      return null;

    case 'array':
      return goog.array.map((/** @type {!Array} */value),
          safaridriver.inject.page.decodeValue);

    case 'object':
      var obj = (/** @type {!Object} */value);
      var keys = Object.keys(obj);
      if (keys.length == 1 &&
          keys[0] === safaridriver.inject.page.ENCODED_ELEMENT_KEY_) {
        var xpath = value[safaridriver.inject.page.ENCODED_ELEMENT_KEY_];
        var element = safaridriver.inject.page.getElementByXpath_(xpath);
        if (!element) {
          throw new bot.Error(bot.ErrorCode.STALE_ELEMENT_REFERENCE,
              'Unable to locate encoded element: ' + xpath);
        }
        return element;
      }
      return goog.object.map(obj, safaridriver.inject.page.decodeValue);

    case 'function':
    default:
      throw Error('Invalid value type: ' + type + ' => ' + value);
  }
};

/**
 * Handles an executeScript command.
 * @param {!safaridriver.Command} command The command to execute.
 * @private
 */
safaridriver.inject.page.executeScript_ = function(command) {
  var response;
  try {
    // TODO: clean-up bot.inject.executeScript so it doesn't pull in so many
    // extra dependencies.
    var fn = new Function(command.getParameter('script'));

    var args = command.getParameter('args');
    args = (/** @type {!Array} */safaridriver.inject.page.decodeValue(args));

    response = fn.apply(window, args);
    console.log('script response', response);
    response = safaridriver.inject.page.encodeValue(response);
    response = {
      'status': bot.ErrorCode.SUCCESS,
      'value': response
    };
  } catch (ex) {
    response = webdriver.error.createResponse(ex);
  }
  var responseMessage = new safaridriver.message.ResponseMessage(
      command.getId(), response);
  safaridriver.inject.page.LOG_.info(
      'Sending executeScript response: ' + responseMessage);
  responseMessage.send(window);
};

/**
 * Handles an executeAsyncScript command.
 * @param {!safaridriver.Command} command The command to execute.
 * @private
 */
safaridriver.inject.page.executeAsyncScript_ = function(command) {
  var response = new webdriver.promise.Deferred();
  // When the response is resolved, we want to wrap it up in a message and
  // send it back to the injected script. This does all that.
  response.
      then(function(value) {
        value = safaridriver.inject.page.encodeValue(value);
        return {
          'status': bot.ErrorCode.SUCCESS,
          'value': value
        };
      }).
      then(null, webdriver.error.createResponse).
      then(function(response) {
        var responseMessage = new safaridriver.message.ResponseMessage(
            command.getId(), response);
        safaridriver.inject.page.LOG_.info(
            'Sending executeAsyncScript response: ' + responseMessage);
        responseMessage.send(window);
      });

  try {
    var script = (/** @type {string} */command.getParameter('script'));
    var scriptFn = new Function(script);

    var args = command.getParameter('args');
    args = (/** @type {!Array} */safaridriver.inject.page.decodeValue(args));
    // The last argument for an async script is the callback that triggers the
    // response.
    args.push(function(value) {
      window.clearTimeout(timeoutId);
      if (response.isPending()) {
        response.resolve(value);
      }
    });

    var startTime = goog.now();
    scriptFn.apply(window, args);

    // Register our timeout *after* the function has been invoked. This will
    // ensure we don't timeout on a function that invokes its callback after a
    // 0-based timeout:
    // var scriptFn = function(callback) {
    //   setTimeout(callback, 0);
    // };
    var timeout = (/** @type {number} */command.getParameter('timeout'));
    var timeoutId = window.setTimeout(function() {
      if (response.isPending()) {
        response.reject(new bot.Error(bot.ErrorCode.SCRIPT_TIMEOUT,
            'Timed out waiting for an asynchronous script result after ' +
                (goog.now() - startTime) +  ' ms'));
      }
    }, Math.max(0, timeout));
  } catch (ex) {
    if (response.isPending()) {
      response.reject(ex);
    }
  }
};
<commit_msg>JasonLeyba: It would help if I ran the tests before committing code...<commit_after>// Copyright 2012 Software Freedom Conservancy. All Rights Reserved.
//
// 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.

/**
 * @fileoverview Defines utilities for exchanging messages between the
 * sandboxed SafariDriver injected script and its corresponding content page.
 */

goog.provide('safaridriver.inject.page');

goog.require('bot.Error');
goog.require('bot.ErrorCode');
goog.require('bot.dom');
goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.dom.classes');
goog.require('safaridriver.console');
goog.require('safaridriver.message');
goog.require('webdriver.CommandName');
goog.require('webdriver.error');
goog.require('webdriver.promise');

/**
 * @define {boolean} Whether this script is being used by the extension or has
 *     been injected into the web page.
 */
safaridriver.inject.page.EXTENSION = true;

/**
 * Class name assigned to the SCRIPT element used to insert the compiled form of
 * this script into the web page.
 * @type {string}
 * @const
 * @private
 */
safaridriver.inject.page.SCRIPT_CLASS_NAME_ = 'safari-driver';

/**
 * @type {!goog.debug.Logger}
 * @const
 * @private
 */
safaridriver.inject.page.LOG_ = goog.debug.Logger.getLogger(
    'safaridriver.inject.page.' +
        (safaridriver.inject.page.EXTENSION ? 'extension' : 'webpage'));

/**
 * Initializes this script. When included in the SafariDriver extension, this
 * appends a SCRIPT element to the DOM that loads the page script. When
 * included as the page script, this sends a LOADED message to the injected
 * script, informing it that the page script has been successfully loaded.
 */
safaridriver.inject.page.init = function() {
  var script;
  if (safaridriver.inject.page.EXTENSION) {
    safaridriver.inject.page.LOG_.info('Initializing for extension');

    script = document.createElement('script');
    script.className = safaridriver.inject.page.SCRIPT_CLASS_NAME_;
    script.type = 'text/javascript';
    script.src = safari.extension.baseURI + 'page.js';
    document.documentElement.appendChild(script);
  } else {
    safaridriver.console.init();
    safaridriver.inject.page.LOG_.info('Initializing for page');

    window.addEventListener('message', safaridriver.inject.page.onMessage_,
        true);

    var message = new safaridriver.message.Message(
        safaridriver.message.Type.LOADED);
    safaridriver.inject.page.LOG_.info('Sending ' + message);
    message.send(window);

    script = document.querySelector(
        'script.' + safaridriver.inject.page.SCRIPT_CLASS_NAME_ +
            ':last-child');
    // If we find the script running this script, remove it.
    if (script) {
      goog.dom.removeNode(script);
    }
  }
};

if (!safaridriver.inject.page.EXTENSION) {
  goog.exportSymbol('init', safaridriver.inject.page.init);
}

/**
 * Responds to messages from the injected script.
 * @param {Event} e The message event.
 * @private
 */
safaridriver.inject.page.onMessage_ = function(e) {
  try {
    var message = safaridriver.message.Message.fromEvent(
        (/** @type {!MessageEvent} */e));
  } catch (ex) {
    // Silently ignore parse failure; message may not have origininated from the
    // injected script.
    return;
  }

  // Ignore messages that are from this context. How would we receive our own
  // messages?  Simple - when we post a message to the page, in addition to
  // going to the page, it will be posted back on our own window.
  if (message.getOrigin() === safaridriver.message.ORIGIN) {
    return;
  }

  safaridriver.inject.page.LOG_.info('onMessage: ' + JSON.stringify(message));
  switch (message.getType()) {
    case safaridriver.message.Type.COMMAND:
      safaridriver.inject.page.onCommand_(
          (/** @type {!safaridriver.message.CommandMessage} */message));
      return;

    default:
      return;  // Ignore unknown message type.
  }
};

/**
 * Handles command messages from the injected script.
 * @param {!safaridriver.message.CommandMessage} message The command message.
 * @throws {Error} If the command is not supported by this script.
 * @private
 */
safaridriver.inject.page.onCommand_ = function(message) {
  var command = message.getCommand();
  switch (command.getName()) {
    case webdriver.CommandName.EXECUTE_ASYNC_SCRIPT:
      safaridriver.inject.page.executeAsyncScript_(command);
      break;

    case webdriver.CommandName.EXECUTE_SCRIPT:
      safaridriver.inject.page.executeScript_(command);
      return;

    default:
      throw Error('Unknown command: ' + command.getName());
  }
};

/**
 * Locates an element by XPath.
 * @param {string} xpath The XPath expression.
 * @return {Element} The located element or {@code null}.
 * @private
 */
safaridriver.inject.page.getElementByXpath_ = function(xpath) {
  return document.evaluate(xpath, document, null,
      XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
};

/**
 * Computes the canonical XPath locator for an element.
 * @param {!Element} element The element to compute an XPath expression for.
 * @return {string} The element's XPath locator.
 * @private
 */
safaridriver.inject.page.getElementXPath_ = function(element) {
  var path = '';
  for (var current = element; current;
       current = bot.dom.getParentElement(current)) {
    var index = 1;
    for (var sibling = current.previousSibling; sibling;
        sibling = sibling.previousSibling) {
      if (sibling.nodeType == goog.dom.NodeType.ELEMENT &&
          sibling.tagName == current.tagName) {
        index++;
      }
    }
    var tmp = '/' + current.tagName;
    if (index > 1) {
      tmp += '[' + index + ']';
    }
    path = tmp + path;
  }
  return path;
};

/**
 * Key used in an object literal to indicate it is the encoded representation of
 * a DOM element. The corresponding property's value will be a CSS selector for
 * the encoded elmeent.
 * @type {string}
 * @const
 * @private
 */
safaridriver.inject.page.ENCODED_ELEMENT_KEY_ = 'WebElement';

/**
 * Encodes a value so it may be included in a message exchanged between the
 * document and sandboxed injected script. Any DOM element references will
 * be replaced with an object literal whose sole key is t
 * @param {*} value The value to encode.
 * @return {*} The encoded value.
 * @throws {Error} If the value is cannot be encoded (e.g. it is a function, or
 *     an array or object with a cyclical reference).
 */
safaridriver.inject.page.encodeValue = function(value) {
  var type = goog.typeOf(value);
  switch (type) {
    case 'boolean':
    case 'number':
    case 'string':
      return value;

    case 'null':
    case 'undefined':
      return null;

    case 'array':
      return goog.array.map((/** @type {!Array} */value),
          safaridriver.inject.page.encodeValue);

    case 'object':
      if (goog.dom.isElement(value)) {
        // We don't permit elements belong to another document because we
        // wouldn't be able to find them again on the other side when the
        // element was decoded.
        if (value.ownerDocument !== document) {
          throw Error('The element does not belong to this document: ' +
              safaridriver.inject.page.getElementXPath_(
                  (/** @type {!Element} */value)));
        }

        var encoded = {};
        encoded[safaridriver.inject.page.ENCODED_ELEMENT_KEY_] =
            safaridriver.inject.page.getElementXPath_(
                (/** @type {!Element} */value));
        return encoded;
      }
      return goog.object.map((/** @type {!Object} */value),
          safaridriver.inject.page.encodeValue);

    case 'function':
    default:
      throw Error('Invalid value type: ' + type + ' => ' + value);
  }
};

/**
 * Decodes a value. Any object literals whose sole key is
 * {@link safaridriver.inject.page.ENCODED_ELEMENT_KEY_} will be considered an
 * encoded reference to a DOM element. The corresponding value for this key will
 * be used as a CSS selector to locate the element.
 * @param {*} value The value to decode.
 * @return {*} The decoded value.
 * @throws {bot.Error} If an encoded DOM element cannot be located on the page.
 * @throws {Error} If the value is an invalid type, or an array or object with
 *     cyclical references.
 */
safaridriver.inject.page.decodeValue = function(value) {
  var type = goog.typeOf(value);
  switch (type) {
    case 'boolean':
    case 'number':
    case 'string':
      return value;

    case 'null':
    case 'undefined':
      return null;

    case 'array':
      return goog.array.map((/** @type {!Array} */value),
          safaridriver.inject.page.decodeValue);

    case 'object':
      var obj = (/** @type {!Object} */value);
      var keys = Object.keys(obj);
      if (keys.length == 1 &&
          keys[0] === safaridriver.inject.page.ENCODED_ELEMENT_KEY_) {
        var xpath = value[safaridriver.inject.page.ENCODED_ELEMENT_KEY_];
        var element = safaridriver.inject.page.getElementByXpath_(xpath);
        if (!element) {
          throw new bot.Error(bot.ErrorCode.STALE_ELEMENT_REFERENCE,
              'Unable to locate encoded element: ' + xpath);
        }
        return element;
      }
      return goog.object.map(obj, safaridriver.inject.page.decodeValue);

    case 'function':
    default:
      throw Error('Invalid value type: ' + type + ' => ' + value);
  }
};

/**
 * Handles an executeScript command.
 * @param {!safaridriver.Command} command The command to execute.
 * @private
 */
safaridriver.inject.page.executeScript_ = function(command) {
  var response;
  try {
    // TODO: clean-up bot.inject.executeScript so it doesn't pull in so many
    // extra dependencies.
    var fn = new Function(command.getParameter('script'));

    var args = command.getParameter('args');
    args = (/** @type {!Array} */safaridriver.inject.page.decodeValue(args));

    response = fn.apply(window, args);
    console.log('script response', response);
    response = safaridriver.inject.page.encodeValue(response);
    response = {
      'status': bot.ErrorCode.SUCCESS,
      'value': response
    };
  } catch (ex) {
    response = webdriver.error.createResponse(ex);
  }
  var responseMessage = new safaridriver.message.ResponseMessage(
      command.getId(), response);
  safaridriver.inject.page.LOG_.info(
      'Sending executeScript response: ' + responseMessage);
  responseMessage.send(window);
};

/**
 * Handles an executeAsyncScript command.
 * @param {!safaridriver.Command} command The command to execute.
 * @private
 */
safaridriver.inject.page.executeAsyncScript_ = function(command) {
  var response = new webdriver.promise.Deferred();
  // When the response is resolved, we want to wrap it up in a message and
  // send it back to the injected script. This does all that.
  response.
      then(function(value) {
        value = safaridriver.inject.page.encodeValue(value);
        return {
          'status': bot.ErrorCode.SUCCESS,
          'value': value
        };
      }).
      then(null, webdriver.error.createResponse).
      then(function(response) {
        var responseMessage = new safaridriver.message.ResponseMessage(
            command.getId(), response);
        safaridriver.inject.page.LOG_.info(
            'Sending executeAsyncScript response: ' + responseMessage);
        responseMessage.send(window);
      });

  try {
    var script = (/** @type {string} */command.getParameter('script'));
    var scriptFn = new Function(script);

    var args = command.getParameter('args');
    args = (/** @type {!Array} */safaridriver.inject.page.decodeValue(args));
    // The last argument for an async script is the callback that triggers the
    // response.
    args.push(function(value) {
      window.clearTimeout(timeoutId);
      if (response.isPending()) {
        response.resolve(value);
      }
    });

    var startTime = goog.now();
    scriptFn.apply(window, args);

    // Register our timeout *after* the function has been invoked. This will
    // ensure we don't timeout on a function that invokes its callback after a
    // 0-based timeout:
    // var scriptFn = function(callback) {
    //   setTimeout(callback, 0);
    // };
    var timeout = (/** @type {number} */command.getParameter('timeout'));
    var timeoutId = window.setTimeout(function() {
      if (response.isPending()) {
        response.reject(new bot.Error(bot.ErrorCode.SCRIPT_TIMEOUT,
            'Timed out waiting for an asynchronous script result after ' +
                (goog.now() - startTime) +  ' ms'));
      }
    }, Math.max(0, timeout));
  } catch (ex) {
    if (response.isPending()) {
      response.reject(ex);
    }
  }
};
<|endoftext|>


<commit_before>var Sound = function(ctx, url, volume, autoPlay, loop)
{
	this.volume = volume || 1;
	this.autoPlay = autoPlay || false;
	this.loop = loop || false

	if(ctx === "useHowler")
	{
		var sound = new Howl({  urls: [url],
			autoplay: this.autoPlay,  loop: this.loop,  volume: this.volume,
			});
		this.play = sound.play;
		this.stop = sound.stop;
	}

	else
	{
		this.ctx = ctx
		this.soundBuffer = null;
		var request = new XMLHttpRequest();
		request.open('GET', url, true);
		request.responseType = 'arraybuffer';
		// Create a gain node.
		this.gainNode = ctx.createGain();

		// Decode asynchronously
		var that = this;
		request.onload = function()
		{
			var thut = that;
			that.ctx.decodeAudioData(request.response, function(buffer)
			{
			that.soundBuffer = buffer;

			if(that.autoPlay)
				that.play();
			});
		}
		request.send();

	}

}

Sound.prototype.play = function (delay)
{
	delay = delay || 0;

	this.source = this.ctx.createBufferSource(); 				// creates a sound source
	this.source.loop = this.loop;								//sets the loop
	this.source.buffer = this.soundBuffer;                   	// tell the source which sound to play
	this.source.connect(this.gainNode);      					// connect the source to the node (serve to manipulate the sound)
	this.gainNode.connect(this.ctx.destination) 				// connect the node to the destination (speaker)
	this.gainNode.gain.value = this.volume;

	this.source.start(delay);                           // play the source after the given delay
}

Sound.prototype.stop = function (delay)
{
	delay = delay || 0;
	this.source.stop(delay);                           // play the source after the given delay
}

function init_sound_context(p_config)
{
  try
  {
    // Fix up for prefixing
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    var context = new AudioContext();
    return context
  }

  catch(e)
  {
  	return "useHowler";
  }
}<commit_msg>fallback audio howler<commit_after>var Sound = function(ctx, url, volume, autoPlay, loop)
{
	this.volume = volume || 1;
	this.autoPlay = autoPlay || false;
	this.loop = loop || false
	this.ctx = ctx

	if(this.ctx === "useHowler")
	{
		this.sound = new Howl({  urls: [url + ".mp3", url + ".ogg"],
			autoplay: this.autoPlay,  loop: this.loop,  volume: this.volume, buffer: true,
		});

	}

	else
	{
		this.soundBuffer = null;
		var request = new XMLHttpRequest();
		request.open('GET', url + "ogg", true);
		request.responseType = 'arraybuffer';
		// Create a gain node.
		this.gainNode = ctx.createGain();

		// Decode asynchronously
		var that = this;
		request.onload = function()
		{
			var thut = that;
			that.ctx.decodeAudioData(request.response, function(buffer)
			{
			that.soundBuffer = buffer;

			if(that.autoPlay)
				that.play();
			});
		}
		request.send();

	}

}

Sound.prototype.play = function (delay)
{
	if(this.ctx === "useHowler")
	{
		this.sound.play();
	}
	else
	{
		delay = delay || 0;

		this.source = this.ctx.createBufferSource(); 				// creates a sound source
		this.source.loop = this.loop;								//sets the loop
		this.source.buffer = this.soundBuffer;                   	// tell the source which sound to play
		this.source.connect(this.gainNode);      					// connect the source to the node (serve to manipulate the sound)
		this.gainNode.connect(this.ctx.destination) 				// connect the node to the destination (speaker)
		this.gainNode.gain.value = this.volume;

		this.source.start(delay);                           // play the source after the given delay

	}
}

Sound.prototype.stop = function (delay)
{
	if(this.ctx === "useHowler")
	{
		this.sound.stop()
	}
	else
	{
		delay = delay || 0;
		this.source.stop(delay);                           // play the source after the given delay

	}
}

function init_sound_context(p_config)
{
  try
  {
    // Fix up for prefixing
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    var context = new AudioContext();
    return context
  }

  catch(e)
  {
  	return "useHowler";
  }
}<|endoftext|>


<commit_before>var Board = function(tiles) {
  this.tiles = [];
  Tile.size = canvas.getWidth() / Board.tilesCount;
  Man.Radius = Tile.size * 0.4;
  Man.StrokeWidth = Man.Radius / 4;
  Man.board = this; //TODO capitalize or not? +REFACTOR
  Tile.board = this; //TODO capitalize or not? +REFACTOR
  this.selectedMan = undefined;
  this.myTurn = undefined;

  //TODO method too long? +REFACTOR
  for (var i = 0; i < tiles.length; ++i) {
    this.tiles[i] = [];
    for (var j = 0; j < tiles.length; ++j) {
      switch (tiles[i][j]) {
        case 'N': {
          this.tiles[i][j] = new Tile(Tile.TileType.NONPLAYABLE, i, j);
          break; }
        case 'B': {
          this.tiles[i][j] = new Tile(Tile.TileType.PLAYABLE, i, j);
          this.tiles[i][j].setMan(new ManBlack(this.tiles[i][j]));
          break; }
        case 'E': {
          this.tiles[i][j] = new Tile(Tile.TileType.PLAYABLE, i, j);
          break; }
        case 'W': {
          this.tiles[i][j] = new Tile(Tile.TileType.PLAYABLE, i, j);
          this.tiles[i][j].setMan(new ManWhite(this.tiles[i][j]));
          break; }

        default:
          console.error("Incorrect tile type");
      }
    }
  }
  $('.fade-in').fadeTo(Board.FadeTime, 1);
};

Board.tilesCount = 10;
Board.FadeTime = 1500;

Board.prototype.unselect = function() {
  if (this.selectedMan) {
    this.selectedMan.unselect();
    this.selectedMan = undefined;
  }
  this.clearAllHighlights();
  this.tilesAllowed = [];
};

Board.prototype.getMen = function(type) {
  var men = [];
  for (var i = 0; i < this.tiles.length; ++i) {
    for (var j = 0; j < this.tiles.length; ++j) {
      if (this.tiles[i][j].man !== undefined && this.tiles[i][j].man instanceof type)
        men.push(this.tiles[i][j].man);
    }
  }

  return men;
};

Board.prototype.setPlayerColor = function(color) {
  this.playerColor = color;
  this.myTurn = true;
  // var men;
  //
  // if (this.playerColor === "black") {
  //   men = this.getMen(ManWhite);
  //   this.myTurn = false;
  // }
  // else {
  //   men = this.getMen(ManBlack);
  //   this.myTurn = true;
  // }
  //
  // for (var i = 0; i < men.length; ++i)
  //   men[i].disableSelectable();
};

Board.prototype.select = function(man) {
  //clear previous selection
  this.unselect();

  //apply new selection
  this.selectedMan = man;
  this.findAllowedMoves(this.selectedMan);
};

Board.prototype.onMoveCompleted = function(tile) {
  tile.clearHighlights();
  this.findAllowedMoves(this.selectedMan);

  // this.selectedMan.unselect();
};

Board.prototype.findAllowedMoves = function(man) {
  var relativePos;

  if (man instanceof ManWhite)
    relativePos = [ [1, -1], [-1, -1] ];
  else
    relativePos = [ [1, 1], [-1, 1] ];

  var allowed = this.findAllowedMovesNoBeat(man, relativePos);
  var allowedForBeat = this.findAllowedMovesBeat(man);
  for (var i in allowed)
    allowed[i].setAsAllowed();
  for (var j in allowedForBeat)
    allowedForBeat[j].setAsAllowedForBeat();
  this.tilesAllowed = allowed.concat(allowedForBeat);
};

Board.prototype.findAllowedMovesNoBeat = function(man, relativePos) {
  var allowed = [];

  for (var i in relativePos) {
    var tileToCheck = {
      x: man.tile.x + relativePos[i][0],
      y: man.tile.y + relativePos[i][1]
    };
    if (this.areCoordsValid(tileToCheck) &&
      this.tiles[tileToCheck.x][tileToCheck.y].man === undefined)
        allowed.push(this.tiles[tileToCheck.x][tileToCheck.y]);
  }

  return allowed;
};

Board.prototype.findAllowedMovesBeat = function(man) {
  var relativePosBeat = [ [-2, -2], [-2, 2], [2, -2], [ 2, 2] ]; //always the same
  var allowed = [];

  for (var i in relativePosBeat) {
    var tileToCheck = {
      x: man.tile.x + relativePosBeat[i][0],
      y: man.tile.y + relativePosBeat[i][1]
    };
    var oppTileToCheck = {
      x: man.tile.x + relativePosBeat[i][0] / 2,
      y: man.tile.y + relativePosBeat[i][1] / 2,
    };
    if (this.areCoordsValid(tileToCheck) &&
      this.canBeat(tileToCheck, oppTileToCheck, man))
      allowed.push(this.tiles[tileToCheck.x][tileToCheck.y]);
  }

  return allowed;
};

Board.prototype.canBeat = function(tile, oppTile, man) {
  return this.tiles[tile.x][tile.y].man === undefined &&
    this.tiles[oppTile.x][oppTile.y].man !== undefined &&
    this.tiles[oppTile.x][oppTile.y].man.Color === man.oppositeColor();
};

//TODO ->moveManTo(selectedMan, tile) +RETHINK +REFACTOR
Board.prototype.moveSelectedManTo = function(tile) {
  this.clearAllHighlights();
  tile.setAsMovingToNow();

  this.selectedMan.moveToTile(tile, true);
  // changeTurn();
};

Board.prototype.clearAllHighlights = function() {
  for (var i in this.tilesAllowed)
    this.tilesAllowed[i].clearHighlights();
};

//TODO -> moveManTo(man, tile) +RETHINK +REFACTOR
Board.prototype.moveMan = function(fromX, fromY, toX, toY) {
  var fromTile = this.tiles[fromX][fromY];
  var toTile = this.tiles[toX][toY];

  if (fromTile.man !== undefined)
    fromTile.man.moveToTile(toTile, false);
};

// Board.prototype.getJumpCoords = function(x, y) {
//   var x = man.tile.x + xRelative;
//   var y = man.tile.y + yRelative;
//
//   if (!areCoordsValid(x, y))
//     return undefined;
//
//   return {
//     x: x,
//     y: y
//   };
// };

Board.prototype.areCoordsValid = function(tile) {
  return (tile.x >= 0 && tile.x < 10 && tile.y >= 0 && tile.y < 10);
};
<commit_msg>Allow only beating moves if beating is available<commit_after>var Board = function(tiles) {
  this.tiles = [];
  Tile.size = canvas.getWidth() / Board.tilesCount;
  Man.Radius = Tile.size * 0.4;
  Man.StrokeWidth = Man.Radius / 4;
  Man.board = this; //TODO capitalize or not? +REFACTOR
  Tile.board = this; //TODO capitalize or not? +REFACTOR
  this.selectedMan = undefined;
  this.myTurn = undefined;

  //TODO method too long? +REFACTOR
  for (var i = 0; i < tiles.length; ++i) {
    this.tiles[i] = [];
    for (var j = 0; j < tiles.length; ++j) {
      switch (tiles[i][j]) {
        case 'N': {
          this.tiles[i][j] = new Tile(Tile.TileType.NONPLAYABLE, i, j);
          break; }
        case 'B': {
          this.tiles[i][j] = new Tile(Tile.TileType.PLAYABLE, i, j);
          this.tiles[i][j].setMan(new ManBlack(this.tiles[i][j]));
          break; }
        case 'E': {
          this.tiles[i][j] = new Tile(Tile.TileType.PLAYABLE, i, j);
          break; }
        case 'W': {
          this.tiles[i][j] = new Tile(Tile.TileType.PLAYABLE, i, j);
          this.tiles[i][j].setMan(new ManWhite(this.tiles[i][j]));
          break; }

        default:
          console.error("Incorrect tile type");
      }
    }
  }
  $('.fade-in').fadeTo(Board.FadeTime, 1);
};

Board.tilesCount = 10;
Board.FadeTime = 1500;

Board.prototype.unselect = function() {
  if (this.selectedMan) {
    this.selectedMan.unselect();
    this.selectedMan = undefined;
  }
  this.clearAllHighlights();
  this.tilesAllowed = [];
};

Board.prototype.getMen = function(type) {
  var men = [];
  for (var i = 0; i < this.tiles.length; ++i) {
    for (var j = 0; j < this.tiles.length; ++j) {
      if (this.tiles[i][j].man !== undefined && this.tiles[i][j].man instanceof type)
        men.push(this.tiles[i][j].man);
    }
  }

  return men;
};

Board.prototype.setPlayerColor = function(color) {
  this.playerColor = color;
  this.myTurn = true;
  // var men;
  //
  // if (this.playerColor === "black") {
  //   men = this.getMen(ManWhite);
  //   this.myTurn = false;
  // }
  // else {
  //   men = this.getMen(ManBlack);
  //   this.myTurn = true;
  // }
  //
  // for (var i = 0; i < men.length; ++i)
  //   men[i].disableSelectable();
};

Board.prototype.select = function(man) {
  //clear previous selection
  this.unselect();

  //apply new selection
  this.selectedMan = man;
  this.findAllowedMoves(this.selectedMan);
};

Board.prototype.onMoveCompleted = function(tile) {
  tile.clearHighlights();
  this.findAllowedMoves(this.selectedMan);

  // this.selectedMan.unselect();
};

Board.prototype.findAllowedMoves = function(man) {
  var relativePos,
      allowed = [],
      allowedForBeat = [];

  if (man instanceof ManWhite)
    relativePos = [ [1, -1], [-1, -1] ];
  else
    relativePos = [ [1, 1], [-1, 1] ];

  allowedForBeat = this.findAllowedMovesBeat(man);
  if (allowedForBeat.length === 0) //if beat is possible, disallow simple moves
    allowed = this.findAllowedMovesNoBeat(man, relativePos);

  for (var j in allowedForBeat)
    allowedForBeat[j].setAsAllowedForBeat();
  for (var i in allowed)
    allowed[i].setAsAllowed();
  this.tilesAllowed = allowed.concat(allowedForBeat);
};

Board.prototype.findAllowedMovesNoBeat = function(man, relativePos) {
  var allowed = [];

  for (var i in relativePos) {
    var tileToCheck = {
      x: man.tile.x + relativePos[i][0],
      y: man.tile.y + relativePos[i][1]
    };
    if (this.areCoordsValid(tileToCheck) &&
      this.tiles[tileToCheck.x][tileToCheck.y].man === undefined)
        allowed.push(this.tiles[tileToCheck.x][tileToCheck.y]);
  }

  return allowed;
};

Board.prototype.findAllowedMovesBeat = function(man) {
  var relativePosBeat = [ [-2, -2], [-2, 2], [2, -2], [ 2, 2] ]; //always the same
  var allowed = [];

  for (var i in relativePosBeat) {
    var tileToCheck = {
      x: man.tile.x + relativePosBeat[i][0],
      y: man.tile.y + relativePosBeat[i][1]
    };
    var oppTileToCheck = {
      x: man.tile.x + relativePosBeat[i][0] / 2,
      y: man.tile.y + relativePosBeat[i][1] / 2,
    };
    if (this.areCoordsValid(tileToCheck) &&
      this.canBeat(tileToCheck, oppTileToCheck, man))
      allowed.push(this.tiles[tileToCheck.x][tileToCheck.y]);
  }

  return allowed;
};

Board.prototype.canBeat = function(tile, oppTile, man) {
  return this.tiles[tile.x][tile.y].man === undefined &&
    this.tiles[oppTile.x][oppTile.y].man !== undefined &&
    this.tiles[oppTile.x][oppTile.y].man.Color === man.oppositeColor();
};

//TODO ->moveManTo(selectedMan, tile) +RETHINK +REFACTOR
Board.prototype.moveSelectedManTo = function(tile) {
  this.clearAllHighlights();
  tile.setAsMovingToNow();

  this.selectedMan.moveToTile(tile, true);
  // changeTurn();
};

Board.prototype.clearAllHighlights = function() {
  for (var i in this.tilesAllowed)
    this.tilesAllowed[i].clearHighlights();
};

//TODO -> moveManTo(man, tile) +RETHINK +REFACTOR
Board.prototype.moveMan = function(fromX, fromY, toX, toY) {
  var fromTile = this.tiles[fromX][fromY];
  var toTile = this.tiles[toX][toY];

  if (fromTile.man !== undefined)
    fromTile.man.moveToTile(toTile, false);
};

// Board.prototype.getJumpCoords = function(x, y) {
//   var x = man.tile.x + xRelative;
//   var y = man.tile.y + yRelative;
//
//   if (!areCoordsValid(x, y))
//     return undefined;
//
//   return {
//     x: x,
//     y: y
//   };
// };

Board.prototype.areCoordsValid = function(tile) {
  return (tile.x >= 0 && tile.x < 10 && tile.y >= 0 && tile.y < 10);
};
<|endoftext|>


<commit_before>$("body").css("font-size", 60);
<commit_msg>ON PEUT METTRE DES SCRIPTS DANS MARKDOWN<commit_after>$("h1").css("font-size", "60px!important");
console.log("test depuis le script externe");
<|endoftext|>


<commit_before>// ==UserScript==
// @name        hBlockOwnedAV
// @name:zh-CN  【H】屏蔽已拥有AV
// @author      Dodying
// @namespace   https://github.com/dodying/Dodying-UserJs
// @supportURL  https://github.com/dodying/Dodying-UserJs/issues
// @icon        http://cdn4.iconfinder.com/data/icons/mood-smiles/80/mood-29-48.png
// @description	1pondo.tv需按按钮
// @include     http://www.dmm.co.jp/*
// include      http*://www.baidu.com/*
// include      https://www.google.co.jp/*
// @include     *.tokyo-hot.com/*
// @include     *.caribbeancom.com/*
// @include     *.1000giri.net/*
// @include     *.10musume.com/*
// @include     *.heyzo.com/*
// @include     *.1pondo.tv/*
// @include     *bt*.*/*
// @include     *jav*.*/*
// @include     *av28*.*/*
// include     *fuli*
// @version     1
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_deleteValue
// @grant       GM_listValues
// @run-at      document-end
// ==/UserScript==
var URL = window.location.toString();
if (URL.indexOf('http://www.javlibrary.com/cn/?v=jav') >= 0) {
  var Code_Try = document.querySelector('#video_id  .text').innerHTML;
} else {
  var Code_Try = CodeTry(URL);
}
QuickButton();
if (URL.indexOf('search') >= 0) {
  SearchResult();
}
Block(); //先屏蔽一次
DeleteSameCode('0');
DeleteSameCode('1');
DeleteSameCode('2');
window.onscroll = function () {
  document.querySelector('#QuickButton').style.top = document.documentElement.scrollTop + 'px';
}
window.addEventListener('keydown', function (e) {
  if (e.keyCode == 66) { //Bb
    document.querySelector('#QuickButton_Switch').click();
  }
}, true);
document.querySelector('#QuickButton_Switch').onclick = function () {
  if (document.querySelector('#QuickButton_Switch img').src == 'https://cdn1.iconfinder.com/data/icons/ui-icons-2/512/checkbox-off-01-24.png') {
    Block();
  } else {
    TurnOffBlock();
    document.querySelector('#QuickButton_Switch img').src = 'https://cdn1.iconfinder.com/data/icons/ui-icons-2/512/checkbox-off-01-24.png';
  }
}
document.querySelector('#QuickButton_Add').onclick = function () {
  var code = prompt('新增\n请输入【番号】：\n10musume-\nCarib-\nTokyo-Hot \n1000girls-\nHeyzo-\n1pon-', Code_Try).toUpperCase();
  var NewAdd = GM_getValue('NewAdd', '');
  if (NewAdd == '') {
    GM_setValue('NewAdd', code);
  } else if (NewAdd.indexOf(code) >= 0) {
    return;
  } else {
    GM_setValue('NewAdd', NewAdd + '|' + code);
  }
  document.querySelector('#QuickButton_Search').href = 'http://btio.pw/search/' + code;
  document.querySelector('#QuickButton_Apply').style.display = 'inline';
}
document.querySelector('#QuickButton_Abandon').onclick = function () {
  var code = prompt('抛弃\n请输入【番号】：\n10musume-\nCarib-\nTokyo-Hot \n1000girls-\nHeyzo-\n1pon-', Code_Try).toUpperCase();
  var NewDelete = GM_getValue('NewDelete', '');
  if (NewDelete == '') {
    GM_setValue('NewDelete', code);
  } else if (NewDelete.indexOf(code) >= 0) {
    return;
  } else {
    GM_setValue('NewDelete', NewDelete + '|' + code);
  }
  document.querySelector('#QuickButton_Apply').style.display = 'inline';
}
document.querySelector('#QuickButton_Delete').onclick = function () {
  var code = prompt('删除\n请输入【番号】：\n10musume-\nCarib-\nTokyo-Hot \n1000girls-\nHeyzo-\n1pon-', Code_Try).toUpperCase();
  var list = GM_listValues();
  for (i in list) {
    list[i] = GM_getValue(i);
    if (list[i].indexOf(code >= 0)) {
      list[i] = list[i].replace(code, '').replace(/$\|/, '').replace(/\|\|/g, '');
      GM_setValue(i, list[i])
    }
  }
  delete list;
  document.querySelector('#QuickButton_Apply').style.display = 'inline';
}
document.querySelector('#QuickButton_Change').onclick = function () {
  var code_all = prompt('更改\nWait2OK\n请输入【番号】，以[|]分割：', Code_Try).toUpperCase();
  var code = code_all.split('|');
  var Wait_all = GM_getValue('0');
  var Wait = Wait_all.split('|');
  for (var i = 0; i < code.length; i++) {
    for (var n = 0; n < Wait.length; n++) {
      //alert('code['+i+']\n'+Code[i]+'\nWait['+n+']\n'+Wait[n]);
      //alert(code[i]+'\n'+ Wait[n])
      if (code[i] == Wait[n]) {
        Wait.splice(n, 1);
        n = n - 1;
      }
    }
  }
  Wait_New = Wait.join('|');
  //Wait_all = Wait_all.replace(/\|\|/g, '');
  GM_setValue('0', Wait_New);
  GM_setValue('1', GM_getValue(1) + '|' + code_all);
  document.querySelector('#QuickButton_Apply').style.display = 'inline';
}
document.querySelector('#QuickButton_Apply').onclick = function () {
  Add2To1('0', 'NewAdd');
  var OK_all = GM_getValue('1');
  var OK = OK_all.split('|');
  var code_all = GM_getValue('NewDelete');
  var code = code_all.split('|');
  for (var i = 0; i < code.length; i++) {
    for (var n = 0; n < OK.length; n++) {
      //alert('code['+i+']\n'+Code[i]+'\nWait['+n+']\n'+Wait[n]);
      //alert(code[i]+'\n'+ Wait[n])
      if (code[i] == OK[n]) {
        OK.splice(n, 1);
        n = n - 1;
      }
    }
  }
  OK_New = OK.join('|');
  GM_setValue('1', OK_New);
  Add2To1('2', 'NewDelete');
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////

function QuickButton() {
  var div = document.createElement('div');
  div.id = 'QuickButton'
  var left = document.documentElement.clientWidth - 24;
  div.style = 'background-color:white;text-align:center;position:absolute;left:' + left + 'px; top:0px;z-index:9999;';
  //1开关 搜索 3添加 抛弃 5等待到OK 6应用
  div.innerHTML = '

';
  document.body.appendChild(div);
}
function SearchResult() {
  var parent = document.querySelectorAll('#list li');
  for (var i = 0; i < parent.length; i++) {
    var href = parent[i].querySelector('a').getAttribute('href');
    var no_video = new RegExp('pcgame|dlsoft|book|doujin|goods', 'gi');
    if (no_video.test(href)) {
      document.querySelector('#list').removeChild(parent[i]);
    }
  }
}
function Add2To1(name1, name2) {
  var all_1 = GM_getValue(name1);
  var all_2 = GM_getValue(name2);
  var all = all_1 + '|' + all_2;
  all = all.replace(/||/g, '');
  GM_setValue(name1, all);
  GM_deleteValue(name2);
}
function DeleteSameCode(name) {
  var array = GM_getValue(name).split('|');
  array.sort();
  for (var i = 0; i < array.length; i++) {
    if (array[i] == array[i + 1]) {
      array.splice(i + 1, 1);
    }
  }
  var all = array.join('|').toUpperCase();
  //console.log('数据库'+name+'  '+all);
  GM_setValue(name, all);
}
function Block() {
  var Code_All = new Array(); //0等待，1完成，2抛弃+女同，3动画，4欧美
  if (GM_getValue('NewAdd', '') == '') {
    Code_All[0] = GM_getValue('0');
  } else {
    Code_All[0] = GM_getValue('0') + '|' + GM_getValue('NewAdd', '');
  }
  Code_All[1] = GM_getValue('1');
  var del = GM_getValue('NewDelete', '');
  if (del != '') {
    var del_array = new Array();
    var del_array = del.split('|');
    for (var i = 0; i < del_array.length; i++) {
      Code_All[1] = Code_All[1].replace(del_array[i], '').replace(/||/g, '');
    }
  }
  if (GM_getValue('NewDelete', '') == '') { //抛弃+女同
    Code_All[2] = GM_getValue('2');
  } else {
    Code_All[2] = GM_getValue('2') + '|' + GM_getValue('NewDelete', '');
  }
  Code_All[3] = 'してあげちゃう-治癒|コワレモノ-璃沙|凌成敗|理-コトワリ|相姦遊戯|相思相愛ノート|相関遊戯|都合のよいセックスフレンド|ヌキどきッ|ピスはめ|ハーレムタイム|ツンツンメイドはエロエロです|Love-Selection|ばくあね|漫喫ハプニング|恋騎士|雨芳恋歌|娘ワレモノ|少女教育|夜這いする七人の孕女|なまイキ|学園で時間よ止まれ|女子校生の腰つき|メイドさんとボイン魂|デーモンバスターズ|小悪魔カノジョ|3PingLovers|イエナイコト'; //英文无效
  //Code_All[6]='1By-Day.14.02.15|EuroTeenErotica.14.01.30|EuroTeenErotica.14.04.17|EuroTeenErotica.15.06.22|EuroTeenErotica.15.08.24|EuroTeenErotica.15.01.01';
  for (var i = 0; i < Code_All.length; i++) {
    console.log(Code_All[i])
  }
  img_status_All_1 = 'Loading|OK|Abandoned|Flash';
  img_status_All = img_status_All_1.split('|');
  span_status_All_1 = 'yellow|green|black|green';
  span_status_All = span_status_All_1.split('|');
  href_status_All_1 = '#等待中|#已下载|#已删除|#已下载_动画';
  href_status_All = href_status_All_1.split('|');
  var URL_NeedChange = new RegExp('bt|tokyo-hot.com|www.caribbeancom.com|www.1000giri.net|www.10musume.com|www.heyzo.com|1pondo.tv', 'gi');
  if (URL_NeedChange.test(URL)) {
    for (var a = 0; a < Code_All.length; a++) {
      Code_All[a] = Code_All[a].replace(/10musume-/gi, '').replace(/Carib-/gi, '').replace(/Tokyo-Hot /gi, '').replace(/1000girls-/gi, '').replace(/Heyzo-/gi, '').replace(/1pon-/gi, '');
    }
  }
  var URL_img = new RegExp('av|dmm.co.jp|tokyo-hot.com|www.10musume.com|www.1000giri.net|heyzo.com|1pondo.tv', 'gi'); //图片
  if (URL_img.test(URL)) {
    var div_img = 'img';
    var img = document.querySelectorAll(div_img);
  }
  var URL_span = new RegExp('bt|www.baidu.com|www.google.co|dmm.co.jp|jav', 'gi'); //文字
  if (URL_span.test(URL)) {
    var div_span = 'div.c-abstract,h3 a,h3.r a,span.st,a.tag,div.file,div.tags-box+h3,table.mg-b20 tbody td,td.torrent_name a,pre.snippet,h1';
    /*
  百度：div.c-abstract,h3 a
  谷歌：h3.r a,span.st
  BTSOW：a.tag,div.file
  DMM:table.mg-b20 tbody td
  BTDIGG:td.torrent_name a,pre.snippet
  *:h1
  */
    var span = document.querySelectorAll(div_span);
    //console.log(span);
  }
  var URL_href = new RegExp('www.caribbeancom.com', 'gi'); //链接
  if (URL_href.test(URL)) {
    var div_href = '.list-area a>img,#slider-recom a img,#slider-rank a img,#slider-latest a img,.w-940 a img,#main-content a img'; //Carib
    var href = document.querySelectorAll(div_href);
    console.log(href);
  }
  for (num0 = 0; num0 < Code_All.length; num0++) {
    var Code = new Array();
    Code = Code_All[num0].toLowerCase().split('|');
    for (var i = 0; i < Code.length; i++) { //删除空元素
      if (Code[i] == '' || typeof (Code[i]) == 'undefined') {
        Code.splice(i, 1);
        i = i - 1;
      }
    }
    var img_status_1 = img_status_All[num0];
    img_status = 'https://raw.githubusercontent.com/dodying/HentaiVersePlus/master/HV/Temp/' + img_status_1 + '.png';
    var span_status = span_status_All[num0];
    var href_status = href_status_All[num0];
    for (num1 = 0; num1 < Code.length; num1++) {
      var Code_Find = new Array();
      Code_Find = Code[num1].toLowerCase().split('-');
      var OK_0 = '';
      for (i = 0; i < Code_Find.length; i++) {
        OK_0 += '1';
      }
      if (URL_img.test(URL)) {
        for (num2 = 0; num2 < img.length; num2++) {
          var ok = '';
          if (num0 == 3) {
            var img_2 = img[num2].getAttribute('alt') || '';
          } else {
            var img_1 = img[num2].getAttribute('blocksrc') || img[num2].getAttribute('src');
            var img_2 = img_1.toLowerCase().replace(/http:\/\/(pics|p)\.dmm\.(co\.jp|com).*\//, '');
          }
          for (num3 = 0; num3 < Code_Find.length; num3++) {
            if (img_2.indexOf(Code_Find[num3]) >= 0) {
              ok += '1';
              if (ok == OK_0) {
                img[num2].setAttribute('blocksrc', img_1);
                img[num2].setAttribute('src', img_status);
              }
            }
          }
        }
      }
      if (URL_span.test(URL)) {
        for (num4 = 0; num4 < span.length; num4++) {
          var ok = '';
          var span_1 = span[num4].innerHTML.toLowerCase();
          for (num5 = 0; num5 < Code_Find.length; num5++) {
            if (span_1.indexOf(Code_Find[num5]) >= 0) {
              ok += '1';
              if (ok == OK_0) {
                var Code_Find_RegExp = new RegExp(Code_Find[num5 - 1], 'gi');
                var style = '';
                span[num4].innerHTML = span[num4].innerHTML.replace(Code_Find_RegExp, style + Code_Find[num5 - 1].toUpperCase() + '').replace(Code_Find[num5], style + Code_Find[num5] + '');
              }
            }
          }
        }
      }
      if (URL_href.test(URL)) {
        //console.log('href.length=' + href.length);
        for (num6 = 0; num6 < href.length; num6++) {
          var ok = '';
          var href_1 = href[num6].parentNode.getAttribute('href').toLowerCase();
          //console.log('href[' + num6 + ']=' + href_1)
          for (num7 = 0; num7 < Code_Find.length; num7++) {
            if (href_1.indexOf(Code_Find[num7]) >= 0) {
              ok += '1';
              if (ok == OK_0) {
                //console.log('OK')
                //href[num6].setAttribute('href', href_1 + href_status);
                //if (href[num6].querySelector('img')) {
                var img_1 = href[num6].getAttribute('src');
                href[num6].setAttribute('blocksrc', img_1);
                href[num6].setAttribute('src', img_status);
                //}
              }
            }
          }
        }
      }
    }
  }
  document.querySelector('#QuickButton_Switch img').src = 'https://cdn1.iconfinder.com/data/icons/ui-icons-2/512/checkbox-on-green-01-24.png';
  if (document.title.indexOf('BTSOW') >= 0) {
    document.querySelector('#QuickButton_Search').style.display = 'none';
  }
  if (GM_getValue('NewAdd', '') != '' || GM_getValue('NewDelete', '') != '') {
    document.querySelector('#QuickButton_Apply').style.display = 'inline';
  }
}
function TurnOffBlock() {
  var img = document.querySelectorAll('img');
  for (var i = 0; i < img.length; i++) {
    var img_url = img[i].getAttribute('blocksrc') || '';
    if (img_url != '') {
      img[i].setAttribute('src', img_url);
      img[i].removeAttribute('blocksrc');
    }
  }
}
function CodeTry(URL) {
  switch (window.location.host) {
    case 'www.dmm.co.jp':
      if (URL.toUpperCase().match(/[a-zA-Z]+(\-|)[0-9]+/)) {
        var Code_Try = URL.toUpperCase().match(/[a-zA-Z]+(\-|)[0-9]+/) [0];
      } else {
        var Code_Try = URL;
      }
      break;
    case 'btio.pw':
      var Code_Try = URL.replace(/.*search\//, '');
      break;
    case 'www.caribbeancom.com':
      var Code_Try = URL.replace(/.*moviepages\/(.*)\/index.html/, 'Carib-$1');
      break;
    case 'www.heyzo.com':
      var Code_Try = URL.replace(/.*moviepages\/(.*)\/index.html/, 'Heyzo-$1');
      break;
  }
  return Code_Try;
}
<commit_msg>Delete hBlockOwnedAV.user.js<commit_after><|endoftext|>


<commit_before>"use strict";
var socket;
var mapper;
function main() {
    socket = io();
    mapper = Mapper.init(document.getElementById('mapCard'));
    socket.on('connected', function (users) {
        socket.emit('subscribe', users[users.length-1]);
    });
    socket.on('newPacket', function (packet) {
        console.log(packet);
        mapper.addPackets([packet]);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });

    socket.on('newPackets', function (packets) {
        console.log(packets);
        mapper.addPackets(packets);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });
}
<commit_msg>Update crooz.js<commit_after>"use strict";
var socket;
var mapper;
function main() {
    socket = io();
    mapper = Mapper.init(document.getElementById('mapCard'));
    socket.on('connected', function (users) {
        socket.emit('subscribe', users[users.length-1]);
        console.log(users);
    });
    socket.on('newPacket', function (packet) {
        console.log(packet);
        mapper.addPackets([packet]);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });

    socket.on('newPackets', function (packets) {
        console.log(packets);
        mapper.addPackets(packets);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });
}
<|endoftext|>


<commit_before>// ==========================================================================
//
//  Author:   jsandoe
//
//  Copyright (c) 2017 by The Concord Consortium, Inc. All rights reserved.
//
//  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.
// ==========================================================================
/**
 * @class  DG.Notification - Broadcasts notifications to Data Interactive
 * Plugins with active DI-API channels.
 *
 * @extends SC.Object
 */
DG.NotificationManager = SC.Object.extend(/** @scope DG.NotificationManager.prototype */
(function () {
  /**
   * Returns a list of active channels
   * @param document {DG.DocumentController}
   */
  function findActiveChannels (document) {
    var gameControllers = document.get('dataInteractives');
    var channels = gameControllers.filter(function (gameController) {
      return gameController.get('isUsingDataInteractiveChannel');
    }).map(function (gameController) {
      return gameController.get('activeChannel');
    });
    // If we have embeddedMode handlers return any active ones.
    if (DG.embeddedModePhoneHandlers) {
      DG.embeddedModePhoneHandlers.forEach(function (handler) {
        if (handler.get('isPhoneInUse')) {
          channels.push(handler);
        }
      });
    }
    return channels;
  }

  return {

    /**
     * Stashed as part of contextDataDidChange for later retrieval by observers such as maps
     * @property [Object]
     */
    mostRecentDataContextChanges: null,

    init: function () {
      sc_super();
      this.invokeLater(function () {
        if (!this.isDestroyed) {
          // Because we're in an invokeLater, we might already have been destroyed
          var contexts = DG.currDocumentController().get('contexts');

          contexts.forEach(function (context) {
            this.guaranteeDataContextObserver(context);
          }.bind(this));
          DG.currDocumentController().addObserver('contextsLength', this, this.contextCountDidChange);
        }

      }, 200);
    },
    destroy: function () {
      var contexts = DG.currDocumentController().get('contexts');
      contexts.forEach(function (context) {
        this.removeDataContextObserver(context);
      }.bind(this));
      DG.currDocumentController().removeObserver('contextsLength', this, this.contextCountDidChange);
      sc_super();
    },

    /**
     * Sends a notification to all active channels
     * @param message {Object} A serializable object.
     * @param callback {Function}
     */
    sendNotification: function (message, callback) {
      var activeChannels = findActiveChannels(DG.currDocumentController());
      activeChannels.forEach(function (channel) {
        channel.sendMessage(message, callback);
      });
    },

    sendChannelNotification: function (gameController, message, callback) {
      var channel = gameController.get('activeChannel');
      if (channel) {
        channel.sendMessage(message, callback);
      } else {
        DG.logWarn("NotificationManager.sendChannelNotification to unknown plugin");
      }
    },

    contextCountDidChange: function () {
      DG.log('contextCountDidChange');
      // re-add observers for all data contexts
      DG.currDocumentController().contexts.forEach(function (context){
        this.guaranteeDataContextObserver(context);
      }.bind(this));

      // send notification to DI
      this.sendNotification({
        action: 'notify',
        resource: 'documentChangeNotice',
        values: {
          operation: 'dataContextCountChanged'
        }
      }, function (response) {
        DG.log('Sent documentChangeNotice to Data Interactive');
        DG.log('Response: ' + JSON.stringify(response));
      });
    },

    guaranteeDataContextObserver: function (iDataContext) {
      if (!iDataContext.hasObserverFor('changeCount', this, this.contextDataDidChange)) {
        iDataContext.addObserver('changeCount', this, this.contextDataDidChange);
      }
    },

    removeDataContextObserver: function (iDataContext) {
      iDataContext.removeObserver('changeCount', this, this.contextDataDidChange);
    },

    /**
     * Called in response to data context change notices. We will filter out
     * changes that this object originated and those that were marked
     * unsuccessful. Then we will abstract the original change notice by
     * extracting what may be needed at a bare minimum for the DI to determine
     * their response to the notice.
     *
     * @param {@DG.DataContext} dataContext
     */
    contextDataDidChange: function (dataContext) {
      var dataContextName = dataContext.get('name');

      var originalChanges = dataContext.get('newChanges');

      var activeChannels = findActiveChannels(DG.currDocumentController());

      activeChannels.forEach(function (channel) {
        var changes = originalChanges.filter(function (iChange) {
          // filter out unsuccessful change attempts and those with
          // a requester that matches the channel handler.
          return ((iChange.result && iChange.result.success) &&
          (!iChange.requester || (iChange.requester !== channel.get('id'))));
        }.bind(channel)).map(function (iChange) {
          // fix up change objects by copying through certain result properties
          // and converting objects to their id.
          var result = {};
          DG.ObjectMap.forEach(iChange.result, function (k, v) {
            switch (k) {
              case 'success':
              case 'properties':
              case 'attrIDs':
              case 'caseID':
              case 'caseIDs':
              case 'itemID':
              case 'itemIDs':
                result[k] = v;
                break;
              case 'collection':
                result[k] = v.get('id');
                result.name = iChange.properties.name;
                result.attribute = (iChange.attributes && iChange.attributes.length > 0) ?
                    iChange.attributes[0].get('name') : null;
                break;
              case 'attrs':
                // return archivable attribute descriptors rather DG.Attributes
                result[k] = v && v.map(function(attr) {
                  return DG.DataInteractiveUtils.getAttributeProperties(attr);
                });
                break;
              default:
                DG.log('unhandled result property: ' + k );
            }
          });
          if (iChange.cases) {
            result.cases = [];
            result.extend = iChange.extend;
            (iChange.cases).forEach(function (iCase) {
              if( iCase._isProtoCase)
                return; // In rare situation got here and what follows causes exception
              var values = {};

              iCase.collection.attrs.forEach(function (attr) {
                values[attr.name] = iCase.getValue(attr.id);
              });

              result.cases.push({
                id: iCase.id,
                parent : iCase.parent && iCase.parent.id,
                context: {
                  id: iCase.collection.context.id,
                  name: iCase.collection.context.name
                },
                collection: {
                  id: iCase.collection.id,
                  name: iCase.collection.name,
                  parent: iCase.collection.parent ? {
                        id: iCase.collection.parent.id,
                        name: iCase.collection.parent.name
                      } : null
                },
                values: values
              });
            });
          }

          return {operation: iChange.operation, result: result};
        }); // end of map

        if (!changes || changes.length === 0) {
          return;
        }

        channel.sendMessage({
          action: 'notify',
          resource: 'dataContextChangeNotice[' + dataContextName + ']',
          values: changes
        }, function (response) {
          DG.log('Sent dataContextChangeNotice to Data Interactive for dataContext: '
              + dataContextName + ': ' + JSON.stringify(changes));
          DG.log('Response: ' + JSON.stringify(response));
        });
      });

      this.set('mostRecentDataContextChanges', originalChanges);
    },

    notifyLogMessageSubscribers: function (iValues) {
      // shortcut if no listeners are registered
      var logMonitors = DG.currDocumentController().dataInteractiveLogMonitor.get("logMonitors");
      if (logMonitors.length === 0) {
        return;
      }

      var values = {};
      Object.keys(iValues).forEach(function (key) {
        values[key] = iValues[key];
      });
      values.message = SC.String.fmt(iValues.formatStr, iValues.replaceArgs);

      logMonitors.forEach(function (logMonitor) {
        var logMonitorValues = logMonitor.values;
        logMonitorValues = SC.merge({
          topicMatches: logMonitorValues.topic && (logMonitorValues.topic === iValues.topic),
          topicPrefixMatches: logMonitorValues.topicPrefix && iValues.topic && (logMonitorValues.topicPrefix === iValues.topic.substr(0, logMonitorValues.topicPrefix.length)),
          formatStrMatches: logMonitorValues.formatStr && (logMonitorValues.formatStr === iValues.formatStr),
          formatPrefixMatches: logMonitorValues.formatPrefix && iValues.formatStr && (logMonitorValues.formatPrefix === iValues.formatStr.substr(0, logMonitorValues.formatPrefix.length)),
          messageMatches: logMonitorValues.message &&
            ((logMonitorValues.message === values.message)||
                (logMonitorValues.message === "*"))
        }, logMonitorValues);
        if (logMonitorValues.topicMatches || logMonitorValues.topicPrefixMatches ||
            logMonitorValues.formatStrMatches || logMonitorValues.formatPrefixMatches || logMonitorValues.messageMatches) {
          values.logMonitor = logMonitorValues;
          logMonitor.iPhoneHandler.sendMessage({
            action: "notify",
            resource: "logMessageNotice",
            values: values
          });
        }
      }.bind(this));
    },

    /**
     * Used when a plugin requests document state. We can't send it synchronously as a reply, so we call
     * this method to send it to all subscribers.
     */
    sendDocumentToSubscribers: function() {
      var activeChannels = findActiveChannels(DG.currDocumentController()),
          documentSubscribers;
      documentSubscribers = activeChannels.filter( function( iChannel) {
        return iChannel.getPath('controller.contentView.model.subscribeToDocuments');
      });
      if (documentSubscribers.length > 0) {
        DG.currDocumentController().captureCurrentDocumentState(true /* fullData */).then(function (value) {
          documentSubscribers.forEach( function( iSubscriber) {
            iSubscriber.sendMessage({
              action: 'notify',
              resource: 'document',
              values: {
                operation: 'newDocumentState',
                state: value
              }
            });
          });
        });
      }
    }
  };

})());
<commit_msg>[#181799667] With Markov plugin present, drag attribute crashes CODAP<commit_after>// ==========================================================================
//
//  Author:   jsandoe
//
//  Copyright (c) 2017 by The Concord Consortium, Inc. All rights reserved.
//
//  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.
// ==========================================================================
/**
 * @class  DG.Notification - Broadcasts notifications to Data Interactive
 * Plugins with active DI-API channels.
 *
 * @extends SC.Object
 */
DG.NotificationManager = SC.Object.extend(/** @scope DG.NotificationManager.prototype */
(function () {
  /**
   * Returns a list of active channels
   * @param document {DG.DocumentController}
   */
  function findActiveChannels (document) {
    var gameControllers = document.get('dataInteractives');
    var channels = gameControllers.filter(function (gameController) {
      return gameController.get('isUsingDataInteractiveChannel');
    }).map(function (gameController) {
      return gameController.get('activeChannel');
    });
    // If we have embeddedMode handlers return any active ones.
    if (DG.embeddedModePhoneHandlers) {
      DG.embeddedModePhoneHandlers.forEach(function (handler) {
        if (handler.get('isPhoneInUse')) {
          channels.push(handler);
        }
      });
    }
    return channels;
  }

  return {

    /**
     * Stashed as part of contextDataDidChange for later retrieval by observers such as maps
     * @property [Object]
     */
    mostRecentDataContextChanges: null,

    init: function () {
      sc_super();
      this.invokeLater(function () {
        if (!this.isDestroyed) {
          // Because we're in an invokeLater, we might already have been destroyed
          var contexts = DG.currDocumentController().get('contexts');

          contexts.forEach(function (context) {
            this.guaranteeDataContextObserver(context);
          }.bind(this));
          DG.currDocumentController().addObserver('contextsLength', this, this.contextCountDidChange);
        }

      }, 200);
    },
    destroy: function () {
      var contexts = DG.currDocumentController().get('contexts');
      contexts.forEach(function (context) {
        this.removeDataContextObserver(context);
      }.bind(this));
      DG.currDocumentController().removeObserver('contextsLength', this, this.contextCountDidChange);
      sc_super();
    },

    /**
     * Sends a notification to all active channels
     * @param message {Object} A serializable object.
     * @param callback {Function}
     */
    sendNotification: function (message, callback) {
      var activeChannels = findActiveChannels(DG.currDocumentController());
      activeChannels.forEach(function (channel) {
        if (channel.sendMessage) {
          channel.sendMessage(message, callback);
        }
      });
    },

    sendChannelNotification: function (gameController, message, callback) {
      var channel = gameController.get('activeChannel');
      if (channel) {
        if (channel.sendMessage) {
          channel.sendMessage(message, callback);
        }
      } else {
        DG.logWarn("NotificationManager.sendChannelNotification to unknown plugin");
      }
    },

    contextCountDidChange: function () {
      DG.log('contextCountDidChange');
      // re-add observers for all data contexts
      DG.currDocumentController().contexts.forEach(function (context){
        this.guaranteeDataContextObserver(context);
      }.bind(this));

      // send notification to DI
      this.sendNotification({
        action: 'notify',
        resource: 'documentChangeNotice',
        values: {
          operation: 'dataContextCountChanged'
        }
      }, function (response) {
        DG.log('Sent documentChangeNotice to Data Interactive');
        DG.log('Response: ' + JSON.stringify(response));
      });
    },

    guaranteeDataContextObserver: function (iDataContext) {
      if (!iDataContext.hasObserverFor('changeCount', this, this.contextDataDidChange)) {
        iDataContext.addObserver('changeCount', this, this.contextDataDidChange);
      }
    },

    removeDataContextObserver: function (iDataContext) {
      iDataContext.removeObserver('changeCount', this, this.contextDataDidChange);
    },

    /**
     * Called in response to data context change notices. We will filter out
     * changes that this object originated and those that were marked
     * unsuccessful. Then we will abstract the original change notice by
     * extracting what may be needed at a bare minimum for the DI to determine
     * their response to the notice.
     *
     * @param {@DG.DataContext} dataContext
     */
    contextDataDidChange: function (dataContext) {
      var dataContextName = dataContext.get('name');

      var originalChanges = dataContext.get('newChanges');

      var activeChannels = findActiveChannels(DG.currDocumentController());

      activeChannels.forEach(function (channel) {
        var changes = originalChanges.filter(function (iChange) {
          // filter out unsuccessful change attempts and those with
          // a requester that matches the channel handler.
          return ((iChange.result && iChange.result.success) &&
          (!iChange.requester || (iChange.requester !== channel.get('id'))));
        }.bind(channel)).map(function (iChange) {
          // fix up change objects by copying through certain result properties
          // and converting objects to their id.
          var result = {};
          DG.ObjectMap.forEach(iChange.result, function (k, v) {
            switch (k) {
              case 'success':
              case 'properties':
              case 'attrIDs':
              case 'caseID':
              case 'caseIDs':
              case 'itemID':
              case 'itemIDs':
                result[k] = v;
                break;
              case 'collection':
                result[k] = v.get('id');
                result.name = iChange.properties.name;
                result.attribute = (iChange.attributes && iChange.attributes.length > 0) ?
                    iChange.attributes[0].get('name') : null;
                break;
              case 'attrs':
                // return archivable attribute descriptors rather DG.Attributes
                result[k] = v && v.map(function(attr) {
                  return DG.DataInteractiveUtils.getAttributeProperties(attr);
                });
                break;
              default:
                DG.log('unhandled result property: ' + k );
            }
          });
          if (iChange.cases) {
            result.cases = [];
            result.extend = iChange.extend;
            (iChange.cases).forEach(function (iCase) {
              if( iCase._isProtoCase)
                return; // In rare situation got here and what follows causes exception
              var values = {};

              iCase.collection.attrs.forEach(function (attr) {
                values[attr.name] = iCase.getValue(attr.id);
              });

              result.cases.push({
                id: iCase.id,
                parent : iCase.parent && iCase.parent.id,
                context: {
                  id: iCase.collection.context.id,
                  name: iCase.collection.context.name
                },
                collection: {
                  id: iCase.collection.id,
                  name: iCase.collection.name,
                  parent: iCase.collection.parent ? {
                        id: iCase.collection.parent.id,
                        name: iCase.collection.parent.name
                      } : null
                },
                values: values
              });
            });
          }

          return {operation: iChange.operation, result: result};
        }); // end of map

        if (!changes || changes.length === 0) {
          return;
        }

        channel.sendMessage({
          action: 'notify',
          resource: 'dataContextChangeNotice[' + dataContextName + ']',
          values: changes
        }, function (response) {
          DG.log('Sent dataContextChangeNotice to Data Interactive for dataContext: '
              + dataContextName + ': ' + JSON.stringify(changes));
          DG.log('Response: ' + JSON.stringify(response));
        });
      });

      this.set('mostRecentDataContextChanges', originalChanges);
    },

    notifyLogMessageSubscribers: function (iValues) {
      // shortcut if no listeners are registered
      var logMonitors = DG.currDocumentController().dataInteractiveLogMonitor.get("logMonitors");
      if (logMonitors.length === 0) {
        return;
      }

      var values = {};
      Object.keys(iValues).forEach(function (key) {
        values[key] = iValues[key];
      });
      values.message = SC.String.fmt(iValues.formatStr, iValues.replaceArgs);

      logMonitors.forEach(function (logMonitor) {
        var logMonitorValues = logMonitor.values;
        logMonitorValues = SC.merge({
          topicMatches: logMonitorValues.topic && (logMonitorValues.topic === iValues.topic),
          topicPrefixMatches: logMonitorValues.topicPrefix && iValues.topic && (logMonitorValues.topicPrefix === iValues.topic.substr(0, logMonitorValues.topicPrefix.length)),
          formatStrMatches: logMonitorValues.formatStr && (logMonitorValues.formatStr === iValues.formatStr),
          formatPrefixMatches: logMonitorValues.formatPrefix && iValues.formatStr && (logMonitorValues.formatPrefix === iValues.formatStr.substr(0, logMonitorValues.formatPrefix.length)),
          messageMatches: logMonitorValues.message &&
            ((logMonitorValues.message === values.message)||
                (logMonitorValues.message === "*"))
        }, logMonitorValues);
        if (logMonitorValues.topicMatches || logMonitorValues.topicPrefixMatches ||
            logMonitorValues.formatStrMatches || logMonitorValues.formatPrefixMatches || logMonitorValues.messageMatches) {
          values.logMonitor = logMonitorValues;
          logMonitor.iPhoneHandler.sendMessage({
            action: "notify",
            resource: "logMessageNotice",
            values: values
          });
        }
      }.bind(this));
    },

    /**
     * Used when a plugin requests document state. We can't send it synchronously as a reply, so we call
     * this method to send it to all subscribers.
     */
    sendDocumentToSubscribers: function() {
      var activeChannels = findActiveChannels(DG.currDocumentController()),
          documentSubscribers;
      documentSubscribers = activeChannels.filter( function( iChannel) {
        return iChannel.getPath('controller.contentView.model.subscribeToDocuments');
      });
      if (documentSubscribers.length > 0) {
        DG.currDocumentController().captureCurrentDocumentState(true /* fullData */).then(function (value) {
          documentSubscribers.forEach( function( iSubscriber) {
            iSubscriber.sendMessage({
              action: 'notify',
              resource: 'document',
              values: {
                operation: 'newDocumentState',
                state: value
              }
            });
          });
        });
      }
    }
  };

})());
<|endoftext|>


<commit_before>var mongoose = require('../libs/mongoose');
var Module = require('../models/module').Module;
var Page = require('../models/page').Page;
var log = require('../libs/log')(module);

exports.getData = function (req, res) {
    parsePages(function (err, wavedata) {
        if (err) throw err;
        res.json(wavedata);
    });
}

function waveData() {
    this.waves = [
        {
            moduleGroup: [
                {
                    module: [
                        {
                            cloudApp: [
                                {
                                    progress: 0,
                                    reportedSP: 0,
                                    summarySP: 0,
                                    name: "",
                                    uri: "",
                                    status: "",
                                    blocked: false,
                                    accepted: false,
                                    readyForAcceptance: false,
                                    readyForQA: false
                                }
                            ],
                            reportedSP: 0,
                            summarySP: 0,
                            progress: 0,
                            name: "",
                            uri: ""
                        }
                    ],
                    reportedSP: 0,
                    summarySP: 0,
                    progress: 0,
                    name: "",
                    uri: ""
                }
            ],
            reportedSP: 0,
            summarySP: 0,
            progress: 0,
            name: "",
            uri: ""
        }
    ];
}

function getModuleGroupName(labels) {
    var index = labels.indexOf("PageModuleGroup_");
    if(index < 0) {
        return "UnknownModuleGroup";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index+16,index2);
}

function getModuleName(labels) {
    var index = labels.indexOf("PageModule_");
    if(index < 0) {
        return "UnknownModule";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index+11,index2);
}

function getCloudAppName(labels) {
    var indexpp = labels.indexOf("CloudApp_ParentPage");
    var index = labels.indexOf("CloudApp_");
    if(indexpp > -1 && indexpp == index) {
        index = labels.indexOf("CloudApp_", indexpp+1);
    }
    if(index < 0) {
        return "UnknownCloudApp";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index+9,index2);
}

function getWaveName(labels) {
    var index = labels.indexOf("Wave");
    if(index < 0) {
        return "UnknownWave";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index,index2);
}

function SortData(wavedata) {
    wavedata.waves.sort(function (a, b) {
        a = a.name;
        b = b.name;
        return a > b ? 1 : a < b ? -1 : 0;
    });

    for (var i = 0; i < wavedata.waves.length; i++) {
        wavedata.waves[i].moduleGroup.sort(function (a, b) {
            a = a.name;
            b = b.name;
            return a > b ? 1 : a < b ? -1 : 0;
        });
        for (var j = 0; j < wavedata.waves[i].moduleGroup.length; j++) {
            wavedata.waves[i].moduleGroup[j].module.sort(function (a, b) {
                a = a.name;
                b = b.name;
                return a > b ? 1 : a < b ? -1 : 0;
            });
            for (var k = 0; k < wavedata.waves[i].moduleGroup[j].module.length; k++) {
                wavedata.waves[i].moduleGroup[j].module[k].cloudApp.sort(function (a, b) {
                    a = a.name;
                    b = b.name;
                    return a > b ? 1 : a < b ? -1 : 0;
                });
            }
        }
    }
}
function parsePages(callback) {
    var wavedata = new waveData();
    wavedata.waves = [];

    Page.find({}).exec(function (err, pages) {
        for (var i = 0; i < pages.length; i++) {
            var page = pages[i];
            var storyPoints = page.storyPoints == null ? 0 : parseFloat(page.storyPoints);
            var moduleGroup = getModuleGroupName(page.labels);
            var moduleName = getModuleName(page.labels);
            var cloudApp = getCloudAppName(page.labels);
            var wave = getWaveName(page.labels);
            var progress = 0;
            var status = page.status;

            for (var j = 0; j < page.progressHistory.length; j++) {
                var history = page.progressHistory[j];
                var to = history.progressTo == null || history.progressTo == '' ? 0 : parseInt(history.progressTo);
                if(to > progress) {
                    progress = to;
                }
            }
            var calcStoryPoints = storyPoints * progress / 100;

            putDataPoint(wavedata, wave, moduleGroup, moduleName, cloudApp, calcStoryPoints, storyPoints, status);
        }
        SortData(wavedata);
        callback(err, wavedata);
    })
}

function putDataPoint(wavedata, wave, moduleGroup, moduleName, cloudApp, calcStoryPoints, storyPoints, status) {
    var initUri = "https://jira.epam.com/jira/issues/?jql=project%20%3D%20PLEX-UXC%20and%20issuetype%3DStory%20AND%20%22Story%20Points%22%20%3E%200%20and%20labels%20in%20(";
    //wave

    var waved;
    for (var k = 0; k < wavedata.waves.length; k++) {
        if (wavedata.waves[k].name == wave) {
            waved = wavedata.waves[k];
            break;
        }
    }
    if(!waved) {
        waved = { moduleGroup: [], progress: 0, reportedSP: 0, summarySP: 0, name: wave };
        wavedata.waves.push(waved);
    }

    waved.reportedSP += calcStoryPoints;
    waved.summarySP += storyPoints;
    waved.progress = waved.reportedSP*100/waved.summarySP;
    waved.uri = initUri + wave + ")";

    //module group
    var moduleGroupd;
    for (var k = 0; k < waved.moduleGroup.length; k++) {
        if (waved.moduleGroup[k].name == moduleGroup) {
            moduleGroupd = waved.moduleGroup[k];
            break;
        }
    }
    if(!moduleGroupd) {
        moduleGroupd = { module: [], progress: 0, reportedSP: 0, summarySP: 0, name: moduleGroup};
        waved.moduleGroup.push(moduleGroupd);
    }

    moduleGroupd.reportedSP += calcStoryPoints;
    moduleGroupd.summarySP += storyPoints;
    moduleGroupd.progress = moduleGroupd.reportedSP*100/moduleGroupd.summarySP;
    moduleGroupd.uri = initUri + "PageModuleGroup_" + moduleGroup + ")";

    //module
    var moduled;
    for (var k = 0; k < moduleGroupd.module.length; k++) {
        if (moduleGroupd.module[k].name == moduleName) {
            moduled = moduleGroupd.module[k];
            break;
        }
    }
    if(!moduled) {
        moduled = { cloudApp: [], progress: 0, reportedSP: 0, summarySP: 0, name: moduleName};
        moduleGroupd.module.push(moduled);
    }

    moduled.reportedSP += calcStoryPoints;
    moduled.summarySP += storyPoints;
    moduled.progress = moduled.reportedSP*100/moduled.summarySP;
    moduled.uri = initUri + "PageModule_" + moduleName + ") AND labels in(PageModuleGroup_" + moduleGroup+ ")";

    //Cloud App
    var cloudAppd;
    for (var k = 0; k < moduled.cloudApp.length; k++) {
        if (moduled.cloudApp[k].name == cloudApp) {
            cloudAppd = moduled.cloudApp[k];
            break;
        }
    }
    if(!cloudAppd) {
        cloudAppd = { progress: 0, reportedSP: 0, summarySP: 0, name: cloudApp,
            status: status == 'Closed' ? "Accepted" : status,
            accepted: status == 'Closed',
            readyForAcceptance: status == 'Resolved',
            readyForQA: status == 'Ready for QA' || status == "Testing in Progress",
            blocked: status == 'Blocked'
        };
        moduled.cloudApp.push(cloudAppd);
    }

    cloudAppd.reportedSP += calcStoryPoints;
    cloudAppd.summarySP += storyPoints;
    cloudAppd.progress = cloudAppd.reportedSP*100/cloudAppd.summarySP;
    cloudAppd.uri = initUri + "CloudApp_" + cloudApp + ") AND labels in(PageModuleGroup_" + moduleGroup + ") AND labels in(PageModule_" + moduleName + ")";
    if(!(status == "Closed" && cloudAppd.status == "Accepted") && status != cloudAppd.status) {
        cloudAppd.accepted = false;
        cloudAppd.readyForAcceptance = false;
        cloudAppd.readyForQA = false;
        cloudAppd.blocked = cloudAppd.blocked || status == "Blocked";
        cloudAppd.status = cloudAppd.blocked ? "Blocked" : "";
    }
}
<commit_msg>changed behavior on determining state of the cloud app<commit_after>var mongoose = require('../libs/mongoose');
var Module = require('../models/module').Module;
var Page = require('../models/page').Page;
var log = require('../libs/log')(module);

exports.getData = function (req, res) {
    parsePages(function (err, wavedata) {
        if (err) throw err;
        res.json(wavedata);
    });
}

function waveData() {
    this.waves = [
        {
            moduleGroup: [
                {
                    module: [
                        {
                            cloudApp: [
                                {
                                    progress: 0,
                                    reportedSP: 0,
                                    summarySP: 0,
                                    name: "",
                                    uri: "",
                                    status: "",
                                    blocked: false,
                                    accepted: false,
                                    readyForAcceptance: false,
                                    readyForQA: false
                                }
                            ],
                            reportedSP: 0,
                            summarySP: 0,
                            progress: 0,
                            name: "",
                            uri: ""
                        }
                    ],
                    reportedSP: 0,
                    summarySP: 0,
                    progress: 0,
                    name: "",
                    uri: ""
                }
            ],
            reportedSP: 0,
            summarySP: 0,
            progress: 0,
            name: "",
            uri: ""
        }
    ];
}

function getModuleGroupName(labels) {
    var index = labels.indexOf("PageModuleGroup_");
    if(index < 0) {
        return "UnknownModuleGroup";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index+16,index2);
}

function getModuleName(labels) {
    var index = labels.indexOf("PageModule_");
    if(index < 0) {
        return "UnknownModule";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index+11,index2);
}

function getCloudAppName(labels) {
    var indexpp = labels.indexOf("CloudApp_ParentPage");
    var index = labels.indexOf("CloudApp_");
    if(indexpp > -1 && indexpp == index) {
        index = labels.indexOf("CloudApp_", indexpp+1);
    }
    if(index < 0) {
        return "UnknownCloudApp";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index+9,index2);
}

function getWaveName(labels) {
    var index = labels.indexOf("Wave");
    if(index < 0) {
        return "UnknownWave";
    }
    var index2 = labels.indexOf(',', index);
    if(index2 < 0) {
        index2 = labels.length;
    }

    return labels.substring(index,index2);
}

function SortData(wavedata) {
    wavedata.waves.sort(function (a, b) {
        a = a.name;
        b = b.name;
        return a > b ? 1 : a < b ? -1 : 0;
    });

    for (var i = 0; i < wavedata.waves.length; i++) {
        wavedata.waves[i].moduleGroup.sort(function (a, b) {
            a = a.name;
            b = b.name;
            return a > b ? 1 : a < b ? -1 : 0;
        });
        for (var j = 0; j < wavedata.waves[i].moduleGroup.length; j++) {
            wavedata.waves[i].moduleGroup[j].module.sort(function (a, b) {
                a = a.name;
                b = b.name;
                return a > b ? 1 : a < b ? -1 : 0;
            });
            for (var k = 0; k < wavedata.waves[i].moduleGroup[j].module.length; k++) {
                wavedata.waves[i].moduleGroup[j].module[k].cloudApp.sort(function (a, b) {
                    a = a.name;
                    b = b.name;
                    return a > b ? 1 : a < b ? -1 : 0;
                });
            }
        }
    }
}
function parsePages(callback) {
    var wavedata = new waveData();
    wavedata.waves = [];

    Page.find({}).exec(function (err, pages) {
        for (var i = 0; i < pages.length; i++) {
            var page = pages[i];
            var storyPoints = page.storyPoints == null ? 0 : parseFloat(page.storyPoints);
            var moduleGroup = getModuleGroupName(page.labels);
            var moduleName = getModuleName(page.labels);
            var cloudApp = getCloudAppName(page.labels);
            var wave = getWaveName(page.labels);
            var progress = 0;
            var status = page.status;

            for (var j = 0; j < page.progressHistory.length; j++) {
                var history = page.progressHistory[j];
                var to = history.progressTo == null || history.progressTo == '' ? 0 : parseInt(history.progressTo);
                if(to > progress) {
                    progress = to;
                }
            }
            var calcStoryPoints = storyPoints * progress / 100;

            putDataPoint(wavedata, wave, moduleGroup, moduleName, cloudApp, calcStoryPoints, storyPoints, status);
        }
        SortData(wavedata);
        callback(err, wavedata);
    })
}

function putDataPoint(wavedata, wave, moduleGroup, moduleName, cloudApp, calcStoryPoints, storyPoints, status) {
    var initUri = "https://jira.epam.com/jira/issues/?jql=project%20%3D%20PLEX-UXC%20and%20issuetype%3DStory%20AND%20%22Story%20Points%22%20%3E%200%20and%20labels%20in%20(";
    //wave

    var waved;
    for (var k = 0; k < wavedata.waves.length; k++) {
        if (wavedata.waves[k].name == wave) {
            waved = wavedata.waves[k];
            break;
        }
    }
    if(!waved) {
        waved = { moduleGroup: [], progress: 0, reportedSP: 0, summarySP: 0, name: wave };
        wavedata.waves.push(waved);
    }

    waved.reportedSP += calcStoryPoints;
    waved.summarySP += storyPoints;
    waved.progress = waved.reportedSP*100/waved.summarySP;
    waved.uri = initUri + wave + ")";

    //module group
    var moduleGroupd;
    for (var k = 0; k < waved.moduleGroup.length; k++) {
        if (waved.moduleGroup[k].name == moduleGroup) {
            moduleGroupd = waved.moduleGroup[k];
            break;
        }
    }
    if(!moduleGroupd) {
        moduleGroupd = { module: [], progress: 0, reportedSP: 0, summarySP: 0, name: moduleGroup};
        waved.moduleGroup.push(moduleGroupd);
    }

    moduleGroupd.reportedSP += calcStoryPoints;
    moduleGroupd.summarySP += storyPoints;
    moduleGroupd.progress = moduleGroupd.reportedSP*100/moduleGroupd.summarySP;
    moduleGroupd.uri = initUri + "PageModuleGroup_" + moduleGroup + ")";

    //module
    var moduled;
    for (var k = 0; k < moduleGroupd.module.length; k++) {
        if (moduleGroupd.module[k].name == moduleName) {
            moduled = moduleGroupd.module[k];
            break;
        }
    }
    if(!moduled) {
        moduled = { cloudApp: [], progress: 0, reportedSP: 0, summarySP: 0, name: moduleName};
        moduleGroupd.module.push(moduled);
    }

    moduled.reportedSP += calcStoryPoints;
    moduled.summarySP += storyPoints;
    moduled.progress = moduled.reportedSP*100/moduled.summarySP;
    moduled.uri = initUri + "PageModule_" + moduleName + ") AND labels in(PageModuleGroup_" + moduleGroup+ ")";

    //Cloud App
    var cloudAppd;
    for (var k = 0; k < moduled.cloudApp.length; k++) {
        if (moduled.cloudApp[k].name == cloudApp) {
            cloudAppd = moduled.cloudApp[k];
            break;
        }
    }
    status = status == 'Closed' ? "Accepted" : status;
    if(!cloudAppd) {
        cloudAppd = { progress: 0, reportedSP: 0, summarySP: 0, name: cloudApp,
            status: status,
            accepted: status == 'Accepted',
            readyForAcceptance: status == 'Resolved',
            readyForQA: status == 'Ready for QA' || status == "Testing in Progress",
            blocked: status == 'Blocked'
        };
        moduled.cloudApp.push(cloudAppd);
    }

    cloudAppd.reportedSP += calcStoryPoints;
    cloudAppd.summarySP += storyPoints;
    cloudAppd.progress = cloudAppd.reportedSP*100/cloudAppd.summarySP;
    cloudAppd.uri = initUri + "CloudApp_" + cloudApp + ") AND labels in(PageModuleGroup_" + moduleGroup + ") AND labels in(PageModule_" + moduleName + ")";
    if(status != cloudAppd.status) {
        if((cloudAppd.status == "Ready for QA" || cloudAppd.status == "Testing in Progress") && status == "Resolved") {
        }
        else if(cloudAppd.status == "Resolved" && (status == "Ready for QA" || status == "Testing in Progress")) {
            cloudAppd.status = "Ready for QA";
            cloudAppd.readyForQA = true;
            cloudAppd.accepted = false;
            cloudAppd.readyForAcceptance = false;
        }
        else {
            cloudAppd.accepted = false;
            cloudAppd.readyForAcceptance = false;
            cloudAppd.readyForQA = false;
            cloudAppd.blocked = cloudAppd.blocked || status == "Blocked";
            cloudAppd.status = cloudAppd.blocked ? "Blocked" : "";
        }
    }
}
<|endoftext|>