<commit_before>/* See license.txt for terms of usage */

define([
    "firebug/firebug",
    "firebug/lib/wrapper",
    "firebug/lib/events",
],
function(Firebug, Wrapper, Events) {

// ********************************************************************************************* //
// Command Line APIs

/**
 * Returns a command line object (bundled with passed window through closure). The object
 * provides all necessary APIs as described here:
 * http://getfirebug.com/wiki/index.php/Command_Line_API
 *
 * @param {Object} context
 * @param {Object} win
 */
function createFirebugCommandLine(context, win)
{
    var contentView = Wrapper.getContentView(win);
    if (!contentView)
    {
        if (FBTrace.DBG_COMMANDLINE || FBTrace.DBG_ERRORS)
            FBTrace.sysout("createFirebugCommandLine ERROR no contentView "+context.getName())
            return null;
    }

    // The commandLine object
    var commandLine = {
        __exposedProps__: {}
    };

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Exposed Properties

    // List of command line APIs
    var commands = ["$", "$$", "$x", "$n", "cd", "clear", "inspect", "keys",
        "values", "debug", "undebug", "monitor", "unmonitor", "traceCalls", "untraceCalls",
        "traceAll", "untraceAll", "monitorEvents", "unmonitorEvents", "profile", "profileEnd",
        "copy", "memoryProfile", "memoryProfileEnd"];

    // Define command line methods
    for (var i=0; i<commands.length; i++)
    {
        var command = commands[i];

        // If the method is already defined, don't override it.
        if (contentView[command])
            continue;

        function createCommandHandler(cmd) {
            return function() {
                return notifyFirebug(arguments, cmd, 'firebugExecuteCommand');
            }
        }

        commandLine[command] = createCommandHandler(command);
        commandLine.__exposedProps__[command] = "r";
    }

    // Define shortcuts for some console methods
    var consoleShortcuts = ["dir", "dirxml", "table"];
    for (var i=0; i<consoleShortcuts.length; i++)
    {
        var command = consoleShortcuts[i];

        // If the method is already defined, don't override it.
        if (contentView[command])
            continue;

        function createShortcutHandler(cmd) {
            return function() {
                return contentView.console[cmd].apply(contentView.console, arguments);
            }
        }

        commandLine[command] = createShortcutHandler(command);
        commandLine.__exposedProps__[command] = "r";
    }

    // Define console variables (inspector history).
    var props = ["$0", "$1"];
    for (var i=0; i<props.length; i++)
    {
        var prop = props[i];
        if (contentView[prop])
            continue;

        function createVariableHandler(prop) {
            return function() {
                return notifyFirebug(arguments, prop, 'firebugExecuteCommand');
            }
        }

        commandLine.__defineGetter__(prop, createVariableHandler(prop));
        commandLine.__exposedProps__[prop] = "r";
    }

    attachCommandLine();

    // xxxHonza: TODO make this private.
    commandLine["detachCommandLine"] = detachCommandLine;
    commandLine.__exposedProps__["detachCommandLine"] = "r";

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Helpers (not accessible from web content)

    function attachCommandLine()
    {
        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed.attachCommandLine; "+window.location);

        if (!contentView.console)
        {
            var console = createFirebugConsole(context, win);
            contentView.console = console;
        }

        Events.addEventListener(contentView.document, "firebugCommandLine", firebugEvalEvent, true);
    }

    function detachCommandLine()
    {
        Events.removeEventListener(contentView.document, "firebugCommandLine", firebugEvalEvent, true);
        delete contentView._FirebugCommandLine; // suicide!

        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed.detachCommandLine; "+window.location);
    }

    function firebugEvalEvent(event)
    {
        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed.firebugEvalEvent "+window.location);

        var expr = contentView.document.getUserData("firebug-expr"); // see commandLine.js
        evaluate(expr);

        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed; did evaluate on "+expr);
    }

    function evaluate(expr)
    {
        try
        {
            var result = contentView.eval(expr);
            notifyFirebug([result], "evaluated", "firebugAppendConsole");
        }
        catch(exc)
        {
            var result = exc;
            result.source = expr;
            notifyFirebug([result], "evaluateError", "firebugAppendConsole");
        }
    }

    function notifyFirebug(objs, methodName, eventID)
    {
        var event = contentView.document.createEvent("Events");
        event.initEvent(eventID, true, false);

        commandLine.userObjects = [];
        for (var i=0; i<objs.length; i++)
            commandLine.userObjects.push(objs[i]);

        var length = commandLine.userObjects.length;
        contentView.document.setUserData("firebug-methodName", methodName, null);

        contentView.document.dispatchEvent(event);

        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed; dispatched event "+methodName+" via "+
                eventID+" with "+objs.length+ " user objects, [0]:"+commandLine.userObjects[0]);

        var result;
        if (contentView.document.getUserData("firebug-retValueType") == "array")
            result = [];

        if (!result && commandLine.userObjects.length == length+1)
            return commandLine.userObjects[length];

        for (var i=length; i<commandLine.userObjects.length && result; i++)
            result.push(commandLine.userObjects[i]);

        return result;
    }

    return commandLine;
};

// ********************************************************************************************* //
// Registration

Firebug.CommandLineExposed =
{
    createFirebugCommandLine: createFirebugCommandLine
};

return Firebug.CommandLineExposed;

// ********************************************************************************************* //
});
<commit_msg>[1.9][&1.8] Issue 4757: var table="" returns an error<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/firebug",
    "firebug/lib/wrapper",
    "firebug/lib/events",
],
function(Firebug, Wrapper, Events) {

// ********************************************************************************************* //
// Command Line APIs

/**
 * Returns a command line object (bundled with passed window through closure). The object
 * provides all necessary APIs as described here:
 * http://getfirebug.com/wiki/index.php/Command_Line_API
 *
 * @param {Object} context
 * @param {Object} win
 */
function createFirebugCommandLine(context, win)
{
    var contentView = Wrapper.getContentView(win);
    if (!contentView)
    {
        if (FBTrace.DBG_COMMANDLINE || FBTrace.DBG_ERRORS)
            FBTrace.sysout("createFirebugCommandLine ERROR no contentView "+context.getName())
            return null;
    }

    // The commandLine object
    var commandLine = {
        __exposedProps__: {}
    };

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Exposed Properties

    // List of command line APIs
    var commands = ["$", "$$", "$x", "$n", "cd", "clear", "inspect", "keys",
        "values", "debug", "undebug", "monitor", "unmonitor", "traceCalls", "untraceCalls",
        "traceAll", "untraceAll", "monitorEvents", "unmonitorEvents", "profile", "profileEnd",
        "copy", "memoryProfile", "memoryProfileEnd"];

    // Define command line methods
    for (var i=0; i<commands.length; i++)
    {
        var command = commands[i];

        // If the method is already defined, don't override it.
        if (contentView[command])
            continue;

        function createCommandHandler(cmd) {
            return function() {
                return notifyFirebug(arguments, cmd, 'firebugExecuteCommand');
            }
        }

        commandLine[command] = createCommandHandler(command);
        commandLine.__exposedProps__[command] = "rw";
    }

    // Define shortcuts for some console methods
    var consoleShortcuts = ["dir", "dirxml", "table"];
    for (var i=0; i<consoleShortcuts.length; i++)
    {
        var command = consoleShortcuts[i];

        // If the method is already defined, don't override it.
        if (contentView[command])
            continue;

        function createShortcutHandler(cmd) {
            return function() {
                return contentView.console[cmd].apply(contentView.console, arguments);
            }
        }

        commandLine[command] = createShortcutHandler(command);
        commandLine.__exposedProps__[command] = "rw";
    }

    // Define console variables (inspector history).
    var props = ["$0", "$1"];
    for (var i=0; i<props.length; i++)
    {
        var prop = props[i];
        if (contentView[prop])
            continue;

        function createVariableHandler(prop) {
            return function() {
                return notifyFirebug(arguments, prop, 'firebugExecuteCommand');
            }
        }

        commandLine.__defineGetter__(prop, createVariableHandler(prop));
        commandLine.__exposedProps__[prop] = "r";
    }

    attachCommandLine();

    // xxxHonza: TODO make this private.
    commandLine["detachCommandLine"] = detachCommandLine;
    commandLine.__exposedProps__["detachCommandLine"] = "r";

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Helpers (not accessible from web content)

    function attachCommandLine()
    {
        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed.attachCommandLine; "+window.location);

        if (!contentView.console)
        {
            var console = createFirebugConsole(context, win);
            contentView.console = console;
        }

        Events.addEventListener(contentView.document, "firebugCommandLine", firebugEvalEvent, true);
    }

    function detachCommandLine()
    {
        Events.removeEventListener(contentView.document, "firebugCommandLine", firebugEvalEvent, true);
        delete contentView._FirebugCommandLine; // suicide!

        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed.detachCommandLine; "+window.location);
    }

    function firebugEvalEvent(event)
    {
        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed.firebugEvalEvent "+window.location);

        var expr = contentView.document.getUserData("firebug-expr"); // see commandLine.js
        evaluate(expr);

        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed; did evaluate on "+expr);
    }

    function evaluate(expr)
    {
        try
        {
            var result = contentView.eval(expr);
            notifyFirebug([result], "evaluated", "firebugAppendConsole");
        }
        catch(exc)
        {
            var result = exc;
            result.source = expr;
            notifyFirebug([result], "evaluateError", "firebugAppendConsole");
        }
    }

    function notifyFirebug(objs, methodName, eventID)
    {
        var event = contentView.document.createEvent("Events");
        event.initEvent(eventID, true, false);

        commandLine.userObjects = [];
        for (var i=0; i<objs.length; i++)
            commandLine.userObjects.push(objs[i]);

        var length = commandLine.userObjects.length;
        contentView.document.setUserData("firebug-methodName", methodName, null);

        contentView.document.dispatchEvent(event);

        if (FBTrace.DBG_COMMANDLINE)
            FBTrace.sysout("commandLine.Exposed; dispatched event "+methodName+" via "+
                eventID+" with "+objs.length+ " user objects, [0]:"+commandLine.userObjects[0]);

        var result;
        if (contentView.document.getUserData("firebug-retValueType") == "array")
            result = [];

        if (!result && commandLine.userObjects.length == length+1)
            return commandLine.userObjects[length];

        for (var i=length; i<commandLine.userObjects.length && result; i++)
            result.push(commandLine.userObjects[i]);

        return result;
    }

    return commandLine;
};

// ********************************************************************************************* //
// Registration

Firebug.CommandLineExposed =
{
    createFirebugCommandLine: createFirebugCommandLine
};

return Firebug.CommandLineExposed;

// ********************************************************************************************* //
});
<|endoftext|>


<commit_before>"use strict"

module.exports = MarketItem;

const SteamCrawler = require('../index');
const Regex = require('../../resources/regex');
const Elem = require('../../resources/elements').MarketItem;
const Endpoint = require('../../resources/endpoint');
const defaultIconSize = '/360fx360f';

function MarketItem($, loadEndpoints) {
    const scripts = $('body script').eq(3).text().toString('utf8');

    this.url = $( Elem.market_hash_name ).last().attr('href');

    this.market_hash_name = decodeURIComponent(this.url).split('/')[6] || null;
    this.market_name = $( Elem.market_name ).text() || $( Elem.market_name_alt ).last().text() || this.market_hash_name;

    this.nameID = Regex.get( Regex.listings.nameID, scripts, 2) || null;
    this.appID = parseInt( this._splitURL(this.url, 5), 10 );

    let image = $( Elem.image ).first().attr('src');
    if(image) image = image.replace(defaultIconSize, '');
    this.image = image || null;

    this.app_context_data = this.setAppContextData( scripts );
    this.assets = this.setAssets( scripts );
    this.median_sale_prices = this.setMedianSalePrices( scripts );

    this.recent_activity = [];
    this.histogram = [];

    if(loadEndpoints && this.nameID) {
        this.getRecentActivity();
        this.getHistogram();
    }
}

MarketItem.prototype.setAppContextData = function(html) {
    const app_context_data = Regex.get( Regex.listings.appContextData, html, 3, true);
    if( ! app_context_data) return {};
    return app_context_data;
}

MarketItem.prototype.setAssets = function(html) {
    const assets = Regex.get( Regex.listings.assets, html, 3, true);
    if( ! assets) return {};
    return assets;
}

MarketItem.prototype.setMedianSalePrices = function(html) {
    if( ! this.nameID) return [];
    const median_sale_prices = Regex.get( Regex.listings.medianSalePrices, html, 2, true );
    if( ! median_sale_prices) return [];
    return median_sale_prices;
}

MarketItem.prototype.getRecentActivity = function(cached, callback) {
    if( ! this.nameID) return callback(new Error('This item has no nameID!'));

    if(typeof cached === "function") {
        callback = cached;
        cached = false;
    }
    if(cached) return callback(null, this.recent_activity);

    let self = this;
    return SteamCrawler.prototype.requestJson( Endpoint.itemordersactivity(this.nameID), (err, data) => {
        self.recent_activity = data;

        if(callback) return callback(err, data);
    });
}

MarketItem.prototype.getHistogram = function(cached, callback) {
    if( ! this.nameID) return callback(new Error('This item has no nameID!'));

    if(typeof cached === "function") {
        callback = cached;
        cached = false;
    }
    if(cached) return callback(null, this.histogram);

    let self = this;
    return SteamCrawler.prototype.requestJson( Endpoint.itemordershistogram(this.nameID), (err, data) => {
        self.histogram = data || [];

        if(callback) return callback(err, data);
    });

}

MarketItem.prototype._splitURL = function(url, index) {
    try {
        return decodeURIComponent(url.split('/')[index]).toString('utf8');
    } catch (e) {
        throw new Error('Failed to decodeURI - malformed response?');
    }
}
<commit_msg>MarketItem market_hash_name use _splitURL<commit_after>"use strict"

module.exports = MarketItem;

const SteamCrawler = require('../index');
const Regex = require('../../resources/regex');
const Elem = require('../../resources/elements').MarketItem;
const Endpoint = require('../../resources/endpoint');
const defaultIconSize = '/360fx360f';

function MarketItem($, loadEndpoints) {
    const scripts = $('body script').eq(3).text().toString('utf8');

    this.url = $( Elem.market_hash_name ).last().attr('href');

    this.market_hash_name = decodeURIComponent(this._splitURL(this.url, 6)) || null;
    this.market_name = $( Elem.market_name ).text() || $( Elem.market_name_alt ).last().text() || this.market_hash_name;

    this.nameID = Regex.get( Regex.listings.nameID, scripts, 2) || null;
    this.appID = parseInt( this._splitURL(this.url, 5), 10 );

    let image = $( Elem.image ).first().attr('src');
    if(image) image = image.replace(defaultIconSize, '');
    this.image = image || null;

    this.app_context_data = this.setAppContextData( scripts );
    this.assets = this.setAssets( scripts );
    this.median_sale_prices = this.setMedianSalePrices( scripts );

    this.recent_activity = [];
    this.histogram = [];

    if(loadEndpoints && this.nameID) {
        this.getRecentActivity();
        this.getHistogram();
    }
}

MarketItem.prototype.setAppContextData = function(html) {
    const app_context_data = Regex.get( Regex.listings.appContextData, html, 3, true);
    if( ! app_context_data) return {};
    return app_context_data;
}

MarketItem.prototype.setAssets = function(html) {
    const assets = Regex.get( Regex.listings.assets, html, 3, true);
    if( ! assets) return {};
    return assets;
}

MarketItem.prototype.setMedianSalePrices = function(html) {
    if( ! this.nameID) return [];
    const median_sale_prices = Regex.get( Regex.listings.medianSalePrices, html, 2, true );
    if( ! median_sale_prices) return [];
    return median_sale_prices;
}

MarketItem.prototype.getRecentActivity = function(cached, callback) {
    if( ! this.nameID) return callback(new Error('This item has no nameID!'));

    if(typeof cached === "function") {
        callback = cached;
        cached = false;
    }
    if(cached) return callback(null, this.recent_activity);

    let self = this;
    return SteamCrawler.prototype.requestJson( Endpoint.itemordersactivity(this.nameID), (err, data) => {
        self.recent_activity = data;

        if(callback) return callback(err, data);
    });
}

MarketItem.prototype.getHistogram = function(cached, callback) {
    if( ! this.nameID) return callback(new Error('This item has no nameID!'));

    if(typeof cached === "function") {
        callback = cached;
        cached = false;
    }
    if(cached) return callback(null, this.histogram);

    let self = this;
    return SteamCrawler.prototype.requestJson( Endpoint.itemordershistogram(this.nameID), (err, data) => {
        self.histogram = data || [];

        if(callback) return callback(err, data);
    });

}

MarketItem.prototype._splitURL = function(url, index) {
    try {
        return decodeURIComponent(url.split('/')[index]).toString('utf8');
    } catch (e) {
        throw new Error('Failed to decodeURI - malformed response?');
    }
}
<|endoftext|>


<commit_before>import { animate } from '../actions/animate'

const Circle = {

  getInitialState() {
    return Circle.set(null, { color: 'orange', time: Date.now() })
  },

  set (_, { color, time }) {
    let sin = Math.sin(time / 200)
    let cos = Math.cos(time / 200)

    return {
      color : color,
      cx    : 50 * sin,
      cy    : 35 * cos,
      r     : 12 + (8 * cos)
    }
  },

  register () {
    return {
      [animate.loadings] : Circle.set,
      [animate.done]    : Circle.set
    }
  }
}

export default Circle
<commit_msg>Remove intentional error added for error reporting.<commit_after>import { animate } from '../actions/animate'

const Circle = {

  getInitialState() {
    return Circle.set(null, { color: 'orange', time: Date.now() })
  },

  set (_, { color, time }) {
    let sin = Math.sin(time / 200)
    let cos = Math.cos(time / 200)

    return {
      color : color,
      cx    : 50 * sin,
      cy    : 35 * cos,
      r     : 12 + (8 * cos)
    }
  },

  register () {
    return {
      [animate.loading] : Circle.set,
      [animate.done]    : Circle.set
    }
  }
}

export default Circle
<|endoftext|>


<commit_before>const createRetry = require('../retry')
const createSocket = require('./socket')
const createRequest = require('../protocol/request')
const Decoder = require('../protocol/decoder')
const { KafkaJSConnectionError, KafkaJSConnectionClosedError } = require('../errors')
const { INT_32_MAX_VALUE } = require('../constants')
const getEnv = require('../env')
const RequestQueue = require('./requestQueue')
const { CONNECTION_STATUS, CONNECTED_STATUS } = require('./connectionStatus')

const requestInfo = ({ apiName, apiKey, apiVersion }) =>
  `${apiName}(key: ${apiKey}, version: ${apiVersion})`

/**
 * @param {string} host
 * @param {number} port
 * @param {Object} logger
 * @param {string} clientId='kafkajs'
 * @param {number} requestTimeout The maximum amount of time the client will wait for the response of a request,
 *                                in milliseconds
 * @param {string} [rack=null]
 * @param {Object} [ssl=null] Options for the TLS Secure Context. It accepts all options,
 *                            usually "cert", "key" and "ca". More information at
 *                            https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options
 * @param {Object} [sasl=null] Attributes used for SASL authentication. Options based on the
 *                             key "mechanism". Connection is not actively using the SASL attributes
 *                             but acting as a data object for this information
 * @param {number} [connectionTimeout=1000] The connection timeout, in milliseconds
 * @param {Object} [retry=null] Configurations for the built-in retry mechanism. More information at the
 *                              retry module inside network
 * @param {number} [maxInFlightRequests=null] The maximum number of unacknowledged requests on a connection before
 *                                            enqueuing
 * @param {InstrumentationEventEmitter} [instrumentationEmitter=null]
 */
module.exports = class Connection {
  constructor({
    host,
    port,
    logger,
    socketFactory,
    requestTimeout,
    rack = null,
    ssl = null,
    sasl = null,
    clientId = 'kafkajs',
    connectionTimeout = 1000,
    enforceRequestTimeout = false,
    maxInFlightRequests = null,
    instrumentationEmitter = null,
    retry = {},
  }) {
    this.host = host
    this.port = port
    this.rack = rack
    this.clientId = clientId
    this.broker = `${this.host}:${this.port}`
    this.logger = logger.namespace('Connection')

    this.socketFactory = socketFactory
    this.ssl = ssl
    this.sasl = sasl

    this.retry = retry
    this.retrier = createRetry({ ...this.retry })
    this.requestTimeout = requestTimeout
    this.connectionTimeout = connectionTimeout

    this.bytesBuffered = 0
    this.bytesNeeded = Decoder.int32Size()
    this.chunks = []

    this.connectionStatus = CONNECTION_STATUS.DISCONNECTED
    this.correlationId = 0
    this.requestQueue = new RequestQueue({
      instrumentationEmitter,
      maxInFlightRequests,
      requestTimeout,
      enforceRequestTimeout,
      clientId,
      broker: this.broker,
      logger: logger.namespace('RequestQueue'),
      isConnected: () => this.connected,
    })

    this.authHandlers = null
    this.authExpectResponse = false

    const log = level => (message, extra = {}) => {
      const logFn = this.logger[level]
      logFn(message, { broker: this.broker, clientId, ...extra })
    }

    this.logDebug = log('debug')
    this.logError = log('error')

    const env = getEnv()
    this.shouldLogBuffers = env.KAFKAJS_DEBUG_PROTOCOL_BUFFERS === '1'
    this.shouldLogFetchBuffer =
      this.shouldLogBuffers && env.KAFKAJS_DEBUG_EXTENDED_PROTOCOL_BUFFERS === '1'
  }

  get connected() {
    return CONNECTED_STATUS.includes(this.connectionStatus)
  }

  /**
   * @public
   * @returns {Promise}
   */
  connect() {
    return new Promise((resolve, reject) => {
      if (this.connected) {
        return resolve(true)
      }

      let timeoutId

      const onConnect = () => {
        clearTimeout(timeoutId)
        this.connectionStatus = CONNECTION_STATUS.CONNECTED
        this.requestQueue.scheduleRequestTimeoutCheck()
        resolve(true)
      }

      const onData = data => {
        this.processData(data)
      }

      const onEnd = async () => {
        clearTimeout(timeoutId)

        const wasConnected = this.connected

        if (this.authHandlers) {
          this.authHandlers.onError()
        } else if (wasConnected) {
          this.logDebug('Kafka server has closed connection')
          this.rejectRequests(
            new KafkaJSConnectionClosedError('Closed connection', {
              host: this.host,
              port: this.port,
            })
          )
        }

        await this.disconnect()
      }

      const onError = async e => {
        clearTimeout(timeoutId)

        const error = new KafkaJSConnectionError(`Connection error: ${e.message}`, {
          broker: `${this.host}:${this.port}`,
          code: e.code,
        })

        this.logError(error.message, { stack: e.stack })
        await this.disconnect()
        this.rejectRequests(error)

        reject(error)
      }

      const onTimeout = async () => {
        const error = new KafkaJSConnectionError('Connection timeout', {
          broker: `${this.host}:${this.port}`,
        })

        this.logError(error.message)
        await this.disconnect()
        this.rejectRequests(error)
        reject(error)
      }

      this.logDebug(`Connecting`, {
        ssl: !!this.ssl,
        sasl: !!this.sasl,
      })

      try {
        timeoutId = setTimeout(onTimeout, this.connectionTimeout)
        this.socket = createSocket({
          socketFactory: this.socketFactory,
          host: this.host,
          port: this.port,
          ssl: this.ssl,
          onConnect,
          onData,
          onEnd,
          onError,
          onTimeout,
        })
      } catch (e) {
        clearTimeout(timeoutId)
        reject(
          new KafkaJSConnectionError(`Failed to connect: ${e.message}`, {
            broker: `${this.host}:${this.port}`,
          })
        )
      }
    })
  }

  /**
   * @public
   * @returns {Promise}
   */
  async disconnect() {
    this.connectionStatus = CONNECTION_STATUS.DISCONNECTING
    this.logDebug('disconnecting...')

    await this.requestQueue.waitForPendingRequests()
    this.requestQueue.destroy()

    if (this.socket) {
      this.socket.end()
      this.socket.unref()
    }

    this.connectionStatus = CONNECTION_STATUS.DISCONNECTED
    this.logDebug('disconnected')
    return true
  }

  /**
   * @public
   * @returns {Promise}
   */
  authenticate({ authExpectResponse = false, request, response }) {
    this.authExpectResponse = authExpectResponse

    /**
     * TODO: rewrite removing the async promise executor
     */

    /* eslint-disable no-async-promise-executor */
    return new Promise(async (resolve, reject) => {
      this.authHandlers = {
        onSuccess: rawData => {
          this.authHandlers = null
          this.authExpectResponse = false

          response
            .decode(rawData)
            .then(data => response.parse(data))
            .then(resolve)
            .catch(reject)
        },
        onError: () => {
          this.authHandlers = null
          this.authExpectResponse = false

          reject(
            new KafkaJSConnectionError('Connection closed by the server', {
              broker: `${this.host}:${this.port}`,
            })
          )
        },
      }

      try {
        const requestPayload = await request.encode()

        this.failIfNotConnected()
        this.socket.write(requestPayload.buffer, 'binary')
      } catch (e) {
        reject(e)
      }
    })
  }

  /**
   * @public
   * @param {object} protocol
   * @param {object} protocol.request It is defined by the protocol and consists of an object with "apiKey",
   *                         "apiVersion", "apiName" and an "encode" function. The encode function
   *                         must return an instance of Encoder
   *
   * @param {object} protocol.response It is defined by the protocol and consists of an object with two functions:
   *                          "decode" and "parse"
   *
   * @param {number} [protocol.requestTimeout=null] Override for the default requestTimeout
   * @param {boolean} [protocol.logResponseError=true] Whether to log errors
   * @returns {Promise<data>} where data is the return of "response#parse"
   */
  async send({ request, response, requestTimeout = null, logResponseError = true }) {
    this.failIfNotConnected()

    const expectResponse = !request.expectResponse || request.expectResponse()
    const sendRequest = async () => {
      const { clientId } = this
      const correlationId = this.nextCorrelationId()

      const requestPayload = await createRequest({ request, correlationId, clientId })
      const { apiKey, apiName, apiVersion } = request
      this.logDebug(`Request ${requestInfo(request)}`, {
        correlationId,
        expectResponse,
        size: Buffer.byteLength(requestPayload.buffer),
      })

      return new Promise((resolve, reject) => {
        try {
          this.failIfNotConnected()
          const entry = { apiKey, apiName, apiVersion, correlationId, resolve, reject }

          this.requestQueue.push({
            entry,
            expectResponse,
            requestTimeout,
            sendRequest: () => {
              this.socket.write(requestPayload.buffer, 'binary')
            },
          })
        } catch (e) {
          reject(e)
        }
      })
    }

    const { correlationId, size, entry, payload } = await sendRequest()

    if (!expectResponse) {
      return
    }

    try {
      const payloadDecoded = await response.decode(payload)

      /**
       * @see KIP-219
       * If the response indicates that the client-side needs to throttle, do that.
       */
      this.requestQueue.maybeThrottle(payloadDecoded.clientSideThrottleTime)

      const data = await response.parse(payloadDecoded)
      const isFetchApi = entry.apiName === 'Fetch'
      this.logDebug(`Response ${requestInfo(entry)}`, {
        correlationId,
        size,
        data: isFetchApi && !this.shouldLogFetchBuffer ? '[filtered]' : data,
      })

      return data
    } catch (e) {
      if (logResponseError) {
        this.logError(`Response ${requestInfo(entry)}`, {
          error: e.message,
          correlationId,
          size,
        })
      }

      const isBuffer = Buffer.isBuffer(payload)
      this.logDebug(`Response ${requestInfo(entry)}`, {
        error: e.message,
        correlationId,
        payload:
          isBuffer && !this.shouldLogBuffers ? { type: 'Buffer', data: '[filtered]' } : payload,
      })

      throw e
    }
  }

  /**
   * @private
   */
  failIfNotConnected() {
    if (!this.connected) {
      throw new KafkaJSConnectionError('Not connected', {
        broker: `${this.host}:${this.port}`,
      })
    }
  }

  /**
   * @private
   */
  nextCorrelationId() {
    if (this.correlationId >= INT_32_MAX_VALUE) {
      this.correlationId = 0
    }

    return this.correlationId++
  }

  /**
   * @private
   */
  processData(rawData) {
    if (this.authHandlers && !this.authExpectResponse) {
      return this.authHandlers.onSuccess(rawData)
    }

    // Accumulate the new chunk
    this.chunks.push(rawData)
    this.bytesBuffered += Buffer.byteLength(rawData)

    // Process data if there are enough bytes to read the expected response size,
    // otherwise keep buffering
    while (this.bytesNeeded <= this.bytesBuffered) {
      const buffer = this.chunks.length > 1 ? Buffer.concat(this.chunks) : this.chunks[0]
      const decoder = new Decoder(buffer)
      const expectedResponseSize = decoder.readInt32()

      // Return early if not enough bytes to read the full response
      if (!decoder.canReadBytes(expectedResponseSize)) {
        this.chunks = [buffer]
        this.bytesBuffered = Buffer.byteLength(buffer)
        this.bytesNeeded = Decoder.int32Size() + expectedResponseSize
        return
      }

      const response = new Decoder(decoder.readBytes(expectedResponseSize))

      // Reset the buffered chunks as the rest of the bytes
      const remainderBuffer = decoder.readAll()
      this.chunks = [remainderBuffer]
      this.bytesBuffered = Buffer.byteLength(remainderBuffer)
      this.bytesNeeded = Decoder.int32Size()

      if (this.authHandlers) {
        const rawResponseSize = Decoder.int32Size() + expectedResponseSize
        const rawResponseBuffer = buffer.slice(0, rawResponseSize)
        return this.authHandlers.onSuccess(rawResponseBuffer)
      }

      const correlationId = response.readInt32()
      const payload = response.readAll()

      this.requestQueue.fulfillRequest({
        size: expectedResponseSize,
        correlationId,
        payload,
      })
    }
  }

  /**
   * @private
   */
  rejectRequests(error) {
    this.requestQueue.rejectAll(error)
  }
}
<commit_msg>fix: deadlock on connection onError handler<commit_after>const createRetry = require('../retry')
const createSocket = require('./socket')
const createRequest = require('../protocol/request')
const Decoder = require('../protocol/decoder')
const { KafkaJSConnectionError, KafkaJSConnectionClosedError } = require('../errors')
const { INT_32_MAX_VALUE } = require('../constants')
const getEnv = require('../env')
const RequestQueue = require('./requestQueue')
const { CONNECTION_STATUS, CONNECTED_STATUS } = require('./connectionStatus')

const requestInfo = ({ apiName, apiKey, apiVersion }) =>
  `${apiName}(key: ${apiKey}, version: ${apiVersion})`

/**
 * @param {string} host
 * @param {number} port
 * @param {Object} logger
 * @param {string} clientId='kafkajs'
 * @param {number} requestTimeout The maximum amount of time the client will wait for the response of a request,
 *                                in milliseconds
 * @param {string} [rack=null]
 * @param {Object} [ssl=null] Options for the TLS Secure Context. It accepts all options,
 *                            usually "cert", "key" and "ca". More information at
 *                            https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options
 * @param {Object} [sasl=null] Attributes used for SASL authentication. Options based on the
 *                             key "mechanism". Connection is not actively using the SASL attributes
 *                             but acting as a data object for this information
 * @param {number} [connectionTimeout=1000] The connection timeout, in milliseconds
 * @param {Object} [retry=null] Configurations for the built-in retry mechanism. More information at the
 *                              retry module inside network
 * @param {number} [maxInFlightRequests=null] The maximum number of unacknowledged requests on a connection before
 *                                            enqueuing
 * @param {InstrumentationEventEmitter} [instrumentationEmitter=null]
 */
module.exports = class Connection {
  constructor({
    host,
    port,
    logger,
    socketFactory,
    requestTimeout,
    rack = null,
    ssl = null,
    sasl = null,
    clientId = 'kafkajs',
    connectionTimeout = 1000,
    enforceRequestTimeout = false,
    maxInFlightRequests = null,
    instrumentationEmitter = null,
    retry = {},
  }) {
    this.host = host
    this.port = port
    this.rack = rack
    this.clientId = clientId
    this.broker = `${this.host}:${this.port}`
    this.logger = logger.namespace('Connection')

    this.socketFactory = socketFactory
    this.ssl = ssl
    this.sasl = sasl

    this.retry = retry
    this.retrier = createRetry({ ...this.retry })
    this.requestTimeout = requestTimeout
    this.connectionTimeout = connectionTimeout

    this.bytesBuffered = 0
    this.bytesNeeded = Decoder.int32Size()
    this.chunks = []

    this.connectionStatus = CONNECTION_STATUS.DISCONNECTED
    this.correlationId = 0
    this.requestQueue = new RequestQueue({
      instrumentationEmitter,
      maxInFlightRequests,
      requestTimeout,
      enforceRequestTimeout,
      clientId,
      broker: this.broker,
      logger: logger.namespace('RequestQueue'),
      isConnected: () => this.connected,
    })

    this.authHandlers = null
    this.authExpectResponse = false

    const log = level => (message, extra = {}) => {
      const logFn = this.logger[level]
      logFn(message, { broker: this.broker, clientId, ...extra })
    }

    this.logDebug = log('debug')
    this.logError = log('error')

    const env = getEnv()
    this.shouldLogBuffers = env.KAFKAJS_DEBUG_PROTOCOL_BUFFERS === '1'
    this.shouldLogFetchBuffer =
      this.shouldLogBuffers && env.KAFKAJS_DEBUG_EXTENDED_PROTOCOL_BUFFERS === '1'
  }

  get connected() {
    return CONNECTED_STATUS.includes(this.connectionStatus)
  }

  /**
   * @public
   * @returns {Promise}
   */
  connect() {
    return new Promise((resolve, reject) => {
      if (this.connected) {
        return resolve(true)
      }

      let timeoutId

      const onConnect = () => {
        clearTimeout(timeoutId)
        this.connectionStatus = CONNECTION_STATUS.CONNECTED
        this.requestQueue.scheduleRequestTimeoutCheck()
        resolve(true)
      }

      const onData = data => {
        this.processData(data)
      }

      const onEnd = async () => {
        clearTimeout(timeoutId)

        const wasConnected = this.connected

        if (this.authHandlers) {
          this.authHandlers.onError()
        } else if (wasConnected) {
          this.logDebug('Kafka server has closed connection')
          this.rejectRequests(
            new KafkaJSConnectionClosedError('Closed connection', {
              host: this.host,
              port: this.port,
            })
          )
        }

        await this.disconnect()
      }

      const onError = async e => {
        clearTimeout(timeoutId)

        const error = new KafkaJSConnectionError(`Connection error: ${e.message}`, {
          broker: `${this.host}:${this.port}`,
          code: e.code,
        })

        this.logError(error.message, { stack: e.stack })
        this.rejectRequests(error)
        await this.disconnect()

        reject(error)
      }

      const onTimeout = async () => {
        const error = new KafkaJSConnectionError('Connection timeout', {
          broker: `${this.host}:${this.port}`,
        })

        this.logError(error.message)
        await this.disconnect()
        this.rejectRequests(error)
        reject(error)
      }

      this.logDebug(`Connecting`, {
        ssl: !!this.ssl,
        sasl: !!this.sasl,
      })

      try {
        timeoutId = setTimeout(onTimeout, this.connectionTimeout)
        this.socket = createSocket({
          socketFactory: this.socketFactory,
          host: this.host,
          port: this.port,
          ssl: this.ssl,
          onConnect,
          onData,
          onEnd,
          onError,
          onTimeout,
        })
      } catch (e) {
        clearTimeout(timeoutId)
        reject(
          new KafkaJSConnectionError(`Failed to connect: ${e.message}`, {
            broker: `${this.host}:${this.port}`,
          })
        )
      }
    })
  }

  /**
   * @public
   * @returns {Promise}
   */
  async disconnect() {
    this.connectionStatus = CONNECTION_STATUS.DISCONNECTING
    this.logDebug('disconnecting...')

    await this.requestQueue.waitForPendingRequests()
    this.requestQueue.destroy()

    if (this.socket) {
      this.socket.end()
      this.socket.unref()
    }

    this.connectionStatus = CONNECTION_STATUS.DISCONNECTED
    this.logDebug('disconnected')
    return true
  }

  /**
   * @public
   * @returns {Promise}
   */
  authenticate({ authExpectResponse = false, request, response }) {
    this.authExpectResponse = authExpectResponse

    /**
     * TODO: rewrite removing the async promise executor
     */

    /* eslint-disable no-async-promise-executor */
    return new Promise(async (resolve, reject) => {
      this.authHandlers = {
        onSuccess: rawData => {
          this.authHandlers = null
          this.authExpectResponse = false

          response
            .decode(rawData)
            .then(data => response.parse(data))
            .then(resolve)
            .catch(reject)
        },
        onError: () => {
          this.authHandlers = null
          this.authExpectResponse = false

          reject(
            new KafkaJSConnectionError('Connection closed by the server', {
              broker: `${this.host}:${this.port}`,
            })
          )
        },
      }

      try {
        const requestPayload = await request.encode()

        this.failIfNotConnected()
        this.socket.write(requestPayload.buffer, 'binary')
      } catch (e) {
        reject(e)
      }
    })
  }

  /**
   * @public
   * @param {object} protocol
   * @param {object} protocol.request It is defined by the protocol and consists of an object with "apiKey",
   *                         "apiVersion", "apiName" and an "encode" function. The encode function
   *                         must return an instance of Encoder
   *
   * @param {object} protocol.response It is defined by the protocol and consists of an object with two functions:
   *                          "decode" and "parse"
   *
   * @param {number} [protocol.requestTimeout=null] Override for the default requestTimeout
   * @param {boolean} [protocol.logResponseError=true] Whether to log errors
   * @returns {Promise<data>} where data is the return of "response#parse"
   */
  async send({ request, response, requestTimeout = null, logResponseError = true }) {
    this.failIfNotConnected()

    const expectResponse = !request.expectResponse || request.expectResponse()
    const sendRequest = async () => {
      const { clientId } = this
      const correlationId = this.nextCorrelationId()

      const requestPayload = await createRequest({ request, correlationId, clientId })
      const { apiKey, apiName, apiVersion } = request
      this.logDebug(`Request ${requestInfo(request)}`, {
        correlationId,
        expectResponse,
        size: Buffer.byteLength(requestPayload.buffer),
      })

      return new Promise((resolve, reject) => {
        try {
          this.failIfNotConnected()
          const entry = { apiKey, apiName, apiVersion, correlationId, resolve, reject }

          this.requestQueue.push({
            entry,
            expectResponse,
            requestTimeout,
            sendRequest: () => {
              this.socket.write(requestPayload.buffer, 'binary')
            },
          })
        } catch (e) {
          reject(e)
        }
      })
    }

    const { correlationId, size, entry, payload } = await sendRequest()

    if (!expectResponse) {
      return
    }

    try {
      const payloadDecoded = await response.decode(payload)

      /**
       * @see KIP-219
       * If the response indicates that the client-side needs to throttle, do that.
       */
      this.requestQueue.maybeThrottle(payloadDecoded.clientSideThrottleTime)

      const data = await response.parse(payloadDecoded)
      const isFetchApi = entry.apiName === 'Fetch'
      this.logDebug(`Response ${requestInfo(entry)}`, {
        correlationId,
        size,
        data: isFetchApi && !this.shouldLogFetchBuffer ? '[filtered]' : data,
      })

      return data
    } catch (e) {
      if (logResponseError) {
        this.logError(`Response ${requestInfo(entry)}`, {
          error: e.message,
          correlationId,
          size,
        })
      }

      const isBuffer = Buffer.isBuffer(payload)
      this.logDebug(`Response ${requestInfo(entry)}`, {
        error: e.message,
        correlationId,
        payload:
          isBuffer && !this.shouldLogBuffers ? { type: 'Buffer', data: '[filtered]' } : payload,
      })

      throw e
    }
  }

  /**
   * @private
   */
  failIfNotConnected() {
    if (!this.connected) {
      throw new KafkaJSConnectionError('Not connected', {
        broker: `${this.host}:${this.port}`,
      })
    }
  }

  /**
   * @private
   */
  nextCorrelationId() {
    if (this.correlationId >= INT_32_MAX_VALUE) {
      this.correlationId = 0
    }

    return this.correlationId++
  }

  /**
   * @private
   */
  processData(rawData) {
    if (this.authHandlers && !this.authExpectResponse) {
      return this.authHandlers.onSuccess(rawData)
    }

    // Accumulate the new chunk
    this.chunks.push(rawData)
    this.bytesBuffered += Buffer.byteLength(rawData)

    // Process data if there are enough bytes to read the expected response size,
    // otherwise keep buffering
    while (this.bytesNeeded <= this.bytesBuffered) {
      const buffer = this.chunks.length > 1 ? Buffer.concat(this.chunks) : this.chunks[0]
      const decoder = new Decoder(buffer)
      const expectedResponseSize = decoder.readInt32()

      // Return early if not enough bytes to read the full response
      if (!decoder.canReadBytes(expectedResponseSize)) {
        this.chunks = [buffer]
        this.bytesBuffered = Buffer.byteLength(buffer)
        this.bytesNeeded = Decoder.int32Size() + expectedResponseSize
        return
      }

      const response = new Decoder(decoder.readBytes(expectedResponseSize))

      // Reset the buffered chunks as the rest of the bytes
      const remainderBuffer = decoder.readAll()
      this.chunks = [remainderBuffer]
      this.bytesBuffered = Buffer.byteLength(remainderBuffer)
      this.bytesNeeded = Decoder.int32Size()

      if (this.authHandlers) {
        const rawResponseSize = Decoder.int32Size() + expectedResponseSize
        const rawResponseBuffer = buffer.slice(0, rawResponseSize)
        return this.authHandlers.onSuccess(rawResponseBuffer)
      }

      const correlationId = response.readInt32()
      const payload = response.readAll()

      this.requestQueue.fulfillRequest({
        size: expectedResponseSize,
        correlationId,
        payload,
      })
    }
  }

  /**
   * @private
   */
  rejectRequests(error) {
    this.requestQueue.rejectAll(error)
  }
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import layout from './template';
import { authenticatedAJAX } from 'ember-osf/utils/ajax-helpers';

export default Ember.Component.extend({
    layout,
    showContent: false,
    wikiContent: '',
    actions: {
        toggleContent: function(){
            Ember.run.once(this, function() {
                let url = this.get('wiki.links.download');
                authenticatedAJAX({
                    method: 'GET',
                    url: url,
                    xhrFields: {
                        withCredentials: true
                    }
                }).done(data => {
                    this.set('wikiContent', data);
                });
            });
            this.toggleProperty('showContent');
        }
    }
});
<commit_msg>style fixes<commit_after>import Ember from 'ember';
import layout from './template';
import { authenticatedAJAX } from 'ember-osf/utils/ajax-helpers';

export default Ember.Component.extend({
    layout,
    showContent: false,
    wikiContent: '',
    actions: {
        toggleContent: function() {
            Ember.run.once(this, function() {
                let url = this.get('wiki.links.download');
                authenticatedAJAX({
                    method: 'GET',
                    url: url,
                    xhrFields: {
                        withCredentials: true
                    }
                }).done(data => {
                    this.set('wikiContent', data);
                });
            });
            this.toggleProperty('showContent');
        }
    }
});
<|endoftext|>


<commit_before>// Copyright 2015 Endless Mobile, Inc.

const Gtk = imports.gi.Gtk;

const MockFactory = imports.tests.mockFactory;
const MockWidgets = imports.tests.mockWidgets;
const ResponsiveMarginsModule = imports.app.modules.responsiveMarginsModule;
const Utils = imports.tests.utils;

Gtk.init(null);

describe('Responsive margins module', function () {
    let responsive_margins, factory;

    beforeEach(function () {
        factory = new MockFactory.MockFactory();
        factory.add_named_mock('content', MockWidgets.MockSizeWidget);
        factory.add_named_mock('module', ResponsiveMarginsModule.ResponsiveMarginsModule, {
            'content': 'content',
        });
        responsive_margins = factory.create_named_module('module');

        let provider = new Gtk.CssProvider();
        provider.load_from_data('\
        * {\
            border-width: 0px;\
        }\
        .tiny {\
          margin: 10px;\
        }\
        .small {\
          margin: 20px;\
        }\
        .medium {\
          margin: 30px;\
        }\
        .large {\
          margin: 40px;\
        }\
        .xlarge {\
          margin: 50px;\
        }');
        responsive_margins.get_style_context().add_provider(provider, 800);
    });

    it('constructs', function () {});

    function test_constant_size_requests (primary) {
        describe('get preferred ' + primary, function () {
            let win;

            beforeEach(function () {
                win = new Gtk.OffscreenWindow();
                win.add(responsive_margins);
                win.show_all();
            });

            afterEach(function () {
                win.destroy();
            });

            it ('minimal includes tiny margins', function () {
                let content = factory.get_last_created_named_mock('content');
                content[primary + '_spy'].and.returnValue([50, 50]);
                content.queue_resize();
                expect(responsive_margins['get_preferred_' + primary]()[0]).toBe(70);
            });

            it ('natural includes xlarge margins', function () {
                let content = factory.get_last_created_named_mock('content');
                content[primary + '_spy'].and.returnValue([50, 50]);
                content.queue_resize();
                expect(responsive_margins['get_preferred_' + primary]()[1]).toBe(150);
            });
        });
    }
    test_constant_size_requests('width');
    test_constant_size_requests('height');

    it ('height for width passes correct width for tiny and xlarge margins', function () {
        let win = new Gtk.OffscreenWindow();
        win.add(responsive_margins);
        win.show_all();

        let content = factory.get_last_created_named_mock('content');
        content.mode_spy.and.returnValue(Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH);
        content.queue_resize();
        responsive_margins.get_preferred_height_for_width(200);
        expect(content.height_for_width_spy).toHaveBeenCalledWith(180);
        expect(content.height_for_width_spy).toHaveBeenCalledWith(100);
    });

    function testMarginsForDimensions(total_width, margin) {
        describe('at ' + total_width + ' width', function () {
            let win;
            beforeEach(function () {
                win = new Gtk.OffscreenWindow();
            });

            afterEach(function () {
                win.destroy();
            });

            it ('sets margins for internal child to ' + margin + 'px when width=' + total_width, function () {
                let label = responsive_margins.get_children()[0];
                label.expand = true;
                win.add(responsive_margins);
                win.set_size_request(total_width, 600);
                win.show_all();

                win.queue_resize();
                Utils.update_gui();

                expect(total_width).toBe(label.get_allocated_width() + margin * 2);
            });
        });
    }

    testMarginsForDimensions(720, 10);
    testMarginsForDimensions(800, 20);
    testMarginsForDimensions(1100, 30);
    testMarginsForDimensions(1400, 40);
    testMarginsForDimensions(1600, 50);
});

<commit_msg>testResponsiveMarginsModule: fix for new gtk allocate<commit_after>// Copyright 2015 Endless Mobile, Inc.

const Gtk = imports.gi.Gtk;

const MockFactory = imports.tests.mockFactory;
const MockWidgets = imports.tests.mockWidgets;
const ResponsiveMarginsModule = imports.app.modules.responsiveMarginsModule;
const Utils = imports.tests.utils;

Gtk.init(null);

describe('Responsive margins module', function () {
    let responsive_margins, factory;

    beforeEach(function () {
        factory = new MockFactory.MockFactory();
        factory.add_named_mock('content', MockWidgets.MockSizeWidget);
        factory.add_named_mock('module', ResponsiveMarginsModule.ResponsiveMarginsModule, {
            'content': 'content',
        });
        responsive_margins = factory.create_named_module('module');

        let provider = new Gtk.CssProvider();
        provider.load_from_data('\
        * {\
            border-width: 0px;\
        }\
        .tiny {\
          margin: 10px;\
        }\
        .small {\
          margin: 20px;\
        }\
        .medium {\
          margin: 30px;\
        }\
        .large {\
          margin: 40px;\
        }\
        .xlarge {\
          margin: 50px;\
        }');
        responsive_margins.get_style_context().add_provider(provider, 800);
    });

    it('constructs', function () {});

    function test_constant_size_requests (primary) {
        describe('get preferred ' + primary, function () {
            let win;

            beforeEach(function () {
                win = new Gtk.OffscreenWindow();
                win.add(responsive_margins);
                win.show_all();
            });

            afterEach(function () {
                win.destroy();
            });

            it ('minimal includes tiny margins', function () {
                let content = factory.get_last_created_named_mock('content');
                content[primary + '_spy'].and.returnValue([50, 50]);
                content.queue_resize();
                expect(responsive_margins['get_preferred_' + primary]()[0]).toBe(70);
            });

            it ('natural includes xlarge margins', function () {
                let content = factory.get_last_created_named_mock('content');
                content[primary + '_spy'].and.returnValue([50, 50]);
                content.queue_resize();
                expect(responsive_margins['get_preferred_' + primary]()[1]).toBe(150);
            });
        });
    }
    test_constant_size_requests('width');
    test_constant_size_requests('height');

    it ('height for width passes correct width for tiny and xlarge margins', function () {
        let content = factory.get_last_created_named_mock('content');
        content.mode_spy.and.returnValue(Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH);

        let win = new Gtk.OffscreenWindow();
        win.add(responsive_margins);
        win.show_all();

        content.queue_resize();
        responsive_margins.get_preferred_height_for_width(200);
        expect(content.height_for_width_spy).toHaveBeenCalledWith(180);
        expect(content.height_for_width_spy).toHaveBeenCalledWith(100);
    });

    function testMarginsForDimensions(total_width, margin) {
        describe('at ' + total_width + ' width', function () {
            let win;
            beforeEach(function () {
                win = new Gtk.OffscreenWindow();
            });

            afterEach(function () {
                win.destroy();
            });

            it ('sets margins for internal child to ' + margin + 'px when width=' + total_width, function () {
                let label = responsive_margins.get_children()[0];
                label.expand = true;
                win.add(responsive_margins);
                win.set_size_request(total_width, 600);
                win.show_all();

                win.queue_resize();
                Utils.update_gui();

                expect(total_width).toBe(label.get_allocated_width() + margin * 2);
            });
        });
    }

    testMarginsForDimensions(720, 10);
    testMarginsForDimensions(800, 20);
    testMarginsForDimensions(1100, 30);
    testMarginsForDimensions(1400, 40);
    testMarginsForDimensions(1600, 50);
});

<|endoftext|>


<commit_before>import Nav from '../components/nav'

export default () => (

Next.js + Tailwind CSS

)
<commit_msg>Add name to component in with-tailwindcss example (#12417)<commit_after>import Nav from '../components/nav'

export default function IndexPage() {
  return (

Next.js + Tailwind CSS

  )
}
<|endoftext|>


<commit_before>(function() {

/**
 * Models collection
 * @namespace
 * @constructor
 * @augments ns.Model
 */
ns.ModelCollection = function() {};

no.inherit(ns.ModelCollection, ns.Model);

ns.ModelCollection.prototype.getData = function() {
    // это составная модель —
    // нужно склеить все данные
    // из моделей её состовляющих
    if (this.isValid()) {
        var jpathItems;

        if (this.info.split) {
            jpathItems = this.info.split.items;
        } else if (this.info.jpathItems) {
            jpathItems = this.info.jpathItems;
        } else {
            jpathItems = '.items';
        }

        // если нет поля data сделаем его
        if (!this.data) {
            this.data = {};
        }

        // делаем нужное поле в .data и делаем его пустым
        no.jpath.set(jpathItems, this.data, []);
        // ссылка куда вставлять данные моделей
        var items = no.jpath(jpathItems, this.data);

        // пишем новые
        this.models.forEach(function(model) {
            items.push( model.getData() );
        });
    }
    return this.data;
};

ns.ModelCollection.prototype._reset = function() {
    ns.Model.prototype._reset.apply(this, arguments);

    /**
     * ModelCollection listeners
     * @type {Object}
     */
    this.eventListeners = {};
    this.clear();
};

/**
 * Регистрирует обработчики событий.
 * @private
 */
ns.ModelCollection.prototype._bindEvents = function() {
    ns.Model.prototype._bindEvents.apply(this, arguments);

    // При уничтожении вложенной модели коллекция выносит останки.
    this.on('ns-model-destroyed', function(e, data) {
        // Убедимся, что удалился именно элемент коллекции, а не сама коллекция.
        // Пока это возможно только по наличию data.model в аргументах
        if (data && data.model) {
            this.remove(data.model);
        }
    });
};

/**
 * Разбивает данные через jpath описанный в info.split
 * на составные модели
 */
ns.ModelCollection.prototype._setData = function(data) {
    this.clear();

    var info = this.info.split;
    var models = data;
    if (info) {
        var items = no.jpath(info.items, data);
        models = this._splitModels(items);
        this.insert(models);
    }

    return data;
};

/**
 * Создает модели из разбитых данных
 *
 * @param { Array <JSON>} items – массив данных для будущих подмоделей
 * @return { Array <ns.Model> } – массив полученных подмоделей
 */
ns.ModelCollection.prototype._splitModels = function(items) {
    var info = this.info.split;
    var that = this;

    var models = [];

    items.forEach(function(item) {

        var params = {};
        for (var key in info.params) {
            params[key] = no.jpath(info.params[key], item);
        }

        // идентификатор подмодели берется из info.model_id
        // он коллецкия может содержать модели только одного вида
        var model = ns.Model.get(info.model_id, params).setData(item);

        model.on('ns-model-touched', function() {
            // increment modelCollection version on collection-item update
            that._version++;
        });

        models.push(model);
    });

    return models;
};

/**
 * Подписывает коллекию на события из подмоделей
 *
 * @param {ns.Model} model
 */
ns.ModelCollection.prototype._subscribeSplit = function(model) {

    // добавим нашу коллекцию с список слушающих коллекций для подмодели
    model.eventListeners[this.key] = this;

    // если ранее мы не переопределяли прототипный тригер
    // то переопеделим его
    if (ns.Model.prototype.trigger === model.trigger) {
        model.trigger = function(evt, data) {
            ns.Model.prototype.trigger.call(this, evt, data);

            var collData = {
                data: data,
                model: this
            };

            for (var key in this.eventListeners) {
                var collection = this.eventListeners[key];
                if (collection) {
                    collection.trigger(evt, collData);
                }
            }
        };
    }
};

/**
 * Returns data version (included items version).
 * @returns {number}
 */
ns.ModelCollection.prototype.getSelfVersion = function() {
    return this._versionSelf;
};

/**
 * Обновляет _version модели
 */
ns.ModelCollection.prototype.touch = function() {
    ns.Model.prototype.touch.apply(this, arguments);

    /**
     * _versionSelf показывает версию изменений внешней модели
     * в то время, как _version - последнее время изменения внешней или внутренней модели
     * @type {*}
     * @private
     */
    this._versionSelf = this._version;
};

/**
 * Удаляет подписку коллекции на подмодель
 * Обязательно при удалении подмодели из коллекции
 *
 * @param {ns.Model} model
 */
ns.ModelCollection.prototype._unsubscribeSplit = function(model) {
    delete model.eventListeners[this.key];
};

/**
 * Удаляет все подмодели из коллекции
 * С каждой модели происходит снятие подписки
 */
ns.ModelCollection.prototype.clear = function() {

    this.models = this.models || [];

    this.models.forEach(
        this._unsubscribeSplit.bind(this)
    );

    this.models = [];
};

/**
 * Вставляет подмодели в коллекцию
 *
 * @param {Array <ns.Model> | ns.Model} models – одна или несколько подмоделей
 *                                                 для вставки
 * @param {Number} [index] – индекс позиции, на которую вставить подмодели
 *
 * @return {Boolean} – признак успешности вставки
 */
ns.ModelCollection.prototype.insert = function(models, index) {
    if (isNaN(index)) {
        index = this.models.length;
    }

    // Для удобства, одиночная модель оборачивается в массив.
    if (!(models instanceof Array)) {
        models = [models];
    }

    // Вставить можно только объявленную модель
    // и повторная вставка модели запрещена
    var insertion = models.filter(function(model) {
        return this.models.indexOf(model) === -1 && ns.Model.infoLite(model.id);
    }, this);

    insertion.forEach(function(model, i) {
        this.models.splice(index + i, 0, model);

        // не забудем подписаться на события
        this._subscribeSplit(model);
    }, this);

    // оповестим всех, что вставили подмодели
    if (insertion.length > 0) {
        // если вставка данных состоялась, считаем модель валидной
        this.status = this.STATUS.OK;

        this.trigger('ns-model-insert', insertion);
        return true;
    } else {
        return false;
    }
};

/**
 * Удаляет подмодель из коллекции
 *
 * @param {ns.Model | Number | Array<ns.Model | Number>} models – подмодели или индексы подмодели, которую надо удалить
 * @return {Boolean} – признак успешности удаления
 */
ns.ModelCollection.prototype.remove = function(models) {

    var modelsRemoved = [];

    if (!(models instanceof Array)) {
        models = [models];
    }

    models.forEach(function(modelOrIndex) {
        var index;

        if (isNaN(modelOrIndex)) {
            index = this.models.indexOf(modelOrIndex);
        } else {
            index = modelOrIndex;
        }

        if (index >= 0) {
            var model = this.models[index];

            // не забудем отписаться от событий подмодели
            this._unsubscribeSplit(model);
            modelsRemoved.push(model);
            this.models.splice(index, 1);
        }

    }.bind(this));

    if (modelsRemoved.length) {
        this.trigger('ns-model-remove', modelsRemoved);
        return true;
    }

    return false;
};

})();
<commit_msg>ns.ModelCollection: refactor subscribe to item events<commit_after>(function() {

var splitUnsubscribe = {};

/**
 * Models collection
 * @namespace
 * @constructor
 * @augments ns.Model
 */
ns.ModelCollection = function() {};

no.inherit(ns.ModelCollection, ns.Model);

ns.ModelCollection.prototype.getData = function() {
    // TODO а точно это нужно? Можно ведь просто всегда взять элементы из collection.models.

    // это составная модель —
    // нужно склеить все данные
    // из моделей её состовляющих
    if (this.isValid()) {
        var jpathItems;

        if (this.info.split) {
            jpathItems = this.info.split.items;
        } else if (this.info.jpathItems) {
            jpathItems = this.info.jpathItems;
        } else {
            jpathItems = '.items';
        }

        // если нет поля data сделаем его
        if (!this.data) {
            this.data = {};
        }

        // делаем нужное поле в .data и делаем его пустым
        no.jpath.set(jpathItems, this.data, []);
        // ссылка куда вставлять данные моделей
        var items = no.jpath(jpathItems, this.data);

        // пишем новые
        this.models.forEach(function(model) {
            items.push( model.getData() );
        });
    }
    return this.data;
};

ns.ModelCollection.prototype._reset = function() {
    ns.Model.prototype._reset.apply(this, arguments);

    this.clear();
};

/**
 * Разбивает данные через jpath описанный в info.split
 * на составные модели
 */
ns.ModelCollection.prototype._setData = function(data) {
    this.clear();

    var info = this.info.split;
    var models = data;
    if (info) {
        var items = no.jpath(info.items, data);
        models = this._splitModels(items);
        this.insert(models);
    }

    return data;
};

/**
 * Создает модели из разбитых данных
 *
 * @param { Array <JSON>} items – массив данных для будущих подмоделей
 * @return { Array <ns.Model> } – массив полученных подмоделей
 */
ns.ModelCollection.prototype._splitModels = function(items) {
    var info = this.info.split;
    var that = this;

    var models = [];

    items.forEach(function(item) {

        var params = {};
        for (var key in info.params) {
            params[key] = no.jpath(info.params[key], item);
        }

        // идентификатор подмодели берется из info.model_id
        // он коллецкия может содержать модели только одного вида
        var model = ns.Model.get(info.model_id, params).setData(item);
        models.push(model);
    });

    return models;
};

/**
 * Подписывает коллекию на события из подмоделей
 *
 * @param {ns.Model} model
 */
ns.ModelCollection.prototype._subscribeSplit = function(model) {
    var that = this;

    var onModelChanged = function(evt, jpath) { that.onItemChanged(evt, model, jpath); };
    var onModelTouched = function(evt) { that.onItemTouched(evt, model); }
    var onModelDestroyed = function(evt) { that.onItemDestroyed(evt, model); }

    model.on('ns-model-change', onModelChanged);
    model.on('ns-model-touched', onModelTouched);
    model.on('ns-model-destroyed', onModelDestroyed);

    splitUnsubscribe[model.key] = function() {
        model.off('ns-model-change', onModelChanged);
        model.off('ns-model-touched', onModelTouched);
        model.off('ns-model-destroyed', onModelDestroyed);
    };
};

ns.ModelCollection.prototype.onItemChanged = function(evt, model, jpath) {
    // TODO тут можно триггерить много чего, но мы пока этого не делаем:
    // this.trigger('ns-model-changed.items[3].some.inner.prop'); // (ЭТОГО СЕЙЧАС НЕТ).

    this.trigger('ns-model-changed', { 'model': model, 'jpath': jpath });
};

ns.ModelCollection.prototype.onItemTouched = function(evt, model) {
    // TODO почему не this.touch() ?
    this._version++;
};

ns.ModelCollection.prototype.onItemDestroyed = function(evt, model) {
    // При уничтожении вложенной модели коллекция выносит останки.
    this.remove(model);
};

/**
 * Returns data version (included items version).
 * @returns {number}
 */
ns.ModelCollection.prototype.getSelfVersion = function() {
    return this._versionSelf;
};

/**
 * Обновляет _version модели
 */
ns.ModelCollection.prototype.touch = function() {
    ns.Model.prototype.touch.apply(this, arguments);

    /**
     * _versionSelf показывает версию изменений внешней модели
     * в то время, как _version - последнее время изменения внешней или внутренней модели
     * @type {*}
     * @private
     */
    this._versionSelf = this._version;
};

/**
 * Удаляет подписку коллекции на подмодель
 * Обязательно при удалении подмодели из коллекции
 *
 * @param {ns.Model} model
 */
ns.ModelCollection.prototype._unsubscribeSplit = function(model) {
    if (model && splitUnsubscribe[model.key]) {
        splitUnsubscribe[model.key]();
    }
};

/**
 * Удаляет все подмодели из коллекции
 * С каждой модели происходит снятие подписки
 */
ns.ModelCollection.prototype.clear = function() {

    this.models = this.models || [];

    this.models.forEach(
        this._unsubscribeSplit.bind(this)
    );

    this.models = [];
};

/**
 * Вставляет подмодели в коллекцию
 *
 * @param {Array <ns.Model> | ns.Model} models – одна или несколько подмоделей
 *                                                 для вставки
 * @param {Number} [index] – индекс позиции, на которую вставить подмодели
 *
 * @return {Boolean} – признак успешности вставки
 */
ns.ModelCollection.prototype.insert = function(models, index) {
    if (isNaN(index)) {
        index = this.models.length;
    }

    // Для удобства, одиночная модель оборачивается в массив.
    if (!(models instanceof Array)) {
        models = [models];
    }

    // Вставить можно только объявленную модель
    // и повторная вставка модели запрещена
    var insertion = models.filter(function(model) {
        return this.models.indexOf(model) === -1 && ns.Model.infoLite(model.id);
    }, this);

    insertion.forEach(function(model, i) {
        this.models.splice(index + i, 0, model);

        // не забудем подписаться на события
        this._subscribeSplit(model);
    }, this);

    // оповестим всех, что вставили подмодели
    if (insertion.length > 0) {
        // если вставка данных состоялась, считаем модель валидной
        this.status = this.STATUS.OK;

        this.trigger('ns-model-insert', insertion);
        return true;
    } else {
        return false;
    }
};

/**
 * Удаляет подмодель из коллекции
 *
 * @param {ns.Model | Number | Array<ns.Model | Number>} models – подмодели или индексы подмодели, которую надо удалить
 * @return {Boolean} – признак успешности удаления
 */
ns.ModelCollection.prototype.remove = function(models) {

    var modelsRemoved = [];

    if (!(models instanceof Array)) {
        models = [models];
    }

    models.forEach(function(modelOrIndex) {
        var index;

        if (isNaN(modelOrIndex)) {
            index = this.models.indexOf(modelOrIndex);
        } else {
            index = modelOrIndex;
        }

        if (index >= 0) {
            var model = this.models[index];

            // не забудем отписаться от событий подмодели
            this._unsubscribeSplit(model);
            modelsRemoved.push(model);
            this.models.splice(index, 1);
        }

    }.bind(this));

    if (modelsRemoved.length) {
        this.trigger('ns-model-remove', modelsRemoved);
        return true;
    }

    return false;
};

})();
<|endoftext|>


<commit_before>//view model
var vm = {}
vm.title = m.prop("");
vm.filter = ""

vm.addTodo = function() {
	if (vm.title()) {
		model.todos.push(new model.Todo({title: vm.title()}));
		vm.title("");
		model.save()
	}
};

vm.isVisible = function(todo) {
	if (vm.filter == "")
		return true;
	if (vm.filter == "active")
		return !todo.completed();
	if (vm.filter == "completed")
		return todo.completed();
}

vm.setTodosStatus = function(status) {
	for (var i = 0; i < model.todos.length; i++) vm.setTodoStatus(i, status)
}
vm.setTodoStatus = function(todo, status) {
	todo.completed(status)
	model.save()
}
vm.removeTodo = function(todo) {
	model.todos.splice(model.todos.indexOf(todo), 1)
	model.save()
}
vm.clearCompletedTodos = function() {
	for (var i = model.todos.length - 1; i > -1; i--) {
		if (model.todos[i].completed())
			model.todos.splice(i, 1)
	}
	model.save()
}
vm.countCompletedTodos = function() {
	var amount = 0;

	for (var i = 0; i < model.todos.length; i++)
		if (model.todos[i].completed())
			amount++

	return amount
}

vm.edit = {
	todo: m.prop(),
	title: m.prop(""),
	attach: function(todo) {
		vm.edit.todo(todo)
		vm.edit.title(todo.title())
	},
	save: function() {
		if (vm.edit.title() != "") {
			vm.edit.todo().title(vm.edit.title())
			vm.edit.todo(null)
		}
		else vm.removeTodo(vm.edit.todo())
		model.save()
	},
	cancel: function() {
		vm.edit.todo(null)
	}
}

//model
var model = {}
model.Todo = function(data) {
	this.title = m.prop(data.title || "");
	this.completed = m.prop(data.completed || false);
};

model.storageKey = "todos-mithril"
model.todos = new function() {
	var tmp = localStorage.getItem(model.storageKey)
	return tmp ? JSON.parse(tmp).map(function(data) { return new model.Todo(data) }) : [];
}
model.save = new function(lock) {
	return function() {
		//batch I/O
		clearTimeout(lock)
		lock = setTimeout(function() {
			localStorage.setItem(model.storageKey, JSON.stringify(model.todos))
		}, 0)
	}
}
<commit_msg>fix js error in check all<commit_after>//view model
var vm = {}
vm.title = m.prop("");
vm.filter = ""

vm.addTodo = function() {
	if (vm.title()) {
		model.todos.push(new model.Todo({title: vm.title()}));
		vm.title("");
		model.save()
	}
};

vm.isVisible = function(todo) {
	if (vm.filter == "")
		return true;
	if (vm.filter == "active")
		return !todo.completed();
	if (vm.filter == "completed")
		return todo.completed();
}

vm.setTodosStatus = function(status) {
	for (var i = 0; i < model.todos.length; i++) vm.setTodoStatus(model.todos[i], status)
}
vm.setTodoStatus = function(todo, status) {
	todo.completed(status)
	model.save()
}
vm.removeTodo = function(todo) {
	model.todos.splice(model.todos.indexOf(todo), 1)
	model.save()
}
vm.clearCompletedTodos = function() {
	for (var i = model.todos.length - 1; i > -1; i--) {
		if (model.todos[i].completed())
			model.todos.splice(i, 1)
	}
	model.save()
}
vm.countCompletedTodos = function() {
	var amount = 0;

	for (var i = 0; i < model.todos.length; i++)
		if (model.todos[i].completed())
			amount++

	return amount
}

vm.edit = {
	todo: m.prop(),
	title: m.prop(""),
	attach: function(todo) {
		vm.edit.todo(todo)
		vm.edit.title(todo.title())
	},
	save: function() {
		if (vm.edit.title() != "") {
			vm.edit.todo().title(vm.edit.title())
			vm.edit.todo(null)
		}
		else vm.removeTodo(vm.edit.todo())
		model.save()
	},
	cancel: function() {
		vm.edit.todo(null)
	}
}

//model
var model = {}
model.Todo = function(data) {
	this.title = m.prop(data.title || "");
	this.completed = m.prop(data.completed || false);
};

model.storageKey = "todos-mithril"
model.todos = new function() {
	var tmp = localStorage.getItem(model.storageKey)
	return tmp ? JSON.parse(tmp).map(function(data) { return new model.Todo(data) }) : [];
}
model.save = new function(lock) {
	return function() {
		//batch I/O
		clearTimeout(lock)
		lock = setTimeout(function() {
			localStorage.setItem(model.storageKey, JSON.stringify(model.todos))
		}, 0)
	}
}
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/test/actions/Action",
	"sap/ui/thirdparty/jquery"
], function (Action, jQueryDOM) {
	"use strict";

	/**
	 * @class
	 * The Press action is used to simulate a press interaction with a
	 * control. Most controls are supported, for example buttons, links, list items,
	 * tables, filters, and form controls.
	 *
	 * The Press action targets a special DOM element representing the
	 * control. This DOM element can be customized.
	 *
	 * For most most controls (even custom ones), the DOM focus reference is an
	 * appropriate choice. You can choose a different DOM element by specifying its ID
	 * suffix. You can do this by directly passing the ID suffix to the Press constructor,
	 * or by defining a control adapter.
	 *
	 * There are some basic controls for which OPA5 has defined Press control
	 * adapters. For more information, see {@link sap.ui.test.actions.Press.controlAdapters}.
	 *
	 * @param {string}
	 *            [sId] Optional ID for the new instance; generated automatically if
	 *            no non-empty ID is given. Note: this can be omitted, no matter
	 *            whether mSettings are given or not!
	 * @param {object}
	 *            [mSettings] Optional object with initial settings for the new instance
	 * @extends sap.ui.test.actions.Action
	 * @public
	 * @name sap.ui.test.actions.Press
	 * @author SAP SE
	 * @since 1.34
	 */
	var Press = Action.extend("sap.ui.test.actions.Press", /** @lends sap.ui.test.actions.Press.prototype */ {

		metadata : {
			properties: {
				/**
				 * If it is set to true, the Alt Key modifier will be used
				 * @since 1.97
				 */
				altKey: {
					type: "boolean"
				},
				/**
				 * If it is set to true, the Shift Key modifier will be used
				 * @since 1.97
				 */
				shiftKey: {
					type: "boolean"
				},
				/**
				 * If it is set to true, the Control Key modifier will be used
				 * @since 1.97
				 */
				ctrlKey: {
					type: "boolean"
				},
				/**
				 * Provide percent value for the X coordinate axis to calculate the position of the click event.
				 * The value must be in the range [0 - 100]
				 * @since 1.98
				 */
				xPercentage: {
					type: "number"
				},
				/**
				 * Provide percent value for the Y coordinate axis to calculate the position of the click event.
				 * The value must be in the range [0 - 100]
				 * @since 1.98
				 */
				yPercentage: {
					type: "number"
				}
			},
			publicMethods : [ "executeOn" ]
		},

		init: function () {
			Action.prototype.init.apply(this, arguments);
			this.controlAdapters = jQueryDOM.extend(this.controlAdapters, Press.controlAdapters);
		},

		/**
		 * Sets focus on given control and triggers a 'tap' event on it (which is
		 * internally translated into a 'press' event).
		 * Logs an error if control is not visible (i.e. has no dom representation)
		 *
		 * @param {sap.ui.core.Control} oControl the control on which the 'press' event is triggered
		 * @public
		 */
		executeOn : function (oControl) {
			var $ActionDomRef = this.$(oControl),
				oActionDomRef = $ActionDomRef[0];

			var iClientX, iClientY;

			var bAltKey = this.getAltKey();
			var bCtrlKey = this.getCtrlKey();
			var bShiftKey = this.getShiftKey();

			var iXPercentage = this.getXPercentage();
			var iYPercentage = this.getYPercentage();

			// check if the percentage is in the range 0-100
			if (iXPercentage < 0 || iXPercentage > 100){
				this.oLogger.error("Please provide a valid X percentage in the range: 0 - 100");
				return;
			}

			if (iYPercentage < 0 || iYPercentage > 100){
				this.oLogger.error("Please provide a valid Y percentage in the range: 0 - 100");
				return;
			}

			// get the width and the height of the control
			var oRect = oActionDomRef.getBoundingClientRect();

			var iWidth = oRect.width;
			var iHeight = oRect.height;

			var iX = oRect.left + window.scrollX;
			var iY = oRect.top + window.scrollY;

			if (iXPercentage || iXPercentage === 0){
				iClientX = ((iXPercentage / 100) * iWidth) + iX;
			}

			if (iYPercentage || iYPercentage === 0){
				iClientY = ((iYPercentage / 100) * iHeight) + iY;
			}

			if ($ActionDomRef.length) {
				this.oLogger.timestamp("opa.actions.press");
				this.oLogger.debug("Pressed the control " + oControl);

				this._tryOrSimulateFocusin($ActionDomRef, oControl);

				// the missing events like saptouchstart and tap will be fired by the event simulation
				this._createAndDispatchMouseEvent("mousedown", oActionDomRef, null, null, null, iClientX, iClientY);
				this.getUtils().triggerEvent("selectstart", oActionDomRef);
				this._createAndDispatchMouseEvent("mouseup", oActionDomRef, null, null, null, iClientX, iClientY);
				this._createAndDispatchMouseEvent("click", oActionDomRef, bShiftKey, bAltKey, bCtrlKey);
				//Focusout simulation removed in order to fix Press action behavior
				//since in real scenario manual press action does not fire focusout event
			}
		}
	});

	/**
	 * A map of ID suffixes for controls that require a special DOM reference for
	 * Press interaction.
	 *
	 * Here is a sublist of supported controls and their Press control adapter:
	 *

	 *
sap.m.ComboBox - Arrow button

	 *
sap.m.SearchField - Search Button

	 *
sap.m.Input - Value help

	 *
sap.m.List - More Button

	 *
sap.m.Table - More Button

	 *
sap.m.ObjectIdentifier - Title

	 *
sap.m.ObjectAttribute - Text

	 *
sap.m.Page - Back Button

	 *
sap.m.semantic.FullscreenPage - Back Button

	 *
sap.m.semantic.DetailPage - Back Button

	 *
sap.ui.comp.smartfilterbar.SmartFilterBar - Go Button

	 *

	 *
	 * @since 1.63 a control adapter can also be a function.
	 * This is useful for controls with different modes where a different control adapter makes sense in different modes.
	 *
	 * When you extended a UI5 controls the adapter of the control will be taken.
	 * If you need an adapter for your own control you can add it here. For example:
	 * You wrote a control with the namespace my.Control it renders two buttons and you want the press action to press the second one by default.
	 *
	 *

	 *
	 *     new my.Control("myId");
	 *
	 *

	 *
	 * It contains two button tags in its dom.
	 * When you render your control it creates the following dom:
	 *
	 *
	 *

	 *
	 *     <div id="myId">
	 *         <button id="myId-firstButton"/>
	 *         <button id="myId-secondButton"/>
	 *     </div>
	 *
	 *

	 *
	 * Then you may add a control adapter like this
	 *
	 *

	 *
	 *     Press.controlAdapters["my.control"] = "secondButton"; //This can be used by setting the Target Property of an action
	 *
	 *     // Example usage
	 *     new Press(); // executes on second Button since it is set as default
	 *     new Press({ idSuffix: "firstButton"}); // executes on the first button has to be the same as the last part of the id in the dom
	 *
	 *

	 *
	 *
	 * @public
	 * @static
	 * @name sap.ui.test.actions.Press.controlAdapters
	 * You can specify an Id suffix for specific controls in this map.
	 * The press action will be triggered on the DOM element with the specified suffix
	 * @type map
	 */
	Press.controlAdapters = {};
	Press.controlAdapters["sap.m.Input"] = "vhi"; // focusDomRef: <input>
	Press.controlAdapters["sap.m.SearchField"] = "search"; // suffix is the same if refresh button is shown. focusDomRef: <input>
	Press.controlAdapters["sap.m.ListBase"] = "trigger"; // focusDomRef:

	Press.controlAdapters["sap.m.Page"] = "navButton"; // focusDomRef:
 -- root
	Press.controlAdapters["sap.m.semantic.FullscreenPage"] = "navButton"; // focusDomRef:
 -- root
	Press.controlAdapters["sap.m.semantic.DetailPage"] = "navButton"; // focusDomRef:
 -- root
	Press.controlAdapters["sap.m.ComboBox"] = "arrow"; // focusDomRef: <input>
	Press.controlAdapters["sap.ui.comp.smartfilterbar.SmartFilterBar"] = "btnGo"; // always available?

	Press.controlAdapters["sap.m.ObjectAttribute"] = "text"; // suffix is the same in active state. focusDomRef:
 -- root

	Press.controlAdapters["sap.m.ObjectIdentifier"] = function (oControl) {
		if (oControl.getTitleActive()) {
			return "link";
		} else if (oControl.getTitle()) {
			return "title";
		} else if (oControl.getText()) {
			return "text";
		} else {
			return null; // focusDomRef:
 -- root
		}
	};

	return Press;

});<commit_msg>[INTERNAL][FIX] PressAction: fixing JSDOC property types<commit_after>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/test/actions/Action",
	"sap/ui/thirdparty/jquery"
], function (Action, jQueryDOM) {
	"use strict";

	/**
	 * @class
	 * The Press action is used to simulate a press interaction with a
	 * control. Most controls are supported, for example buttons, links, list items,
	 * tables, filters, and form controls.
	 *
	 * The Press action targets a special DOM element representing the
	 * control. This DOM element can be customized.
	 *
	 * For most most controls (even custom ones), the DOM focus reference is an
	 * appropriate choice. You can choose a different DOM element by specifying its ID
	 * suffix. You can do this by directly passing the ID suffix to the Press constructor,
	 * or by defining a control adapter.
	 *
	 * There are some basic controls for which OPA5 has defined Press control
	 * adapters. For more information, see {@link sap.ui.test.actions.Press.controlAdapters}.
	 *
	 * @param {string}
	 *            [sId] Optional ID for the new instance; generated automatically if
	 *            no non-empty ID is given. Note: this can be omitted, no matter
	 *            whether mSettings are given or not!
	 * @param {object}
	 *            [mSettings] Optional object with initial settings for the new instance
	 * @extends sap.ui.test.actions.Action
	 * @public
	 * @name sap.ui.test.actions.Press
	 * @author SAP SE
	 * @since 1.34
	 */
	var Press = Action.extend("sap.ui.test.actions.Press", /** @lends sap.ui.test.actions.Press.prototype */ {

		metadata : {
			properties: {
				/**
				 * If it is set to true, the Alt Key modifier will be used
				 * @since 1.97
				 */
				altKey: {
					type: "boolean"
				},
				/**
				 * If it is set to true, the Shift Key modifier will be used
				 * @since 1.97
				 */
				shiftKey: {
					type: "boolean"
				},
				/**
				 * If it is set to true, the Control Key modifier will be used
				 * @since 1.97
				 */
				ctrlKey: {
					type: "boolean"
				},
				/**
				 * Provide percent value for the X coordinate axis to calculate the position of the click event.
				 * The value must be in the range [0 - 100]
				 * @since 1.98
				 */
				xPercentage: {
					type: "float"
				},
				/**
				 * Provide percent value for the Y coordinate axis to calculate the position of the click event.
				 * The value must be in the range [0 - 100]
				 * @since 1.98
				 */
				yPercentage: {
					type: "float"
				}
			},
			publicMethods : [ "executeOn" ]
		},

		init: function () {
			Action.prototype.init.apply(this, arguments);
			this.controlAdapters = jQueryDOM.extend(this.controlAdapters, Press.controlAdapters);
		},

		/**
		 * Sets focus on given control and triggers a 'tap' event on it (which is
		 * internally translated into a 'press' event).
		 * Logs an error if control is not visible (i.e. has no dom representation)
		 *
		 * @param {sap.ui.core.Control} oControl the control on which the 'press' event is triggered
		 * @public
		 */
		executeOn : function (oControl) {
			var $ActionDomRef = this.$(oControl),
				oActionDomRef = $ActionDomRef[0];

			var iClientX, iClientY;

			var bAltKey = this.getAltKey();
			var bCtrlKey = this.getCtrlKey();
			var bShiftKey = this.getShiftKey();

			var iXPercentage = this.getXPercentage();
			var iYPercentage = this.getYPercentage();

			// check if the percentage is in the range 0-100
			if (iXPercentage < 0 || iXPercentage > 100){
				this.oLogger.error("Please provide a valid X percentage in the range: 0 - 100");
				return;
			}

			if (iYPercentage < 0 || iYPercentage > 100){
				this.oLogger.error("Please provide a valid Y percentage in the range: 0 - 100");
				return;
			}

			// get the width and the height of the control
			var oRect = oActionDomRef.getBoundingClientRect();

			var iWidth = oRect.width;
			var iHeight = oRect.height;

			var iX = oRect.left + window.scrollX;
			var iY = oRect.top + window.scrollY;

			if (iXPercentage || iXPercentage === 0){
				iClientX = ((iXPercentage / 100) * iWidth) + iX;
			}

			if (iYPercentage || iYPercentage === 0){
				iClientY = ((iYPercentage / 100) * iHeight) + iY;
			}

			if ($ActionDomRef.length) {
				this.oLogger.timestamp("opa.actions.press");
				this.oLogger.debug("Pressed the control " + oControl);

				this._tryOrSimulateFocusin($ActionDomRef, oControl);

				// the missing events like saptouchstart and tap will be fired by the event simulation
				this._createAndDispatchMouseEvent("mousedown", oActionDomRef, null, null, null, iClientX, iClientY);
				this.getUtils().triggerEvent("selectstart", oActionDomRef);
				this._createAndDispatchMouseEvent("mouseup", oActionDomRef, null, null, null, iClientX, iClientY);
				this._createAndDispatchMouseEvent("click", oActionDomRef, bShiftKey, bAltKey, bCtrlKey);
				//Focusout simulation removed in order to fix Press action behavior
				//since in real scenario manual press action does not fire focusout event
			}
		}
	});

	/**
	 * A map of ID suffixes for controls that require a special DOM reference for
	 * Press interaction.
	 *
	 * Here is a sublist of supported controls and their Press control adapter:
	 *

	 *
sap.m.ComboBox - Arrow button

	 *
sap.m.SearchField - Search Button

	 *
sap.m.Input - Value help

	 *
sap.m.List - More Button

	 *
sap.m.Table - More Button

	 *
sap.m.ObjectIdentifier - Title

	 *
sap.m.ObjectAttribute - Text

	 *
sap.m.Page - Back Button

	 *
sap.m.semantic.FullscreenPage - Back Button

	 *
sap.m.semantic.DetailPage - Back Button

	 *
sap.ui.comp.smartfilterbar.SmartFilterBar - Go Button

	 *

	 *
	 * @since 1.63 a control adapter can also be a function.
	 * This is useful for controls with different modes where a different control adapter makes sense in different modes.
	 *
	 * When you extended a UI5 controls the adapter of the control will be taken.
	 * If you need an adapter for your own control you can add it here. For example:
	 * You wrote a control with the namespace my.Control it renders two buttons and you want the press action to press the second one by default.
	 *
	 *

	 *
	 *     new my.Control("myId");
	 *
	 *

	 *
	 * It contains two button tags in its dom.
	 * When you render your control it creates the following dom:
	 *
	 *
	 *

	 *
	 *     <div id="myId">
	 *         <button id="myId-firstButton"/>
	 *         <button id="myId-secondButton"/>
	 *     </div>
	 *
	 *

	 *
	 * Then you may add a control adapter like this
	 *
	 *

	 *
	 *     Press.controlAdapters["my.control"] = "secondButton"; //This can be used by setting the Target Property of an action
	 *
	 *     // Example usage
	 *     new Press(); // executes on second Button since it is set as default
	 *     new Press({ idSuffix: "firstButton"}); // executes on the first button has to be the same as the last part of the id in the dom
	 *
	 *

	 *
	 *
	 * @public
	 * @static
	 * @name sap.ui.test.actions.Press.controlAdapters
	 * You can specify an Id suffix for specific controls in this map.
	 * The press action will be triggered on the DOM element with the specified suffix
	 * @type map
	 */
	Press.controlAdapters = {};
	Press.controlAdapters["sap.m.Input"] = "vhi"; // focusDomRef: <input>
	Press.controlAdapters["sap.m.SearchField"] = "search"; // suffix is the same if refresh button is shown. focusDomRef: <input>
	Press.controlAdapters["sap.m.ListBase"] = "trigger"; // focusDomRef:

	Press.controlAdapters["sap.m.Page"] = "navButton"; // focusDomRef:
 -- root
	Press.controlAdapters["sap.m.semantic.FullscreenPage"] = "navButton"; // focusDomRef:
 -- root
	Press.controlAdapters["sap.m.semantic.DetailPage"] = "navButton"; // focusDomRef:
 -- root
	Press.controlAdapters["sap.m.ComboBox"] = "arrow"; // focusDomRef: <input>
	Press.controlAdapters["sap.ui.comp.smartfilterbar.SmartFilterBar"] = "btnGo"; // always available?

	Press.controlAdapters["sap.m.ObjectAttribute"] = "text"; // suffix is the same in active state. focusDomRef:
 -- root

	Press.controlAdapters["sap.m.ObjectIdentifier"] = function (oControl) {
		if (oControl.getTitleActive()) {
			return "link";
		} else if (oControl.getTitle()) {
			return "title";
		} else if (oControl.getText()) {
			return "text";
		} else {
			return null; // focusDomRef:
 -- root
		}
	};

	return Press;

});<|endoftext|>