// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

if ((typeof mojo !== 'undefined') && mojo.bindingsLibraryInitialized) {
  throw new Error('The Mojo bindings library has been initialized.');
}

var mojo = mojo || {};
mojo.bindingsLibraryInitialized = true;

mojo.internal = mojo.internal || {};

mojo.config = mojo.config || {};
if (typeof mojo.config.global === 'undefined') {
  mojo.config.global = this;
}

if (typeof mojo.config.autoLoadMojomDeps === 'undefined') {
  // Whether to automatically load mojom dependencies.
  // For example, if foo.mojom imports bar.mojom, |autoLoadMojomDeps| set to
  // true means that loading foo.mojom.js will insert a <script> tag to load
  // bar.mojom.js, if it hasn't been loaded.
  //
  // The URL of bar.mojom.js is determined by the relative path of bar.mojom
  // (relative to the position of foo.mojom at build time) and the URL of
  // foo.mojom.js. For exmple, if at build time the two mojom files are
  // located at:
  //   a/b/c/foo.mojom
  //   a/b/d/bar.mojom
  // and the URL of foo.mojom.js is:
  //   http://example.org/scripts/b/c/foo.mojom.js
  // then the URL of bar.mojom.js will be:
  //   http://example.org/scripts/b/d/bar.mojom.js
  //
  // If you would like bar.mojom.js to live at a different location, you need
  // to turn off |autoLoadMojomDeps| before loading foo.mojom.js, and manually
  // load bar.mojom.js yourself. Similarly, you need to turn off the option if
  // you merge bar.mojom.js and foo.mojom.js into a single file.
  //
  // Performance tip: Avoid loading the same mojom.js file multiple times.
  // Assume that |autoLoadMojomDeps| is set to true,
  //
  // <!--
  // (This comment tag is necessary on IOS to avoid interpreting the closing
  // script tags in the example.)
  //
  // No duplicate loading; recommended:
  // <script src="http://example.org/scripts/b/c/foo.mojom.js"></script>
  //
  // No duplicate loading, although unnecessary:
  // <script src="http://example.org/scripts/b/d/bar.mojom.js"></script>
  // <script src="http://example.org/scripts/b/c/foo.mojom.js"></script>
  //
  // Load bar.mojom.js twice; should be avoided:
  // <script src="http://example.org/scripts/b/c/foo.mojom.js"></script>
  // <script src="http://example.org/scripts/b/d/bar.mojom.js"></script>
  //
  // -->
  mojo.config.autoLoadMojomDeps = true;
}

(function() {
  var internal = mojo.internal;
  var config = mojo.config;

  var LoadState = {
    PENDING_LOAD: 1,
    LOADED: 2
  };

  var mojomRegistry = new Map();

  function exposeNamespace(namespace) {
    var current = config.global;
    var parts = namespace.split('.');

    for (var part; parts.length && (part = parts.shift());) {
      if (!current[part]) {
        current[part] = {};
      }
      current = current[part];
    }

    return current;
  }

  function isMojomPendingLoad(id) {
    return mojomRegistry.get(id) === LoadState.PENDING_LOAD;
  }

  function isMojomLoaded(id) {
    return mojomRegistry.get(id) === LoadState.LOADED;
  }

  function markMojomPendingLoad(id) {
    if (isMojomLoaded(id)) {
      throw new Error('The following mojom file has been loaded: ' + id);
    }

    mojomRegistry.set(id, LoadState.PENDING_LOAD);
  }

  function markMojomLoaded(id) {
    mojomRegistry.set(id, LoadState.LOADED);
  }

  function loadMojomIfNecessary(id, relativePath) {
    if (mojomRegistry.has(id)) {
      return;
    }

    if (config.global.document === undefined) {
      throw new Error(
          'Mojom dependency autoloading is not implemented in workers. ' +
          'Please see config variable mojo.config.autoLoadMojomDeps for more ' +
          'details.');
    }

    markMojomPendingLoad(id);
    var url = new URL(relativePath, document.currentScript.src).href;

    if (config.global.document.readyState === 'loading') {
      // We can't use dynamic script loading here (such as
      // `document.createElement(...)` because the loaded script will be
      // evaluated after the following scripts (if they exist). Thus
      // `document.write` guarantees the proper evaluation order.
      config.global.document.write('<script type="text/javascript" src="' +
                                   url + '"><' + '/script>');
    } else {
      // If the parent script is being loaded lazily, we can't use
      // `document.write` because the document has already been loaded.
      var scriptElement = document.createElement('script');
      scriptElement.type = 'text/javascript';
      scriptElement.async = false;
      scriptElement.src = url;
      document.currentScript.parentElement.appendChild(scriptElement);
    }
  }

  internal.exposeNamespace = exposeNamespace;
  internal.isMojomPendingLoad = isMojomPendingLoad;
  internal.isMojomLoaded = isMojomLoaded;
  internal.markMojomPendingLoad = markMojomPendingLoad;
  internal.markMojomLoaded = markMojomLoaded;
  internal.loadMojomIfNecessary = loadMojomIfNecessary;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  // ---------------------------------------------------------------------------

  // |output| could be an interface pointer, InterfacePtrInfo or
  // AssociatedInterfacePtrInfo.
  function makeRequest(output) {
    if (output instanceof mojo.AssociatedInterfacePtrInfo) {
      var {handle0, handle1} = internal.createPairPendingAssociation();
      output.interfaceEndpointHandle = handle0;
      output.version = 0;

      return new mojo.AssociatedInterfaceRequest(handle1);
    }

    if (output instanceof mojo.InterfacePtrInfo) {
      var pipe = Mojo.createMessagePipe();
      output.handle = pipe.handle0;
      output.version = 0;

      return new mojo.InterfaceRequest(pipe.handle1);
    }

    var pipe = Mojo.createMessagePipe();
    output.ptr.bind(new mojo.InterfacePtrInfo(pipe.handle0, 0));
    return new mojo.InterfaceRequest(pipe.handle1);
  }

  // ---------------------------------------------------------------------------

  // Operations used to setup/configure an interface pointer. Exposed as the
  // |ptr| field of generated interface pointer classes.
  // |ptrInfoOrHandle| could be omitted and passed into bind() later.
  function InterfacePtrController(interfaceType, ptrInfoOrHandle) {
    this.version = 0;

    this.interfaceType_ = interfaceType;
    this.router_ = null;
    this.interfaceEndpointClient_ = null;
    this.proxy_ = null;

    // |router_| and |interfaceEndpointClient_| are lazily initialized.
    // |handle_| is valid between bind() and
    // the initialization of |router_| and |interfaceEndpointClient_|.
    this.handle_ = null;

    if (ptrInfoOrHandle)
      this.bind(ptrInfoOrHandle);
  }

  InterfacePtrController.prototype.bind = function(ptrInfoOrHandle) {
    this.reset();

    if (ptrInfoOrHandle instanceof mojo.InterfacePtrInfo) {
      this.version = ptrInfoOrHandle.version;
      this.handle_ = ptrInfoOrHandle.handle;
    } else {
      this.handle_ = ptrInfoOrHandle;
    }
  };

  InterfacePtrController.prototype.isBound = function() {
    return this.interfaceEndpointClient_ !== null || this.handle_ !== null;
  };

  // Although users could just discard the object, reset() closes the pipe
  // immediately.
  InterfacePtrController.prototype.reset = function() {
    this.version = 0;
    if (this.interfaceEndpointClient_) {
      this.interfaceEndpointClient_.close();
      this.interfaceEndpointClient_ = null;
    }
    if (this.router_) {
      this.router_.close();
      this.router_ = null;

      this.proxy_ = null;
    }
    if (this.handle_) {
      this.handle_.close();
      this.handle_ = null;
    }
  };

  InterfacePtrController.prototype.resetWithReason = function(reason) {
    if (this.isBound()) {
      this.configureProxyIfNecessary_();
      this.interfaceEndpointClient_.close(reason);
      this.interfaceEndpointClient_ = null;
    }
    this.reset();
  };

  InterfacePtrController.prototype.setConnectionErrorHandler = function(
      callback) {
    if (!this.isBound())
      throw new Error("Cannot set connection error handler if not bound.");

    this.configureProxyIfNecessary_();
    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
  };

  InterfacePtrController.prototype.passInterface = function() {
    var result;
    if (this.router_) {
      // TODO(yzshen): Fix Router interface to support extracting handle.
      result = new mojo.InterfacePtrInfo(
          this.router_.connector_.handle_, this.version);
      this.router_.connector_.handle_ = null;
    } else {
      // This also handles the case when this object is not bound.
      result = new mojo.InterfacePtrInfo(this.handle_, this.version);
      this.handle_ = null;
    }

    this.reset();
    return result;
  };

  InterfacePtrController.prototype.getProxy = function() {
    this.configureProxyIfNecessary_();
    return this.proxy_;
  };

  InterfacePtrController.prototype.configureProxyIfNecessary_ = function() {
    if (!this.handle_)
      return;

    this.router_ = new internal.Router(this.handle_, true);
    this.handle_ = null;

    this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
        this.router_.createLocalEndpointHandle(internal.kPrimaryInterfaceId));

    this.interfaceEndpointClient_ .setPayloadValidators([
        this.interfaceType_.validateResponse]);
    this.proxy_ = new this.interfaceType_.proxyClass(
        this.interfaceEndpointClient_);
  };

  InterfacePtrController.prototype.queryVersion = function() {
    function onQueryVersion(version) {
      this.version = version;
      return version;
    }

    this.configureProxyIfNecessary_();
    return this.interfaceEndpointClient_.queryVersion().then(
      onQueryVersion.bind(this));
  };

  InterfacePtrController.prototype.requireVersion = function(version) {
    this.configureProxyIfNecessary_();

    if (this.version >= version) {
      return;
    }
    this.version = version;
    this.interfaceEndpointClient_.requireVersion(version);
  };

  // ---------------------------------------------------------------------------

  // |request| could be omitted and passed into bind() later.
  //
  // Example:
  //
  //    // FooImpl implements mojom.Foo.
  //    function FooImpl() { ... }
  //    FooImpl.prototype.fooMethod1 = function() { ... }
  //    FooImpl.prototype.fooMethod2 = function() { ... }
  //
  //    var fooPtr = new mojom.FooPtr();
  //    var request = makeRequest(fooPtr);
  //    var binding = new Binding(mojom.Foo, new FooImpl(), request);
  //    fooPtr.fooMethod1();
  function Binding(interfaceType, impl, requestOrHandle) {
    this.interfaceType_ = interfaceType;
    this.impl_ = impl;
    this.router_ = null;
    this.interfaceEndpointClient_ = null;
    this.stub_ = null;

    if (requestOrHandle)
      this.bind(requestOrHandle);
  }

  Binding.prototype.isBound = function() {
    return this.router_ !== null;
  };

  Binding.prototype.createInterfacePtrAndBind = function() {
    var ptr = new this.interfaceType_.ptrClass();
    // TODO(yzshen): Set the version of the interface pointer.
    this.bind(makeRequest(ptr));
    return ptr;
  };

  Binding.prototype.bind = function(requestOrHandle) {
    this.close();

    var handle = requestOrHandle instanceof mojo.InterfaceRequest ?
        requestOrHandle.handle : requestOrHandle;
    if (!(handle instanceof MojoHandle))
      return;

    this.router_ = new internal.Router(handle);

    this.stub_ = new this.interfaceType_.stubClass(this.impl_);
    this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
        this.router_.createLocalEndpointHandle(internal.kPrimaryInterfaceId),
        this.stub_, this.interfaceType_.kVersion);

    this.interfaceEndpointClient_ .setPayloadValidators([
        this.interfaceType_.validateRequest]);
  };

  Binding.prototype.close = function() {
    if (!this.isBound())
      return;

    if (this.interfaceEndpointClient_) {
      this.interfaceEndpointClient_.close();
      this.interfaceEndpointClient_ = null;
    }

    this.router_.close();
    this.router_ = null;
    this.stub_ = null;
  };

  Binding.prototype.closeWithReason = function(reason) {
    if (this.interfaceEndpointClient_) {
      this.interfaceEndpointClient_.close(reason);
      this.interfaceEndpointClient_ = null;
    }
    this.close();
  };

  Binding.prototype.setConnectionErrorHandler = function(callback) {
    if (!this.isBound()) {
      throw new Error("Cannot set connection error handler if not bound.");
    }
    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
  };

  Binding.prototype.unbind = function() {
    if (!this.isBound())
      return new mojo.InterfaceRequest(null);

    var result = new mojo.InterfaceRequest(this.router_.connector_.handle_);
    this.router_.connector_.handle_ = null;
    this.close();
    return result;
  };

  // ---------------------------------------------------------------------------

  function BindingSetEntry(bindingSet, interfaceType, bindingType, impl,
      requestOrHandle, bindingId) {
    this.bindingSet_ = bindingSet;
    this.bindingId_ = bindingId;
    this.binding_ = new bindingType(interfaceType, impl,
        requestOrHandle);

    this.binding_.setConnectionErrorHandler(function(reason) {
      this.bindingSet_.onConnectionError(bindingId, reason);
    }.bind(this));
  }

  BindingSetEntry.prototype.close = function() {
    this.binding_.close();
  };

  function BindingSet(interfaceType) {
    this.interfaceType_ = interfaceType;
    this.nextBindingId_ = 0;
    this.bindings_ = new Map();
    this.errorHandler_ = null;
    this.bindingType_ = Binding;
  }

  BindingSet.prototype.isEmpty = function() {
    return this.bindings_.size == 0;
  };

  BindingSet.prototype.addBinding = function(impl, requestOrHandle) {
    this.bindings_.set(
        this.nextBindingId_,
        new BindingSetEntry(this, this.interfaceType_, this.bindingType_, impl,
            requestOrHandle, this.nextBindingId_));
    ++this.nextBindingId_;
  };

  BindingSet.prototype.closeAllBindings = function() {
    for (var entry of this.bindings_.values())
      entry.close();
    this.bindings_.clear();
  };

  BindingSet.prototype.setConnectionErrorHandler = function(callback) {
    this.errorHandler_ = callback;
  };

  BindingSet.prototype.onConnectionError = function(bindingId, reason) {
    this.bindings_.delete(bindingId);

    if (this.errorHandler_)
      this.errorHandler_(reason);
  };

  // ---------------------------------------------------------------------------

  // Operations used to setup/configure an associated interface pointer.
  // Exposed as |ptr| field of generated associated interface pointer classes.
  // |associatedPtrInfo| could be omitted and passed into bind() later.
  //
  // Example:
  //    // IntegerSenderImpl implements mojom.IntegerSender
  //    function IntegerSenderImpl() { ... }
  //    IntegerSenderImpl.prototype.echo = function() { ... }
  //
  //    // IntegerSenderConnectionImpl implements mojom.IntegerSenderConnection
  //    function IntegerSenderConnectionImpl() {
  //      this.senderBinding_ = null;
  //    }
  //    IntegerSenderConnectionImpl.prototype.getSender = function(
  //        associatedRequest) {
  //      this.senderBinding_ = new AssociatedBinding(mojom.IntegerSender,
  //          new IntegerSenderImpl(),
  //          associatedRequest);
  //    }
  //
  //    var integerSenderConnection = new mojom.IntegerSenderConnectionPtr();
  //    var integerSenderConnectionBinding = new Binding(
  //        mojom.IntegerSenderConnection,
  //        new IntegerSenderConnectionImpl(),
  //        mojo.makeRequest(integerSenderConnection));
  //
  //    // A locally-created associated interface pointer can only be used to
  //    // make calls when the corresponding associated request is sent over
  //    // another interface (either the primary interface or another
  //    // associated interface).
  //    var associatedInterfacePtrInfo = new AssociatedInterfacePtrInfo();
  //    var associatedRequest = makeRequest(interfacePtrInfo);
  //
  //    integerSenderConnection.getSender(associatedRequest);
  //
  //    // Create an associated interface and bind the associated handle.
  //    var integerSender = new mojom.AssociatedIntegerSenderPtr();
  //    integerSender.ptr.bind(associatedInterfacePtrInfo);
  //    integerSender.echo();

  function AssociatedInterfacePtrController(interfaceType, associatedPtrInfo) {
    this.version = 0;

    this.interfaceType_ = interfaceType;
    this.interfaceEndpointClient_ = null;
    this.proxy_ = null;

    if (associatedPtrInfo) {
      this.bind(associatedPtrInfo);
    }
  }

  AssociatedInterfacePtrController.prototype.bind = function(
      associatedPtrInfo) {
    this.reset();
    this.version = associatedPtrInfo.version;

    this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
        associatedPtrInfo.interfaceEndpointHandle);

    this.interfaceEndpointClient_ .setPayloadValidators([
        this.interfaceType_.validateResponse]);
    this.proxy_ = new this.interfaceType_.proxyClass(
        this.interfaceEndpointClient_);
  };

  AssociatedInterfacePtrController.prototype.isBound = function() {
    return this.interfaceEndpointClient_ !== null;
  };

  AssociatedInterfacePtrController.prototype.reset = function() {
    this.version = 0;
    if (this.interfaceEndpointClient_) {
      this.interfaceEndpointClient_.close();
      this.interfaceEndpointClient_ = null;
    }
    if (this.proxy_) {
      this.proxy_ = null;
    }
  };

  AssociatedInterfacePtrController.prototype.resetWithReason = function(
      reason) {
    if (this.isBound()) {
      this.interfaceEndpointClient_.close(reason);
      this.interfaceEndpointClient_ = null;
    }
    this.reset();
  };

  // Indicates whether an error has been encountered. If true, method calls
  // on this interface will be dropped (and may already have been dropped).
  AssociatedInterfacePtrController.prototype.getEncounteredError = function() {
    return this.interfaceEndpointClient_ ?
        this.interfaceEndpointClient_.getEncounteredError() : false;
  };

  AssociatedInterfacePtrController.prototype.setConnectionErrorHandler =
      function(callback) {
    if (!this.isBound()) {
      throw new Error("Cannot set connection error handler if not bound.");
    }

    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
  };

  AssociatedInterfacePtrController.prototype.passInterface = function() {
    if (!this.isBound()) {
      return new mojo.AssociatedInterfacePtrInfo(null);
    }

    var result = new mojo.AssociatedInterfacePtrInfo(
        this.interfaceEndpointClient_.passHandle(), this.version);
    this.reset();
    return result;
  };

  AssociatedInterfacePtrController.prototype.getProxy = function() {
    return this.proxy_;
  };

  AssociatedInterfacePtrController.prototype.queryVersion = function() {
    function onQueryVersion(version) {
      this.version = version;
      return version;
    }

    return this.interfaceEndpointClient_.queryVersion().then(
      onQueryVersion.bind(this));
  };

  AssociatedInterfacePtrController.prototype.requireVersion = function(
      version) {
    if (this.version >= version) {
      return;
    }
    this.version = version;
    this.interfaceEndpointClient_.requireVersion(version);
  };

  // ---------------------------------------------------------------------------

  // |associatedInterfaceRequest| could be omitted and passed into bind()
  // later.
  function AssociatedBinding(interfaceType, impl, associatedInterfaceRequest) {
    this.interfaceType_ = interfaceType;
    this.impl_ = impl;
    this.interfaceEndpointClient_ = null;
    this.stub_ = null;

    if (associatedInterfaceRequest) {
      this.bind(associatedInterfaceRequest);
    }
  }

  AssociatedBinding.prototype.isBound = function() {
    return this.interfaceEndpointClient_ !== null;
  };

  AssociatedBinding.prototype.bind = function(associatedInterfaceRequest) {
    this.close();

    this.stub_ = new this.interfaceType_.stubClass(this.impl_);
    this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
        associatedInterfaceRequest.interfaceEndpointHandle, this.stub_,
        this.interfaceType_.kVersion);

    this.interfaceEndpointClient_ .setPayloadValidators([
        this.interfaceType_.validateRequest]);
  };


  AssociatedBinding.prototype.close = function() {
    if (!this.isBound()) {
      return;
    }

    if (this.interfaceEndpointClient_) {
      this.interfaceEndpointClient_.close();
      this.interfaceEndpointClient_ = null;
    }

    this.stub_ = null;
  };

  AssociatedBinding.prototype.closeWithReason = function(reason) {
    if (this.interfaceEndpointClient_) {
      this.interfaceEndpointClient_.close(reason);
      this.interfaceEndpointClient_ = null;
    }
    this.close();
  };

  AssociatedBinding.prototype.setConnectionErrorHandler = function(callback) {
    if (!this.isBound()) {
      throw new Error("Cannot set connection error handler if not bound.");
    }
    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
  };

  AssociatedBinding.prototype.unbind = function() {
    if (!this.isBound()) {
      return new mojo.AssociatedInterfaceRequest(null);
    }

    var result = new mojo.AssociatedInterfaceRequest(
        this.interfaceEndpointClient_.passHandle());
    this.close();
    return result;
  };

  // ---------------------------------------------------------------------------

  function AssociatedBindingSet(interfaceType) {
    mojo.BindingSet.call(this, interfaceType);
    this.bindingType_ = AssociatedBinding;
  }

  AssociatedBindingSet.prototype = Object.create(BindingSet.prototype);
  AssociatedBindingSet.prototype.constructor = AssociatedBindingSet;

  mojo.makeRequest = makeRequest;
  mojo.AssociatedInterfacePtrController = AssociatedInterfacePtrController;
  mojo.AssociatedBinding = AssociatedBinding;
  mojo.AssociatedBindingSet = AssociatedBindingSet;
  mojo.Binding = Binding;
  mojo.BindingSet = BindingSet;
  mojo.InterfacePtrController = InterfacePtrController;
})();
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  // Constants ----------------------------------------------------------------
  var kInterfaceIdNamespaceMask = 0x80000000;
  var kPrimaryInterfaceId = 0x00000000;
  var kInvalidInterfaceId = 0xFFFFFFFF;

  // ---------------------------------------------------------------------------

  function InterfacePtrInfo(handle, version) {
    this.handle = handle;
    this.version = version;
  }

  InterfacePtrInfo.prototype.isValid = function() {
    return this.handle instanceof MojoHandle;
  };

  InterfacePtrInfo.prototype.close = function() {
    if (!this.isValid())
      return;

    this.handle.close();
    this.handle = null;
    this.version = 0;
  };

  function AssociatedInterfacePtrInfo(interfaceEndpointHandle, version) {
    this.interfaceEndpointHandle = interfaceEndpointHandle;
    this.version = version;
  }

  AssociatedInterfacePtrInfo.prototype.isValid = function() {
    return this.interfaceEndpointHandle.isValid();
  };

  // ---------------------------------------------------------------------------

  function InterfaceRequest(handle) {
    this.handle = handle;
  }

  InterfaceRequest.prototype.isValid = function() {
    return this.handle instanceof MojoHandle;
  };

  InterfaceRequest.prototype.close = function() {
    if (!this.isValid())
      return;

    this.handle.close();
    this.handle = null;
  };

  function AssociatedInterfaceRequest(interfaceEndpointHandle) {
    this.interfaceEndpointHandle = interfaceEndpointHandle;
  }

  AssociatedInterfaceRequest.prototype.isValid = function() {
    return this.interfaceEndpointHandle.isValid();
  };

  AssociatedInterfaceRequest.prototype.resetWithReason = function(reason) {
    this.interfaceEndpointHandle.reset(reason);
  };

  function isPrimaryInterfaceId(interfaceId) {
    return interfaceId === kPrimaryInterfaceId;
  }

  function isValidInterfaceId(interfaceId) {
    return interfaceId !== kInvalidInterfaceId;
  }

  function hasInterfaceIdNamespaceBitSet(interfaceId) {
    if (interfaceId >= 2 * kInterfaceIdNamespaceMask) {
      throw new Error("Interface ID should be a 32-bit unsigned integer.");
    }
    return interfaceId >= kInterfaceIdNamespaceMask;
  }

  mojo.InterfacePtrInfo = InterfacePtrInfo;
  mojo.InterfaceRequest = InterfaceRequest;
  mojo.AssociatedInterfacePtrInfo = AssociatedInterfacePtrInfo;
  mojo.AssociatedInterfaceRequest = AssociatedInterfaceRequest;
  internal.isPrimaryInterfaceId = isPrimaryInterfaceId;
  internal.isValidInterfaceId = isValidInterfaceId;
  internal.hasInterfaceIdNamespaceBitSet = hasInterfaceIdNamespaceBitSet;
  internal.kInvalidInterfaceId = kInvalidInterfaceId;
  internal.kPrimaryInterfaceId = kPrimaryInterfaceId;
  internal.kInterfaceIdNamespaceMask = kInterfaceIdNamespaceMask;
})();
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  var kHostIsLittleEndian = (function () {
    var endianArrayBuffer = new ArrayBuffer(2);
    var endianUint8Array = new Uint8Array(endianArrayBuffer);
    var endianUint16Array = new Uint16Array(endianArrayBuffer);
    endianUint16Array[0] = 1;
    return endianUint8Array[0] == 1;
  })();

  var kHighWordMultiplier = 0x100000000;

  function Buffer(sizeOrArrayBuffer) {
    if (sizeOrArrayBuffer instanceof ArrayBuffer)
      this.arrayBuffer = sizeOrArrayBuffer;
    else
      this.arrayBuffer = new ArrayBuffer(sizeOrArrayBuffer);

    this.dataView = new DataView(this.arrayBuffer);
    this.next = 0;
  }

  Object.defineProperty(Buffer.prototype, "byteLength", {
    get: function() { return this.arrayBuffer.byteLength; }
  });

  Buffer.prototype.alloc = function(size) {
    var pointer = this.next;
    this.next += size;
    if (this.next > this.byteLength) {
      var newSize = (1.5 * (this.byteLength + size)) | 0;
      this.grow(newSize);
    }
    return pointer;
  };

  function copyArrayBuffer(dstArrayBuffer, srcArrayBuffer) {
    (new Uint8Array(dstArrayBuffer)).set(new Uint8Array(srcArrayBuffer));
  }

  Buffer.prototype.grow = function(size) {
    var newArrayBuffer = new ArrayBuffer(size);
    copyArrayBuffer(newArrayBuffer, this.arrayBuffer);
    this.arrayBuffer = newArrayBuffer;
    this.dataView = new DataView(this.arrayBuffer);
  };

  Buffer.prototype.trim = function() {
    this.arrayBuffer = this.arrayBuffer.slice(0, this.next);
    this.dataView = new DataView(this.arrayBuffer);
  };

  Buffer.prototype.getUint8 = function(offset) {
    return this.dataView.getUint8(offset);
  }
  Buffer.prototype.getUint16 = function(offset) {
    return this.dataView.getUint16(offset, kHostIsLittleEndian);
  }
  Buffer.prototype.getUint32 = function(offset) {
    return this.dataView.getUint32(offset, kHostIsLittleEndian);
  }
  Buffer.prototype.getUint64 = function(offset) {
    var lo, hi;
    if (kHostIsLittleEndian) {
      lo = this.dataView.getUint32(offset, kHostIsLittleEndian);
      hi = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
    } else {
      hi = this.dataView.getUint32(offset, kHostIsLittleEndian);
      lo = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
    }
    return lo + hi * kHighWordMultiplier;
  }

  Buffer.prototype.getInt8 = function(offset) {
    return this.dataView.getInt8(offset);
  }
  Buffer.prototype.getInt16 = function(offset) {
    return this.dataView.getInt16(offset, kHostIsLittleEndian);
  }
  Buffer.prototype.getInt32 = function(offset) {
    return this.dataView.getInt32(offset, kHostIsLittleEndian);
  }
  Buffer.prototype.getInt64 = function(offset) {
    var lo, hi;
    if (kHostIsLittleEndian) {
      lo = this.dataView.getUint32(offset, kHostIsLittleEndian);
      hi = this.dataView.getInt32(offset + 4, kHostIsLittleEndian);
    } else {
      hi = this.dataView.getInt32(offset, kHostIsLittleEndian);
      lo = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
    }
    return lo + hi * kHighWordMultiplier;
  }

  Buffer.prototype.getFloat32 = function(offset) {
    return this.dataView.getFloat32(offset, kHostIsLittleEndian);
  }
  Buffer.prototype.getFloat64 = function(offset) {
    return this.dataView.getFloat64(offset, kHostIsLittleEndian);
  }

  Buffer.prototype.setUint8 = function(offset, value) {
    this.dataView.setUint8(offset, value);
  }
  Buffer.prototype.setUint16 = function(offset, value) {
    this.dataView.setUint16(offset, value, kHostIsLittleEndian);
  }
  Buffer.prototype.setUint32 = function(offset, value) {
    this.dataView.setUint32(offset, value, kHostIsLittleEndian);
  }
  Buffer.prototype.setUint64 = function(offset, value) {
    var hi = (value / kHighWordMultiplier) | 0;
    if (kHostIsLittleEndian) {
      this.dataView.setInt32(offset, value, kHostIsLittleEndian);
      this.dataView.setInt32(offset + 4, hi, kHostIsLittleEndian);
    } else {
      this.dataView.setInt32(offset, hi, kHostIsLittleEndian);
      this.dataView.setInt32(offset + 4, value, kHostIsLittleEndian);
    }
  }

  Buffer.prototype.setInt8 = function(offset, value) {
    this.dataView.setInt8(offset, value);
  }
  Buffer.prototype.setInt16 = function(offset, value) {
    this.dataView.setInt16(offset, value, kHostIsLittleEndian);
  }
  Buffer.prototype.setInt32 = function(offset, value) {
    this.dataView.setInt32(offset, value, kHostIsLittleEndian);
  }
  Buffer.prototype.setInt64 = function(offset, value) {
    var hi = Math.floor(value / kHighWordMultiplier);
    if (kHostIsLittleEndian) {
      this.dataView.setInt32(offset, value, kHostIsLittleEndian);
      this.dataView.setInt32(offset + 4, hi, kHostIsLittleEndian);
    } else {
      this.dataView.setInt32(offset, hi, kHostIsLittleEndian);
      this.dataView.setInt32(offset + 4, value, kHostIsLittleEndian);
    }
  }

  Buffer.prototype.setFloat32 = function(offset, value) {
    this.dataView.setFloat32(offset, value, kHostIsLittleEndian);
  }
  Buffer.prototype.setFloat64 = function(offset, value) {
    this.dataView.setFloat64(offset, value, kHostIsLittleEndian);
  }

  internal.Buffer = Buffer;
})();
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  var kErrorUnsigned = "Passing negative value to unsigned";
  var kErrorArray = "Passing non Array for array type";
  var kErrorString = "Passing non String for string type";
  var kErrorMap = "Passing non Map for map type";

  // Memory -------------------------------------------------------------------

  var kAlignment = 8;

  function align(size) {
    return size + (kAlignment - (size % kAlignment)) % kAlignment;
  }

  function isAligned(offset) {
    return offset >= 0 && (offset % kAlignment) === 0;
  }

  // Constants ----------------------------------------------------------------

  var kArrayHeaderSize = 8;
  var kStructHeaderSize = 8;
  var kMessageV0HeaderSize = 24;
  var kMessageV1HeaderSize = 32;
  var kMessageV2HeaderSize = 48;
  var kMapStructPayloadSize = 16;

  var kStructHeaderNumBytesOffset = 0;
  var kStructHeaderVersionOffset = 4;

  var kEncodedInvalidHandleValue = 0xFFFFFFFF;

  // Decoder ------------------------------------------------------------------

  function Decoder(buffer, handles, associatedEndpointHandles, base) {
    this.buffer = buffer;
    this.handles = handles;
    this.associatedEndpointHandles = associatedEndpointHandles;
    this.base = base;
    this.next = base;
  }

  Decoder.prototype.align = function() {
    this.next = align(this.next);
  };

  Decoder.prototype.skip = function(offset) {
    this.next += offset;
  };

  Decoder.prototype.readInt8 = function() {
    var result = this.buffer.getInt8(this.next);
    this.next += 1;
    return result;
  };

  Decoder.prototype.readUint8 = function() {
    var result = this.buffer.getUint8(this.next);
    this.next += 1;
    return result;
  };

  Decoder.prototype.readInt16 = function() {
    var result = this.buffer.getInt16(this.next);
    this.next += 2;
    return result;
  };

  Decoder.prototype.readUint16 = function() {
    var result = this.buffer.getUint16(this.next);
    this.next += 2;
    return result;
  };

  Decoder.prototype.readInt32 = function() {
    var result = this.buffer.getInt32(this.next);
    this.next += 4;
    return result;
  };

  Decoder.prototype.readUint32 = function() {
    var result = this.buffer.getUint32(this.next);
    this.next += 4;
    return result;
  };

  Decoder.prototype.readInt64 = function() {
    var result = this.buffer.getInt64(this.next);
    this.next += 8;
    return result;
  };

  Decoder.prototype.readUint64 = function() {
    var result = this.buffer.getUint64(this.next);
    this.next += 8;
    return result;
  };

  Decoder.prototype.readFloat = function() {
    var result = this.buffer.getFloat32(this.next);
    this.next += 4;
    return result;
  };

  Decoder.prototype.readDouble = function() {
    var result = this.buffer.getFloat64(this.next);
    this.next += 8;
    return result;
  };

  Decoder.prototype.decodePointer = function() {
    // TODO(abarth): To correctly decode a pointer, we need to know the real
    // base address of the array buffer.
    var offsetPointer = this.next;
    var offset = this.readUint64();
    if (!offset)
      return 0;
    return offsetPointer + offset;
  };

  Decoder.prototype.decodeAndCreateDecoder = function(pointer) {
    return new Decoder(this.buffer, this.handles,
        this.associatedEndpointHandles, pointer);
  };

  Decoder.prototype.decodeHandle = function() {
    return this.handles[this.readUint32()] || null;
  };

  Decoder.prototype.decodeAssociatedEndpointHandle = function() {
    return this.associatedEndpointHandles[this.readUint32()] || null;
  };

  Decoder.prototype.decodeString = function() {
    var numberOfBytes = this.readUint32();
    var numberOfElements = this.readUint32();
    var base = this.next;
    this.next += numberOfElements;
    return internal.decodeUtf8String(
        new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements));
  };

  Decoder.prototype.decodeArray = function(cls) {
    var numberOfBytes = this.readUint32();
    var numberOfElements = this.readUint32();
    var val = new Array(numberOfElements);
    if (cls === PackedBool) {
      var byte;
      for (var i = 0; i < numberOfElements; ++i) {
        if (i % 8 === 0)
          byte = this.readUint8();
        val[i] = (byte & (1 << i % 8)) ? true : false;
      }
    } else {
      for (var i = 0; i < numberOfElements; ++i) {
        val[i] = cls.decode(this);
      }
    }
    return val;
  };

  Decoder.prototype.decodeStruct = function(cls) {
    return cls.decode(this);
  };

  Decoder.prototype.decodeStructPointer = function(cls) {
    var pointer = this.decodePointer();
    if (!pointer) {
      return null;
    }
    return cls.decode(this.decodeAndCreateDecoder(pointer));
  };

  Decoder.prototype.decodeArrayPointer = function(cls) {
    var pointer = this.decodePointer();
    if (!pointer) {
      return null;
    }
    return this.decodeAndCreateDecoder(pointer).decodeArray(cls);
  };

  Decoder.prototype.decodeStringPointer = function() {
    var pointer = this.decodePointer();
    if (!pointer) {
      return null;
    }
    return this.decodeAndCreateDecoder(pointer).decodeString();
  };

  Decoder.prototype.decodeMap = function(keyClass, valueClass) {
    this.skip(4); // numberOfBytes
    this.skip(4); // version
    var keys = this.decodeArrayPointer(keyClass);
    var values = this.decodeArrayPointer(valueClass);
    var val = new Map();
    for (var i = 0; i < keys.length; i++)
      val.set(keys[i], values[i]);
    return val;
  };

  Decoder.prototype.decodeMapPointer = function(keyClass, valueClass) {
    var pointer = this.decodePointer();
    if (!pointer) {
      return null;
    }
    var decoder = this.decodeAndCreateDecoder(pointer);
    return decoder.decodeMap(keyClass, valueClass);
  };

  // Encoder ------------------------------------------------------------------

  function Encoder(buffer, handles, associatedEndpointHandles, base) {
    this.buffer = buffer;
    this.handles = handles;
    this.associatedEndpointHandles = associatedEndpointHandles;
    this.base = base;
    this.next = base;
  }

  Encoder.prototype.align = function() {
    this.next = align(this.next);
  };

  Encoder.prototype.skip = function(offset) {
    this.next += offset;
  };

  Encoder.prototype.writeInt8 = function(val) {
    this.buffer.setInt8(this.next, val);
    this.next += 1;
  };

  Encoder.prototype.writeUint8 = function(val) {
    if (val < 0) {
      throw new Error(kErrorUnsigned);
    }
    this.buffer.setUint8(this.next, val);
    this.next += 1;
  };

  Encoder.prototype.writeInt16 = function(val) {
    this.buffer.setInt16(this.next, val);
    this.next += 2;
  };

  Encoder.prototype.writeUint16 = function(val) {
    if (val < 0) {
      throw new Error(kErrorUnsigned);
    }
    this.buffer.setUint16(this.next, val);
    this.next += 2;
  };

  Encoder.prototype.writeInt32 = function(val) {
    this.buffer.setInt32(this.next, val);
    this.next += 4;
  };

  Encoder.prototype.writeUint32 = function(val) {
    if (val < 0) {
      throw new Error(kErrorUnsigned);
    }
    this.buffer.setUint32(this.next, val);
    this.next += 4;
  };

  Encoder.prototype.writeInt64 = function(val) {
    this.buffer.setInt64(this.next, val);
    this.next += 8;
  };

  Encoder.prototype.writeUint64 = function(val) {
    if (val < 0) {
      throw new Error(kErrorUnsigned);
    }
    this.buffer.setUint64(this.next, val);
    this.next += 8;
  };

  Encoder.prototype.writeFloat = function(val) {
    this.buffer.setFloat32(this.next, val);
    this.next += 4;
  };

  Encoder.prototype.writeDouble = function(val) {
    this.buffer.setFloat64(this.next, val);
    this.next += 8;
  };

  Encoder.prototype.encodePointer = function(pointer) {
    if (!pointer)
      return this.writeUint64(0);
    // TODO(abarth): To correctly encode a pointer, we need to know the real
    // base address of the array buffer.
    var offset = pointer - this.next;
    this.writeUint64(offset);
  };

  Encoder.prototype.createAndEncodeEncoder = function(size) {
    var pointer = this.buffer.alloc(align(size));
    this.encodePointer(pointer);
    return new Encoder(this.buffer, this.handles,
        this.associatedEndpointHandles, pointer);
  };

  Encoder.prototype.encodeHandle = function(handle) {
    if (handle) {
      this.handles.push(handle);
      this.writeUint32(this.handles.length - 1);
    } else {
      this.writeUint32(kEncodedInvalidHandleValue);
    }
  };

  Encoder.prototype.encodeAssociatedEndpointHandle = function(endpointHandle) {
    if (endpointHandle) {
      this.associatedEndpointHandles.push(endpointHandle);
      this.writeUint32(this.associatedEndpointHandles.length - 1);
    } else {
      this.writeUint32(kEncodedInvalidHandleValue);
    }
  };

  Encoder.prototype.encodeString = function(val) {
    var base = this.next + kArrayHeaderSize;
    var numberOfElements = internal.encodeUtf8String(
        val, new Uint8Array(this.buffer.arrayBuffer, base));
    var numberOfBytes = kArrayHeaderSize + numberOfElements;
    this.writeUint32(numberOfBytes);
    this.writeUint32(numberOfElements);
    this.next += numberOfElements;
  };

  Encoder.prototype.encodeArray =
      function(cls, val, numberOfElements, encodedSize) {
    if (numberOfElements === undefined)
      numberOfElements = val.length;
    if (encodedSize === undefined)
      encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements;

    this.writeUint32(encodedSize);
    this.writeUint32(numberOfElements);

    if (cls === PackedBool) {
      var byte = 0;
      for (let i = 0; i < numberOfElements; ++i) {
        if (val[i])
          byte |= (1 << i % 8);
        if (i % 8 === 7 || i == numberOfElements - 1) {
          Uint8.encode(this, byte);
          byte = 0;
        }
      }
    } else {
      for (var i = 0; i < numberOfElements; ++i)
        cls.encode(this, val[i]);
    }
  };

  Encoder.prototype.encodeStruct = function(cls, val) {
    return cls.encode(this, val);
  };

  Encoder.prototype.encodeStructPointer = function(cls, val) {
    if (val == null) {
      // Also handles undefined, since undefined == null.
      this.encodePointer(val);
      return;
    }
    var encoder = this.createAndEncodeEncoder(cls.encodedSize);
    cls.encode(encoder, val);
  };

  Encoder.prototype.encodeArrayPointer = function(cls, val) {
    if (val == null) {
      // Also handles undefined, since undefined == null.
      this.encodePointer(val);
      return;
    }

    var numberOfElements = val.length;
    if (!Number.isSafeInteger(numberOfElements) || numberOfElements < 0)
      throw new Error(kErrorArray);

    var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ?
        Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements);
    var encoder = this.createAndEncodeEncoder(encodedSize);
    encoder.encodeArray(cls, val, numberOfElements, encodedSize);
  };

  Encoder.prototype.encodeStringPointer = function(val) {
    if (val == null) {
      // Also handles undefined, since undefined == null.
      this.encodePointer(val);
      return;
    }
    // Only accepts string primivites, not String Objects like new String("foo")
    if (typeof(val) !== "string") {
      throw new Error(kErrorString);
    }
    var encodedSize = kArrayHeaderSize + internal.utf8Length(val);
    var encoder = this.createAndEncodeEncoder(encodedSize);
    encoder.encodeString(val);
  };

  Encoder.prototype.encodeMap = function(keyClass, valueClass, val) {
    var keys = new Array(val.size);
    var values = new Array(val.size);
    var i = 0;
    val.forEach(function(value, key) {
      values[i] = value;
      keys[i++] = key;
    });
    this.writeUint32(kStructHeaderSize + kMapStructPayloadSize);
    this.writeUint32(0);  // version
    this.encodeArrayPointer(keyClass, keys);
    this.encodeArrayPointer(valueClass, values);
  }

  Encoder.prototype.encodeMapPointer = function(keyClass, valueClass, val) {
    if (val == null) {
      // Also handles undefined, since undefined == null.
      this.encodePointer(val);
      return;
    }
    if (!(val instanceof Map)) {
      throw new Error(kErrorMap);
    }
    var encodedSize = kStructHeaderSize + kMapStructPayloadSize;
    var encoder = this.createAndEncodeEncoder(encodedSize);
    encoder.encodeMap(keyClass, valueClass, val);
  };

  // Message ------------------------------------------------------------------

  var kMessageInterfaceIdOffset = kStructHeaderSize;
  var kMessageNameOffset = kMessageInterfaceIdOffset + 4;
  var kMessageFlagsOffset = kMessageNameOffset + 4;
  var kMessageRequestIDOffset = kMessageFlagsOffset + 8;
  var kMessagePayloadInterfaceIdsPointerOffset = kMessageV2HeaderSize - 8;

  var kMessageExpectsResponse = 1 << 0;
  var kMessageIsResponse      = 1 << 1;

  function Message(buffer, handles, associatedEndpointHandles) {
    if (associatedEndpointHandles === undefined) {
      associatedEndpointHandles = [];
    }

    this.buffer = buffer;
    this.handles = handles;
    this.associatedEndpointHandles = associatedEndpointHandles;
  }

  Message.prototype.getHeaderNumBytes = function() {
    return this.buffer.getUint32(kStructHeaderNumBytesOffset);
  };

  Message.prototype.getHeaderVersion = function() {
    return this.buffer.getUint32(kStructHeaderVersionOffset);
  };

  Message.prototype.getName = function() {
    return this.buffer.getUint32(kMessageNameOffset);
  };

  Message.prototype.getFlags = function() {
    return this.buffer.getUint32(kMessageFlagsOffset);
  };

  Message.prototype.getInterfaceId = function() {
    return this.buffer.getUint32(kMessageInterfaceIdOffset);
  };

  Message.prototype.getPayloadInterfaceIds = function() {
    if (this.getHeaderVersion() < 2) {
      return null;
    }

    var decoder = new Decoder(this.buffer, this.handles,
        this.associatedEndpointHandles,
        kMessagePayloadInterfaceIdsPointerOffset);
    var payloadInterfaceIds = decoder.decodeArrayPointer(Uint32);
    return payloadInterfaceIds;
  };

  Message.prototype.isResponse = function() {
    return (this.getFlags() & kMessageIsResponse) != 0;
  };

  Message.prototype.expectsResponse = function() {
    return (this.getFlags() & kMessageExpectsResponse) != 0;
  };

  Message.prototype.setRequestID = function(requestID) {
    // TODO(darin): Verify that space was reserved for this field!
    this.buffer.setUint64(kMessageRequestIDOffset, requestID);
  };

  Message.prototype.setInterfaceId = function(interfaceId) {
    this.buffer.setUint32(kMessageInterfaceIdOffset, interfaceId);
  };

  Message.prototype.setPayloadInterfaceIds_ = function(payloadInterfaceIds) {
    if (this.getHeaderVersion() < 2) {
      throw new Error(
          "Version of message does not support payload interface ids");
    }

    var decoder = new Decoder(this.buffer, this.handles,
        this.associatedEndpointHandles,
        kMessagePayloadInterfaceIdsPointerOffset);
    var payloadInterfaceIdsOffset = decoder.decodePointer();
    var encoder = new Encoder(this.buffer, this.handles,
        this.associatedEndpointHandles,
        payloadInterfaceIdsOffset);
    encoder.encodeArray(Uint32, payloadInterfaceIds);
  };

  Message.prototype.serializeAssociatedEndpointHandles = function(
      associatedGroupController) {
    if (this.associatedEndpointHandles.length > 0) {
      if (this.getHeaderVersion() < 2) {
        throw new Error(
            "Version of message does not support associated endpoint handles");
      }

      var data = [];
      for (var i = 0; i < this.associatedEndpointHandles.length; i++) {
        var handle = this.associatedEndpointHandles[i];
        data.push(associatedGroupController.associateInterface(handle));
      }
      this.associatedEndpointHandles = [];
      this.setPayloadInterfaceIds_(data);
    }
  };

  Message.prototype.deserializeAssociatedEndpointHandles = function(
      associatedGroupController) {
    if (this.getHeaderVersion() < 2) {
      return true;
    }

    this.associatedEndpointHandles = [];
    var ids = this.getPayloadInterfaceIds();
    if (ids == null) {
      return true;
    }

    var result = true;
    for (var i = 0; i < ids.length; i++) {
      var handle = associatedGroupController.createLocalEndpointHandle(ids[i]);
      if (internal.isValidInterfaceId(ids[i]) && !handle.isValid()) {
        // |ids[i]| itself is valid but handle creation failed. In that case,
        // mark deserialization as failed but continue to deserialize the
        // rest of handles.
        result = false;
      }
      this.associatedEndpointHandles.push(handle);
      ids[i] = internal.kInvalidInterfaceId;
    }

    this.setPayloadInterfaceIds_(ids);
    return result;
  };


  // MessageV0Builder ---------------------------------------------------------

  function MessageV0Builder(messageName, payloadSize) {
    // Currently, we don't compute the payload size correctly ahead of time.
    // Instead, we resize the buffer at the end.
    var numberOfBytes = kMessageV0HeaderSize + payloadSize;
    this.buffer = new internal.Buffer(numberOfBytes);
    this.handles = [];
    var encoder = this.createEncoder(kMessageV0HeaderSize);
    encoder.writeUint32(kMessageV0HeaderSize);
    encoder.writeUint32(0);  // version.
    encoder.writeUint32(0);  // interface ID.
    encoder.writeUint32(messageName);
    encoder.writeUint32(0);  // flags.
    encoder.writeUint32(0);  // padding.
  }

  MessageV0Builder.prototype.createEncoder = function(size) {
    var pointer = this.buffer.alloc(size);
    return new Encoder(this.buffer, this.handles, [], pointer);
  };

  MessageV0Builder.prototype.encodeStruct = function(cls, val) {
    cls.encode(this.createEncoder(cls.encodedSize), val);
  };

  MessageV0Builder.prototype.finish = function() {
    // TODO(abarth): Rather than resizing the buffer at the end, we could
    // compute the size we need ahead of time, like we do in C++.
    this.buffer.trim();
    var message = new Message(this.buffer, this.handles);
    this.buffer = null;
    this.handles = null;
    this.encoder = null;
    return message;
  };

  // MessageV1Builder -----------------------------------------------

  function MessageV1Builder(messageName, payloadSize, flags,
                                       requestID) {
    // Currently, we don't compute the payload size correctly ahead of time.
    // Instead, we resize the buffer at the end.
    var numberOfBytes = kMessageV1HeaderSize + payloadSize;
    this.buffer = new internal.Buffer(numberOfBytes);
    this.handles = [];
    var encoder = this.createEncoder(kMessageV1HeaderSize);
    encoder.writeUint32(kMessageV1HeaderSize);
    encoder.writeUint32(1);  // version.
    encoder.writeUint32(0);  // interface ID.
    encoder.writeUint32(messageName);
    encoder.writeUint32(flags);
    encoder.writeUint32(0);  // padding.
    encoder.writeUint64(requestID);
  }

  MessageV1Builder.prototype =
      Object.create(MessageV0Builder.prototype);

  MessageV1Builder.prototype.constructor =
      MessageV1Builder;

  // MessageV2 -----------------------------------------------

  function MessageV2Builder(messageName, payloadSize, flags, requestID) {
    // Currently, we don't compute the payload size correctly ahead of time.
    // Instead, we resize the buffer at the end.
    var numberOfBytes = kMessageV2HeaderSize + payloadSize;
    this.buffer = new internal.Buffer(numberOfBytes);
    this.handles = [];

    this.payload = null;
    this.associatedEndpointHandles = [];

    this.encoder = this.createEncoder(kMessageV2HeaderSize);
    this.encoder.writeUint32(kMessageV2HeaderSize);
    this.encoder.writeUint32(2);  // version.
    // Gets set to an appropriate interfaceId for the endpoint by the Router.
    this.encoder.writeUint32(0);  // interface ID.
    this.encoder.writeUint32(messageName);
    this.encoder.writeUint32(flags);
    this.encoder.writeUint32(0);  // padding.
    this.encoder.writeUint64(requestID);
  }

  MessageV2Builder.prototype.createEncoder = function(size) {
    var pointer = this.buffer.alloc(size);
    return new Encoder(this.buffer, this.handles,
        this.associatedEndpointHandles, pointer);
  };

  MessageV2Builder.prototype.setPayload = function(cls, val) {
    this.payload = {cls: cls, val: val};
  };

  MessageV2Builder.prototype.finish = function() {
    if (!this.payload) {
      throw new Error("Payload needs to be set before calling finish");
    }

    this.encoder.encodeStructPointer(this.payload.cls, this.payload.val);
    this.encoder.encodeArrayPointer(Uint32,
        new Array(this.associatedEndpointHandles.length));

    this.buffer.trim();
    var message = new Message(this.buffer, this.handles,
        this.associatedEndpointHandles);
    this.buffer = null;
    this.handles = null;
    this.encoder = null;
    this.payload = null;
    this.associatedEndpointHandles = null;

    return message;
  };

  // MessageReader ------------------------------------------------------------

  function MessageReader(message) {
    this.decoder = new Decoder(message.buffer, message.handles,
        message.associatedEndpointHandles, 0);
    var messageHeaderSize = this.decoder.readUint32();
    this.payloadSize = message.buffer.byteLength - messageHeaderSize;
    var version = this.decoder.readUint32();
    var interface_id = this.decoder.readUint32();
    this.messageName = this.decoder.readUint32();
    this.flags = this.decoder.readUint32();
    // Skip the padding.
    this.decoder.skip(4);
    if (version >= 1)
      this.requestID = this.decoder.readUint64();
    this.decoder.skip(messageHeaderSize - this.decoder.next);
  }

  MessageReader.prototype.decodeStruct = function(cls) {
    return cls.decode(this.decoder);
  };

  // Built-in types -----------------------------------------------------------

  // This type is only used with ArrayOf(PackedBool).
  function PackedBool() {
  }

  function Int8() {
  }

  Int8.encodedSize = 1;

  Int8.decode = function(decoder) {
    return decoder.readInt8();
  };

  Int8.encode = function(encoder, val) {
    encoder.writeInt8(val);
  };

  Uint8.encode = function(encoder, val) {
    encoder.writeUint8(val);
  };

  function Uint8() {
  }

  Uint8.encodedSize = 1;

  Uint8.decode = function(decoder) {
    return decoder.readUint8();
  };

  Uint8.encode = function(encoder, val) {
    encoder.writeUint8(val);
  };

  function Int16() {
  }

  Int16.encodedSize = 2;

  Int16.decode = function(decoder) {
    return decoder.readInt16();
  };

  Int16.encode = function(encoder, val) {
    encoder.writeInt16(val);
  };

  function Uint16() {
  }

  Uint16.encodedSize = 2;

  Uint16.decode = function(decoder) {
    return decoder.readUint16();
  };

  Uint16.encode = function(encoder, val) {
    encoder.writeUint16(val);
  };

  function Int32() {
  }

  Int32.encodedSize = 4;

  Int32.decode = function(decoder) {
    return decoder.readInt32();
  };

  Int32.encode = function(encoder, val) {
    encoder.writeInt32(val);
  };

  function Uint32() {
  }

  Uint32.encodedSize = 4;

  Uint32.decode = function(decoder) {
    return decoder.readUint32();
  };

  Uint32.encode = function(encoder, val) {
    encoder.writeUint32(val);
  };

  function Int64() {
  }

  Int64.encodedSize = 8;

  Int64.decode = function(decoder) {
    return decoder.readInt64();
  };

  Int64.encode = function(encoder, val) {
    encoder.writeInt64(val);
  };

  function Uint64() {
  }

  Uint64.encodedSize = 8;

  Uint64.decode = function(decoder) {
    return decoder.readUint64();
  };

  Uint64.encode = function(encoder, val) {
    encoder.writeUint64(val);
  };

  function String() {
  };

  String.encodedSize = 8;

  String.decode = function(decoder) {
    return decoder.decodeStringPointer();
  };

  String.encode = function(encoder, val) {
    encoder.encodeStringPointer(val);
  };

  function NullableString() {
  }

  NullableString.encodedSize = String.encodedSize;

  NullableString.decode = String.decode;

  NullableString.encode = String.encode;

  function Float() {
  }

  Float.encodedSize = 4;

  Float.decode = function(decoder) {
    return decoder.readFloat();
  };

  Float.encode = function(encoder, val) {
    encoder.writeFloat(val);
  };

  function Double() {
  }

  Double.encodedSize = 8;

  Double.decode = function(decoder) {
    return decoder.readDouble();
  };

  Double.encode = function(encoder, val) {
    encoder.writeDouble(val);
  };

  function Enum(cls) {
    this.cls = cls;
  }

  Enum.prototype.encodedSize = 4;

  Enum.prototype.decode = function(decoder) {
    let value = decoder.readInt32();
    return this.cls.toKnownEnumValue(value);
  };

  Enum.prototype.encode = function(encoder, val) {
    encoder.writeInt32(val);
  };

  function PointerTo(cls) {
    this.cls = cls;
  }

  PointerTo.prototype.encodedSize = 8;

  PointerTo.prototype.decode = function(decoder) {
    var pointer = decoder.decodePointer();
    if (!pointer) {
      return null;
    }
    return this.cls.decode(decoder.decodeAndCreateDecoder(pointer));
  };

  PointerTo.prototype.encode = function(encoder, val) {
    if (!val) {
      encoder.encodePointer(val);
      return;
    }
    var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
    this.cls.encode(objectEncoder, val);
  };

  function NullablePointerTo(cls) {
    PointerTo.call(this, cls);
  }

  NullablePointerTo.prototype = Object.create(PointerTo.prototype);

  function ArrayOf(cls, length) {
    this.cls = cls;
    this.length = length || 0;
  }

  ArrayOf.prototype.encodedSize = 8;

  ArrayOf.prototype.dimensions = function() {
    return [this.length].concat(
      (this.cls instanceof ArrayOf) ? this.cls.dimensions() : []);
  }

  ArrayOf.prototype.decode = function(decoder) {
    return decoder.decodeArrayPointer(this.cls);
  };

  ArrayOf.prototype.encode = function(encoder, val) {
    encoder.encodeArrayPointer(this.cls, val);
  };

  function NullableArrayOf(cls) {
    ArrayOf.call(this, cls);
  }

  NullableArrayOf.prototype = Object.create(ArrayOf.prototype);

  function Handle() {
  }

  Handle.encodedSize = 4;

  Handle.decode = function(decoder) {
    return decoder.decodeHandle();
  };

  Handle.encode = function(encoder, val) {
    encoder.encodeHandle(val);
  };

  function NullableHandle() {
  }

  NullableHandle.encodedSize = Handle.encodedSize;

  NullableHandle.decode = Handle.decode;

  NullableHandle.encode = Handle.encode;

  function Interface(cls) {
    this.cls = cls;
  }

  Interface.prototype.encodedSize = 8;

  Interface.prototype.decode = function(decoder) {
    var interfacePtrInfo = new mojo.InterfacePtrInfo(
        decoder.decodeHandle(), decoder.readUint32());
    var interfacePtr = new this.cls();
    interfacePtr.ptr.bind(interfacePtrInfo);
    return interfacePtr;
  };

  Interface.prototype.encode = function(encoder, val) {
    var interfacePtrInfo =
        val ? val.ptr.passInterface() : new mojo.InterfacePtrInfo(null, 0);
    encoder.encodeHandle(interfacePtrInfo.handle);
    encoder.writeUint32(interfacePtrInfo.version);
  };

  function NullableInterface(cls) {
    Interface.call(this, cls);
  }

  NullableInterface.prototype = Object.create(Interface.prototype);

  function AssociatedInterfacePtrInfo() {
  }

  AssociatedInterfacePtrInfo.prototype.encodedSize = 8;

  AssociatedInterfacePtrInfo.decode = function(decoder) {
    return new mojo.AssociatedInterfacePtrInfo(
      decoder.decodeAssociatedEndpointHandle(), decoder.readUint32());
  };

  AssociatedInterfacePtrInfo.encode = function(encoder, val) {
    var associatedinterfacePtrInfo =
        val ? val : new mojo.AssociatedInterfacePtrInfo(null, 0);
    encoder.encodeAssociatedEndpointHandle(
        associatedinterfacePtrInfo.interfaceEndpointHandle);
    encoder.writeUint32(associatedinterfacePtrInfo.version);
  };

  function NullableAssociatedInterfacePtrInfo() {
  }

  NullableAssociatedInterfacePtrInfo.encodedSize =
      AssociatedInterfacePtrInfo.encodedSize;

  NullableAssociatedInterfacePtrInfo.decode =
      AssociatedInterfacePtrInfo.decode;

  NullableAssociatedInterfacePtrInfo.encode =
      AssociatedInterfacePtrInfo.encode;

  function InterfaceRequest() {
  }

  InterfaceRequest.encodedSize = 4;

  InterfaceRequest.decode = function(decoder) {
    return new mojo.InterfaceRequest(decoder.decodeHandle());
  };

  InterfaceRequest.encode = function(encoder, val) {
    encoder.encodeHandle(val ? val.handle : null);
  };

  function NullableInterfaceRequest() {
  }

  NullableInterfaceRequest.encodedSize = InterfaceRequest.encodedSize;

  NullableInterfaceRequest.decode = InterfaceRequest.decode;

  NullableInterfaceRequest.encode = InterfaceRequest.encode;

  function AssociatedInterfaceRequest() {
  }

  AssociatedInterfaceRequest.decode = function(decoder) {
    var handle = decoder.decodeAssociatedEndpointHandle();
    return new mojo.AssociatedInterfaceRequest(handle);
  };

  AssociatedInterfaceRequest.encode = function(encoder, val) {
    encoder.encodeAssociatedEndpointHandle(
        val ? val.interfaceEndpointHandle : null);
  };

  AssociatedInterfaceRequest.encodedSize = 4;

  function NullableAssociatedInterfaceRequest() {
  }

  NullableAssociatedInterfaceRequest.encodedSize =
      AssociatedInterfaceRequest.encodedSize;

  NullableAssociatedInterfaceRequest.decode =
      AssociatedInterfaceRequest.decode;

  NullableAssociatedInterfaceRequest.encode =
      AssociatedInterfaceRequest.encode;

  function MapOf(keyClass, valueClass) {
    this.keyClass = keyClass;
    this.valueClass = valueClass;
  }

  MapOf.prototype.encodedSize = 8;

  MapOf.prototype.decode = function(decoder) {
    return decoder.decodeMapPointer(this.keyClass, this.valueClass);
  };

  MapOf.prototype.encode = function(encoder, val) {
    encoder.encodeMapPointer(this.keyClass, this.valueClass, val);
  };

  function NullableMapOf(keyClass, valueClass) {
    MapOf.call(this, keyClass, valueClass);
  }

  NullableMapOf.prototype = Object.create(MapOf.prototype);

  internal.align = align;
  internal.isAligned = isAligned;
  internal.Message = Message;
  internal.MessageV0Builder = MessageV0Builder;
  internal.MessageV1Builder = MessageV1Builder;
  internal.MessageV2Builder = MessageV2Builder;
  internal.MessageReader = MessageReader;
  internal.kArrayHeaderSize = kArrayHeaderSize;
  internal.kMapStructPayloadSize = kMapStructPayloadSize;
  internal.kStructHeaderSize = kStructHeaderSize;
  internal.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue;
  internal.kMessageV0HeaderSize = kMessageV0HeaderSize;
  internal.kMessageV1HeaderSize = kMessageV1HeaderSize;
  internal.kMessageV2HeaderSize = kMessageV2HeaderSize;
  internal.kMessagePayloadInterfaceIdsPointerOffset =
      kMessagePayloadInterfaceIdsPointerOffset;
  internal.kMessageExpectsResponse = kMessageExpectsResponse;
  internal.kMessageIsResponse = kMessageIsResponse;
  internal.Int8 = Int8;
  internal.Uint8 = Uint8;
  internal.Int16 = Int16;
  internal.Uint16 = Uint16;
  internal.Int32 = Int32;
  internal.Uint32 = Uint32;
  internal.Int64 = Int64;
  internal.Uint64 = Uint64;
  internal.Float = Float;
  internal.Double = Double;
  internal.String = String;
  internal.Enum = Enum;
  internal.NullableString = NullableString;
  internal.PointerTo = PointerTo;
  internal.NullablePointerTo = NullablePointerTo;
  internal.ArrayOf = ArrayOf;
  internal.NullableArrayOf = NullableArrayOf;
  internal.PackedBool = PackedBool;
  internal.Handle = Handle;
  internal.NullableHandle = NullableHandle;
  internal.Interface = Interface;
  internal.NullableInterface = NullableInterface;
  internal.InterfaceRequest = InterfaceRequest;
  internal.NullableInterfaceRequest = NullableInterfaceRequest;
  internal.AssociatedInterfacePtrInfo = AssociatedInterfacePtrInfo;
  internal.NullableAssociatedInterfacePtrInfo =
      NullableAssociatedInterfacePtrInfo;
  internal.AssociatedInterfaceRequest = AssociatedInterfaceRequest;
  internal.NullableAssociatedInterfaceRequest =
      NullableAssociatedInterfaceRequest;
  internal.MapOf = MapOf;
  internal.NullableMapOf = NullableMapOf;
})();
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  function Connector(handle) {
    if (!(handle instanceof MojoHandle))
      throw new Error("Connector: not a handle " + handle);
    this.handle_ = handle;
    this.dropWrites_ = false;
    this.error_ = false;
    this.incomingReceiver_ = null;
    this.readWatcher_ = null;
    this.errorHandler_ = null;
    this.paused_ = false;

    this.waitToReadMore();
  }

  Connector.prototype.close = function() {
    this.cancelWait();
    if (this.handle_ != null) {
      this.handle_.close();
      this.handle_ = null;
    }
  };

  Connector.prototype.pauseIncomingMethodCallProcessing = function() {
    if (this.paused_) {
      return;
    }
    this.paused_= true;
    this.cancelWait();
  };

  Connector.prototype.resumeIncomingMethodCallProcessing = function() {
    if (!this.paused_) {
      return;
    }
    this.paused_= false;
    this.waitToReadMore();
  };

  Connector.prototype.accept = function(message) {
    if (this.error_)
      return false;

    if (this.dropWrites_)
      return true;

    var result = this.handle_.writeMessage(
        new Uint8Array(message.buffer.arrayBuffer), message.handles);
    switch (result) {
      case Mojo.RESULT_OK:
        // The handles were successfully transferred, so we don't own them
        // anymore.
        message.handles = [];
        break;
      case Mojo.RESULT_FAILED_PRECONDITION:
        // There's no point in continuing to write to this pipe since the other
        // end is gone. Avoid writing any future messages. Hide write failures
        // from the caller since we'd like them to continue consuming any
        // backlog of incoming messages before regarding the message pipe as
        // closed.
        this.dropWrites_ = true;
        break;
      default:
        // This particular write was rejected, presumably because of bad input.
        // The pipe is not necessarily in a bad state.
        return false;
    }
    return true;
  };

  Connector.prototype.setIncomingReceiver = function(receiver) {
    this.incomingReceiver_ = receiver;
  };

  Connector.prototype.setErrorHandler = function(handler) {
    this.errorHandler_ = handler;
  };

  Connector.prototype.readMore_ = function(result) {
    for (;;) {
      if (this.paused_) {
        return;
      }

      var read = this.handle_.readMessage();
      if (this.handle_ == null) // The connector has been closed.
        return;
      if (read.result == Mojo.RESULT_SHOULD_WAIT)
        return;
      if (read.result != Mojo.RESULT_OK) {
        this.handleError(read.result !== Mojo.RESULT_FAILED_PRECONDITION,
            false);
        return;
      }
      var messageBuffer = new internal.Buffer(read.buffer);
      var message = new internal.Message(messageBuffer, read.handles);
      var receiverResult = this.incomingReceiver_ &&
          this.incomingReceiver_.accept(message);

      // Dispatching the message may have closed the connector.
      if (this.handle_ == null)
        return;

      // Handle invalid incoming message.
      if (!internal.isTestingMode() && !receiverResult) {
        // TODO(yzshen): Consider notifying the embedder.
        this.handleError(true, false);
      }
    }
  };

  Connector.prototype.cancelWait = function() {
    if (this.readWatcher_) {
      this.readWatcher_.cancel();
      this.readWatcher_ = null;
    }
  };

  Connector.prototype.waitToReadMore = function() {
    if (this.handle_) {
      this.readWatcher_ = this.handle_.watch({readable: true},
                                             this.readMore_.bind(this));
    }
  };

  Connector.prototype.handleError = function(forcePipeReset,
                                             forceAsyncHandler) {
    if (this.error_ || this.handle_ === null) {
      return;
    }

    if (this.paused_) {
      // Enforce calling the error handler asynchronously if the user has
      // paused receiving messages. We need to wait until the user starts
      // receiving messages again.
      forceAsyncHandler = true;
    }

    if (!forcePipeReset && forceAsyncHandler) {
      forcePipeReset = true;
    }

    this.cancelWait();
    if (forcePipeReset) {
      this.handle_.close();
      var dummyPipe = Mojo.createMessagePipe();
      this.handle_ = dummyPipe.handle0;
    }

    if (forceAsyncHandler) {
      if (!this.paused_) {
        this.waitToReadMore();
      }
    } else {
      this.error_ = true;
      if (this.errorHandler_) {
        this.errorHandler_.onError();
      }
    }
  };

  internal.Connector = Connector;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  function validateControlRequestWithResponse(message) {
    var messageValidator = new internal.Validator(message);
    var error = messageValidator.validateMessageIsRequestExpectingResponse();
    if (error !== internal.validationError.NONE) {
      throw error;
    }

    if (message.getName() != mojo.interfaceControl.RUN_MESSAGE_ID) {
      throw new Error("Control message name is not RUN_MESSAGE_ID");
    }

    // Validate payload.
    error = mojo.interfaceControl.RunMessageParams.validate(messageValidator,
        message.getHeaderNumBytes());
    if (error != internal.validationError.NONE) {
      throw error;
    }
  }

  function validateControlRequestWithoutResponse(message) {
    var messageValidator = new internal.Validator(message);
    var error = messageValidator.validateMessageIsRequestWithoutResponse();
    if (error != internal.validationError.NONE) {
      throw error;
    }

    if (message.getName() !=
          mojo.interfaceControl.RUN_OR_CLOSE_PIPE_MESSAGE_ID) {
      throw new Error(
        "Control message name is not RUN_OR_CLOSE_PIPE_MESSAGE_ID");
    }

    // Validate payload.
    error = mojo.interfaceControl.RunOrClosePipeMessageParams.validate(
        messageValidator, message.getHeaderNumBytes());
    if (error != internal.validationError.NONE) {
      throw error;
    }
  }

  function runOrClosePipe(message, interfaceVersion) {
    var reader = new internal.MessageReader(message);
    var runOrClosePipeMessageParams = reader.decodeStruct(
        mojo.interfaceControl.RunOrClosePipeMessageParams);
    return interfaceVersion >=
        runOrClosePipeMessageParams.input.requireVersion.version;
  }

  function run(message, responder, interfaceVersion) {
    var reader = new internal.MessageReader(message);
    var runMessageParams =
        reader.decodeStruct(mojo.interfaceControl.RunMessageParams);
    var runOutput = null;

    if (runMessageParams.input.queryVersion) {
      runOutput = new mojo.interfaceControl.RunOutput();
      runOutput.queryVersionResult = new
          mojo.interfaceControl.QueryVersionResult(
              {'version': interfaceVersion});
    }

    var runResponseMessageParams = new
        mojo.interfaceControl.RunResponseMessageParams();
    runResponseMessageParams.output = runOutput;

    var messageName = mojo.interfaceControl.RUN_MESSAGE_ID;
    var payloadSize =
        mojo.interfaceControl.RunResponseMessageParams.encodedSize;
    var requestID = reader.requestID;
    var builder = new internal.MessageV1Builder(messageName,
        payloadSize, internal.kMessageIsResponse, requestID);
    builder.encodeStruct(mojo.interfaceControl.RunResponseMessageParams,
                         runResponseMessageParams);
    responder.accept(builder.finish());
    return true;
  }

  function isInterfaceControlMessage(message) {
    return message.getName() == mojo.interfaceControl.RUN_MESSAGE_ID ||
           message.getName() ==
             mojo.interfaceControl.RUN_OR_CLOSE_PIPE_MESSAGE_ID;
  }

  function ControlMessageHandler(interfaceVersion) {
    this.interfaceVersion_ = interfaceVersion;
  }

  ControlMessageHandler.prototype.accept = function(message) {
    validateControlRequestWithoutResponse(message);
    return runOrClosePipe(message, this.interfaceVersion_);
  };

  ControlMessageHandler.prototype.acceptWithResponder = function(message,
      responder) {
    validateControlRequestWithResponse(message);
    return run(message, responder, this.interfaceVersion_);
  };

  internal.ControlMessageHandler = ControlMessageHandler;
  internal.isInterfaceControlMessage = isInterfaceControlMessage;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  function constructRunOrClosePipeMessage(runOrClosePipeInput) {
    var runOrClosePipeMessageParams = new
        mojo.interfaceControl.RunOrClosePipeMessageParams();
    runOrClosePipeMessageParams.input = runOrClosePipeInput;

    var messageName = mojo.interfaceControl.RUN_OR_CLOSE_PIPE_MESSAGE_ID;
    var payloadSize =
        mojo.interfaceControl.RunOrClosePipeMessageParams.encodedSize;
    var builder = new internal.MessageV0Builder(messageName, payloadSize);
    builder.encodeStruct(mojo.interfaceControl.RunOrClosePipeMessageParams,
                         runOrClosePipeMessageParams);
    var message = builder.finish();
    return message;
  }

  function validateControlResponse(message) {
    var messageValidator = new internal.Validator(message);
    var error = messageValidator.validateMessageIsResponse();
    if (error != internal.validationError.NONE) {
      throw error;
    }

    if (message.getName() != mojo.interfaceControl.RUN_MESSAGE_ID) {
      throw new Error("Control message name is not RUN_MESSAGE_ID");
    }

    // Validate payload.
    error = mojo.interfaceControl.RunResponseMessageParams.validate(
        messageValidator, message.getHeaderNumBytes());
    if (error != internal.validationError.NONE) {
      throw error;
    }
  }

  function acceptRunResponse(message) {
    validateControlResponse(message);

    var reader = new internal.MessageReader(message);
    var runResponseMessageParams = reader.decodeStruct(
        mojo.interfaceControl.RunResponseMessageParams);

    return Promise.resolve(runResponseMessageParams);
  }

 /**
  * Sends the given run message through the receiver.
  * Accepts the response message from the receiver and decodes the message
  * struct to RunResponseMessageParams.
  *
  * @param  {Router} receiver
  * @param  {RunMessageParams} runMessageParams to be sent via a message.
  * @return {Promise} that resolves to a RunResponseMessageParams.
  */
  function sendRunMessage(receiver, runMessageParams) {
    var messageName = mojo.interfaceControl.RUN_MESSAGE_ID;
    var payloadSize = mojo.interfaceControl.RunMessageParams.encodedSize;
    // |requestID| is set to 0, but is later properly set by Router.
    var builder = new internal.MessageV1Builder(messageName,
        payloadSize, internal.kMessageExpectsResponse, 0);
    builder.encodeStruct(mojo.interfaceControl.RunMessageParams,
                         runMessageParams);
    var message = builder.finish();

    return receiver.acceptAndExpectResponse(message).then(acceptRunResponse);
  }

  function ControlMessageProxy(receiver) {
    this.receiver_ = receiver;
  }

  ControlMessageProxy.prototype.queryVersion = function() {
    var runMessageParams = new mojo.interfaceControl.RunMessageParams();
    runMessageParams.input = new mojo.interfaceControl.RunInput();
    runMessageParams.input.queryVersion =
        new mojo.interfaceControl.QueryVersion();

    return sendRunMessage(this.receiver_, runMessageParams).then(function(
        runResponseMessageParams) {
      return runResponseMessageParams.output.queryVersionResult.version;
    });
  };

  ControlMessageProxy.prototype.requireVersion = function(version) {
    var runOrClosePipeInput = new mojo.interfaceControl.RunOrClosePipeInput();
    runOrClosePipeInput.requireVersion =
        new mojo.interfaceControl.RequireVersion({'version': version});
    var message = constructRunOrClosePipeMessage(runOrClosePipeInput);
    this.receiver_.accept(message);
  };

  internal.ControlMessageProxy = ControlMessageProxy;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  function InterfaceEndpointClient(interfaceEndpointHandle, receiver,
      interfaceVersion) {
    this.controller_ = null;
    this.encounteredError_ = false;
    this.handle_ = interfaceEndpointHandle;
    this.incomingReceiver_ = receiver;

    if (interfaceVersion !== undefined) {
      this.controlMessageHandler_ = new internal.ControlMessageHandler(
          interfaceVersion);
    } else {
      this.controlMessageProxy_ = new internal.ControlMessageProxy(this);
    }

    this.nextRequestID_ = 0;
    this.completers_ = new Map();
    this.payloadValidators_ = [];
    this.connectionErrorHandler_ = null;

    if (interfaceEndpointHandle.pendingAssociation()) {
      interfaceEndpointHandle.setAssociationEventHandler(
          this.onAssociationEvent.bind(this));
    } else {
      this.initControllerIfNecessary_();
    }
  }

  InterfaceEndpointClient.prototype.initControllerIfNecessary_ = function() {
    if (!this.handle_) {
      return false;
    }

    if (this.controller_ || this.handle_.pendingAssociation()) {
      return true;
    }

    this.controller_ = this.handle_.groupController().attachEndpointClient(
        this.handle_, this);
    return true;
  };

  InterfaceEndpointClient.prototype.onAssociationEvent = function(
      associationEvent) {
    if (associationEvent === internal.AssociationEvent.ASSOCIATED) {
      this.initControllerIfNecessary_();
    } else if (associationEvent ===
          internal.AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION) {
      setTimeout(this.notifyError.bind(this, this.handle_.disconnectReason()),
                 0);
    }
  };

  InterfaceEndpointClient.prototype.passHandle = function() {
    if (!this.handle_.isValid()) {
      return new internal.InterfaceEndpointHandle();
    }

    // Used to clear the previously set callback.
    this.handle_.setAssociationEventHandler(undefined);

    if (this.controller_) {
      this.controller_ = null;
      this.handle_.groupController().detachEndpointClient(this.handle_);
    }
    var handle = this.handle_;
    this.handle_ = null;
    return handle;
  };

  InterfaceEndpointClient.prototype.close = function(reason) {
    var handle = this.passHandle();
    handle.reset(reason);
  };

  InterfaceEndpointClient.prototype.accept = function(message) {
    if (message.associatedEndpointHandles.length > 0) {
      message.serializeAssociatedEndpointHandles(
          this.handle_.groupController());
    }

    if (this.encounteredError_) {
      return false;
    }

    if (!this.initControllerIfNecessary_()) {
      return false;
    }
    return this.controller_.sendMessage(message);
  };

  InterfaceEndpointClient.prototype.acceptAndExpectResponse = function(
      message) {
    if (message.associatedEndpointHandles.length > 0) {
      message.serializeAssociatedEndpointHandles(
          this.handle_.groupController());
    }

    if (this.encounteredError_) {
      return Promise.reject();
    }

    if (!this.initControllerIfNecessary_()) {
      return Promise.reject(Error('Endpoint has been closed'));
    }

    // Reserve 0 in case we want it to convey special meaning in the future.
    var requestID = this.nextRequestID_++;
    if (requestID === 0)
      requestID = this.nextRequestID_++;

    message.setRequestID(requestID);
    var result = this.controller_.sendMessage(message);
    if (!result)
      return Promise.reject(Error("Connection error"));

    var completer = {};
    this.completers_.set(requestID, completer);
    return new Promise(function(resolve, reject) {
      completer.resolve = resolve;
      completer.reject = reject;
    });
  };

  InterfaceEndpointClient.prototype.setPayloadValidators = function(
      payloadValidators) {
    this.payloadValidators_ = payloadValidators;
  };

  InterfaceEndpointClient.prototype.setIncomingReceiver = function(receiver) {
    this.incomingReceiver_ = receiver;
  };

  InterfaceEndpointClient.prototype.setConnectionErrorHandler = function(
      handler) {
    this.connectionErrorHandler_ = handler;
  };

  InterfaceEndpointClient.prototype.handleIncomingMessage = function(message,
      messageValidator) {
    var noError = internal.validationError.NONE;
    var err = noError;
    for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i)
      err = this.payloadValidators_[i](messageValidator);

    if (err == noError) {
      return this.handleValidIncomingMessage_(message);
    } else {
      internal.reportValidationError(err);
      return false;
    }
  };

  InterfaceEndpointClient.prototype.handleValidIncomingMessage_ = function(
      message) {
    if (internal.isTestingMode()) {
      return true;
    }

    if (this.encounteredError_) {
      return false;
    }

    var ok = false;

    if (message.expectsResponse()) {
      if (internal.isInterfaceControlMessage(message) &&
          this.controlMessageHandler_) {
        ok = this.controlMessageHandler_.acceptWithResponder(message, this);
      } else if (this.incomingReceiver_) {
        ok = this.incomingReceiver_.acceptWithResponder(message, this);
      }
    } else if (message.isResponse()) {
      var reader = new internal.MessageReader(message);
      var requestID = reader.requestID;
      var completer = this.completers_.get(requestID);
      if (completer) {
        this.completers_.delete(requestID);
        completer.resolve(message);
        ok = true;
      } else {
        console.log("Unexpected response with request ID: " + requestID);
      }
    } else {
      if (internal.isInterfaceControlMessage(message) &&
          this.controlMessageHandler_) {
        ok = this.controlMessageHandler_.accept(message);
      } else if (this.incomingReceiver_) {
        ok = this.incomingReceiver_.accept(message);
      }
    }
    return ok;
  };

  InterfaceEndpointClient.prototype.notifyError = function(reason) {
    if (this.encounteredError_) {
      return;
    }
    this.encounteredError_ = true;

    this.completers_.forEach(function(value) {
      value.reject();
    });
    this.completers_.clear();  // Drop any responders.

    if (this.connectionErrorHandler_) {
      this.connectionErrorHandler_(reason);
    }
  };

  InterfaceEndpointClient.prototype.queryVersion = function() {
    return this.controlMessageProxy_.queryVersion();
  };

  InterfaceEndpointClient.prototype.requireVersion = function(version) {
    this.controlMessageProxy_.requireVersion(version);
  };

  InterfaceEndpointClient.prototype.getEncounteredError = function() {
    return this.encounteredError_;
  };

  internal.InterfaceEndpointClient = InterfaceEndpointClient;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  var AssociationEvent = {
    // The interface has been associated with a message pipe.
    ASSOCIATED: 'associated',
    // The peer of this object has been closed before association.
    PEER_CLOSED_BEFORE_ASSOCIATION: 'peer_closed_before_association'
  };

  function State(interfaceId, associatedGroupController) {
    if (interfaceId === undefined) {
      interfaceId = internal.kInvalidInterfaceId;
    }

    this.interfaceId = interfaceId;
    this.associatedGroupController = associatedGroupController;
    this.pendingAssociation = false;
    this.disconnectReason = null;
    this.peerState_ = null;
    this.associationEventHandler_ = null;
  }

  State.prototype.initPendingState = function(peer) {
    this.pendingAssociation = true;
    this.peerState_ = peer;
  };

  State.prototype.isValid = function() {
    return this.pendingAssociation ||
        internal.isValidInterfaceId(this.interfaceId);
  };

  State.prototype.close = function(disconnectReason) {
    var cachedGroupController;
    var cachedPeerState;
    var cachedId = internal.kInvalidInterfaceId;

    if (!this.pendingAssociation) {
      if (internal.isValidInterfaceId(this.interfaceId)) {
        cachedGroupController = this.associatedGroupController;
        this.associatedGroupController = null;
        cachedId = this.interfaceId;
        this.interfaceId = internal.kInvalidInterfaceId;
      }
    } else {
      this.pendingAssociation = false;
      cachedPeerState = this.peerState_;
      this.peerState_ = null;
    }

    if (cachedGroupController) {
      cachedGroupController.closeEndpointHandle(cachedId,
          disconnectReason);
    } else if (cachedPeerState) {
      cachedPeerState.onPeerClosedBeforeAssociation(disconnectReason);
    }
  };

  State.prototype.runAssociationEventHandler = function(associationEvent) {
    if (this.associationEventHandler_) {
      var handler = this.associationEventHandler_;
      this.associationEventHandler_ = null;
      handler(associationEvent);
    }
  };

  State.prototype.setAssociationEventHandler = function(handler) {
    if (!this.pendingAssociation &&
        !internal.isValidInterfaceId(this.interfaceId)) {
      return;
    }

    if (!handler) {
      this.associationEventHandler_ = null;
      return;
    }

    this.associationEventHandler_ = handler;
    if (!this.pendingAssociation) {
      setTimeout(this.runAssociationEventHandler.bind(this,
          AssociationEvent.ASSOCIATED), 0);
    } else if (!this.peerState_) {
      setTimeout(this.runAssociationEventHandler.bind(this,
          AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION), 0);
    }
  };

  State.prototype.notifyAssociation = function(interfaceId,
                                               peerGroupController) {
    var cachedPeerState = this.peerState_;
    this.peerState_ = null;

    this.pendingAssociation = false;

    if (cachedPeerState) {
      cachedPeerState.onAssociated(interfaceId, peerGroupController);
      return true;
    }
    return false;
  };

  State.prototype.onAssociated = function(interfaceId,
      associatedGroupController) {
    if (!this.pendingAssociation) {
      return;
    }

    this.pendingAssociation = false;
    this.peerState_ = null;
    this.interfaceId = interfaceId;
    this.associatedGroupController = associatedGroupController;
    this.runAssociationEventHandler(AssociationEvent.ASSOCIATED);
  };

  State.prototype.onPeerClosedBeforeAssociation = function(disconnectReason) {
    if (!this.pendingAssociation) {
      return;
    }

    this.peerState_ = null;
    this.disconnectReason = disconnectReason;

    this.runAssociationEventHandler(
        AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION);
  };

  function createPairPendingAssociation() {
    var handle0 = new InterfaceEndpointHandle();
    var handle1 = new InterfaceEndpointHandle();
    handle0.state_.initPendingState(handle1.state_);
    handle1.state_.initPendingState(handle0.state_);
    return {handle0: handle0, handle1: handle1};
  }

  function InterfaceEndpointHandle(interfaceId, associatedGroupController) {
    this.state_ = new State(interfaceId, associatedGroupController);
  }

  InterfaceEndpointHandle.prototype.isValid = function() {
    return this.state_.isValid();
  };

  InterfaceEndpointHandle.prototype.pendingAssociation = function() {
    return this.state_.pendingAssociation;
  };

  InterfaceEndpointHandle.prototype.id = function() {
    return this.state_.interfaceId;
  };

  InterfaceEndpointHandle.prototype.groupController = function() {
    return this.state_.associatedGroupController;
  };

  InterfaceEndpointHandle.prototype.disconnectReason = function() {
    return this.state_.disconnectReason;
  };

  InterfaceEndpointHandle.prototype.setAssociationEventHandler = function(
      handler) {
    this.state_.setAssociationEventHandler(handler);
  };

  InterfaceEndpointHandle.prototype.notifyAssociation = function(interfaceId,
      peerGroupController) {
    return this.state_.notifyAssociation(interfaceId, peerGroupController);
  };

  InterfaceEndpointHandle.prototype.reset = function(reason) {
    this.state_.close(reason);
    this.state_ = new State();
  };

  internal.AssociationEvent = AssociationEvent;
  internal.InterfaceEndpointHandle = InterfaceEndpointHandle;
  internal.createPairPendingAssociation = createPairPendingAssociation;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  function validateControlRequestWithoutResponse(message) {
    var messageValidator = new internal.Validator(message);
    var error = messageValidator.validateMessageIsRequestWithoutResponse();
    if (error != internal.validationError.NONE) {
      throw error;
    }

    if (message.getName() != mojo.pipeControl.RUN_OR_CLOSE_PIPE_MESSAGE_ID) {
      throw new Error(
        "Control message name is not RUN_OR_CLOSE_PIPE_MESSAGE_ID");
    }

    // Validate payload.
    error = mojo.pipeControl.RunOrClosePipeMessageParams.validate(
        messageValidator, message.getHeaderNumBytes());
    if (error != internal.validationError.NONE) {
      throw error;
    }
  }

  function runOrClosePipe(message, delegate) {
    var reader = new internal.MessageReader(message);
    var runOrClosePipeMessageParams = reader.decodeStruct(
        mojo.pipeControl.RunOrClosePipeMessageParams);
    var event = runOrClosePipeMessageParams.input
        .peerAssociatedEndpointClosedEvent;
    return delegate.onPeerAssociatedEndpointClosed(event.id,
        event.disconnectReason);
  }

  function isPipeControlMessage(message) {
    return !internal.isValidInterfaceId(message.getInterfaceId());
  }

  function PipeControlMessageHandler(delegate) {
    this.delegate_ = delegate;
  }

  PipeControlMessageHandler.prototype.accept = function(message) {
    validateControlRequestWithoutResponse(message);
    return runOrClosePipe(message, this.delegate_);
  };

  internal.PipeControlMessageHandler = PipeControlMessageHandler;
  internal.isPipeControlMessage = isPipeControlMessage;
})();
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  function constructRunOrClosePipeMessage(runOrClosePipeInput) {
    var runOrClosePipeMessageParams = new
        mojo.pipeControl.RunOrClosePipeMessageParams();
    runOrClosePipeMessageParams.input = runOrClosePipeInput;

    var messageName = mojo.pipeControl.RUN_OR_CLOSE_PIPE_MESSAGE_ID;
    var payloadSize =
        mojo.pipeControl.RunOrClosePipeMessageParams.encodedSize;

    var builder = new internal.MessageV0Builder(messageName, payloadSize);
    builder.encodeStruct(mojo.pipeControl.RunOrClosePipeMessageParams,
                         runOrClosePipeMessageParams);
    var message = builder.finish();
    message.setInterfaceId(internal.kInvalidInterfaceId);
    return message;
  }

  function PipeControlMessageProxy(receiver) {
    this.receiver_ = receiver;
  }

  PipeControlMessageProxy.prototype.notifyPeerEndpointClosed = function(
      interfaceId, reason) {
    var message = this.constructPeerEndpointClosedMessage(interfaceId, reason);
    this.receiver_.accept(message);
  };

  PipeControlMessageProxy.prototype.constructPeerEndpointClosedMessage =
      function(interfaceId, reason) {
    var event = new mojo.pipeControl.PeerAssociatedEndpointClosedEvent();
    event.id = interfaceId;
    if (reason) {
      event.disconnectReason = new mojo.pipeControl.DisconnectReason({
          customReason: reason.customReason,
          description: reason.description});
    }
    var runOrClosePipeInput = new mojo.pipeControl.RunOrClosePipeInput();
    runOrClosePipeInput.peerAssociatedEndpointClosedEvent = event;
    return constructRunOrClosePipeMessage(runOrClosePipeInput);
  };

  internal.PipeControlMessageProxy = PipeControlMessageProxy;
})();
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  /**
   * The state of |endpoint|. If both the endpoint and its peer have been
   * closed, removes it from |endpoints_|.
   * @enum {string}
   */
  var EndpointStateUpdateType = {
    ENDPOINT_CLOSED: 'endpoint_closed',
    PEER_ENDPOINT_CLOSED: 'peer_endpoint_closed'
  };

  function check(condition, output) {
    if (!condition) {
      // testharness.js does not rethrow errors so the error stack needs to be
      // included as a string in the error we throw for debugging layout tests.
      throw new Error((new Error()).stack);
    }
  }

  function InterfaceEndpoint(router, interfaceId) {
    this.router_ = router;
    this.id = interfaceId;
    this.closed = false;
    this.peerClosed = false;
    this.handleCreated = false;
    this.disconnectReason = null;
    this.client = null;
  }

  InterfaceEndpoint.prototype.sendMessage = function(message) {
    message.setInterfaceId(this.id);
    return this.router_.connector_.accept(message);
  };

  function Router(handle, setInterfaceIdNamespaceBit) {
    if (!(handle instanceof MojoHandle)) {
      throw new Error("Router constructor: Not a handle");
    }
    if (setInterfaceIdNamespaceBit === undefined) {
      setInterfaceIdNamespaceBit = false;
    }

    this.connector_ = new internal.Connector(handle);

    this.connector_.setIncomingReceiver({
        accept: this.accept.bind(this),
    });
    this.connector_.setErrorHandler({
        onError: this.onPipeConnectionError.bind(this),
    });

    this.setInterfaceIdNamespaceBit_ = setInterfaceIdNamespaceBit;
    // |cachedMessageData| caches infomation about a message, so it can be
    // processed later if a client is not yet attached to the target endpoint.
    this.cachedMessageData = null;
    this.controlMessageHandler_ = new internal.PipeControlMessageHandler(this);
    this.controlMessageProxy_ =
        new internal.PipeControlMessageProxy(this.connector_);
    this.nextInterfaceIdValue_ = 1;
    this.encounteredError_ = false;
    this.endpoints_ = new Map();
  }

  Router.prototype.associateInterface = function(handleToSend) {
    if (!handleToSend.pendingAssociation()) {
      return internal.kInvalidInterfaceId;
    }

    var id = 0;
    do {
      if (this.nextInterfaceIdValue_ >= internal.kInterfaceIdNamespaceMask) {
        this.nextInterfaceIdValue_ = 1;
      }
      id = this.nextInterfaceIdValue_++;
      if (this.setInterfaceIdNamespaceBit_) {
        id += internal.kInterfaceIdNamespaceMask;
      }
    } while (this.endpoints_.has(id));

    var endpoint = new InterfaceEndpoint(this, id);
    this.endpoints_.set(id, endpoint);
    if (this.encounteredError_) {
      this.updateEndpointStateMayRemove(endpoint,
          EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
    }
    endpoint.handleCreated = true;

    if (!handleToSend.notifyAssociation(id, this)) {
      // The peer handle of |handleToSend|, which is supposed to join this
      // associated group, has been closed.
      this.updateEndpointStateMayRemove(endpoint,
          EndpointStateUpdateType.ENDPOINT_CLOSED);

      pipeControlMessageproxy.notifyPeerEndpointClosed(id,
          handleToSend.disconnectReason());
    }

    return id;
  };

  Router.prototype.attachEndpointClient = function(
      interfaceEndpointHandle, interfaceEndpointClient) {
    check(internal.isValidInterfaceId(interfaceEndpointHandle.id()));
    check(interfaceEndpointClient);

    var endpoint = this.endpoints_.get(interfaceEndpointHandle.id());
    check(endpoint);
    check(!endpoint.client);
    check(!endpoint.closed);
    endpoint.client = interfaceEndpointClient;

    if (endpoint.peerClosed) {
      setTimeout(endpoint.client.notifyError.bind(endpoint.client), 0);
    }

    if (this.cachedMessageData && interfaceEndpointHandle.id() ===
        this.cachedMessageData.message.getInterfaceId()) {
      setTimeout((function() {
        if (!this.cachedMessageData) {
          return;
        }

        var targetEndpoint = this.endpoints_.get(
            this.cachedMessageData.message.getInterfaceId());
        // Check that the target endpoint's client still exists.
        if (targetEndpoint && targetEndpoint.client) {
          var message = this.cachedMessageData.message;
          var messageValidator = this.cachedMessageData.messageValidator;
          this.cachedMessageData = null;
          this.connector_.resumeIncomingMethodCallProcessing();
          var ok = endpoint.client.handleIncomingMessage(message,
              messageValidator);

          // Handle invalid cached incoming message.
          if (!internal.isTestingMode() && !ok) {
            this.connector_.handleError(true, true);
          }
        }
      }).bind(this), 0);
    }

    return endpoint;
  };

  Router.prototype.detachEndpointClient = function(
      interfaceEndpointHandle) {
    check(internal.isValidInterfaceId(interfaceEndpointHandle.id()));
    var endpoint = this.endpoints_.get(interfaceEndpointHandle.id());
    check(endpoint);
    check(endpoint.client);
    check(!endpoint.closed);

    endpoint.client = null;
  };

  Router.prototype.createLocalEndpointHandle = function(
      interfaceId) {
    if (!internal.isValidInterfaceId(interfaceId)) {
      return new internal.InterfaceEndpointHandle();
    }

    // Unless it is the primary ID, |interfaceId| is from the remote side and
    // therefore its namespace bit is supposed to be different than the value
    // that this router would use.
    if (!internal.isPrimaryInterfaceId(interfaceId) &&
        this.setInterfaceIdNamespaceBit_ ===
            internal.hasInterfaceIdNamespaceBitSet(interfaceId)) {
      return new internal.InterfaceEndpointHandle();
    }

    var endpoint = this.endpoints_.get(interfaceId);

    if (!endpoint) {
      endpoint = new InterfaceEndpoint(this, interfaceId);
      this.endpoints_.set(interfaceId, endpoint);

      check(!endpoint.handleCreated);

      if (this.encounteredError_) {
        this.updateEndpointStateMayRemove(endpoint,
            EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
      }
    } else {
      // If the endpoint already exist, it is because we have received a
      // notification that the peer endpoint has closed.
      check(!endpoint.closed);
      check(endpoint.peerClosed);

      if (endpoint.handleCreated) {
        return new internal.InterfaceEndpointHandle();
      }
    }

    endpoint.handleCreated = true;
    return new internal.InterfaceEndpointHandle(interfaceId, this);
  };

  Router.prototype.accept = function(message) {
    var messageValidator = new internal.Validator(message);
    var err = messageValidator.validateMessageHeader();

    var ok = false;
    if (err !== internal.validationError.NONE) {
      internal.reportValidationError(err);
    } else if (message.deserializeAssociatedEndpointHandles(this)) {
      if (internal.isPipeControlMessage(message)) {
        ok = this.controlMessageHandler_.accept(message);
      } else {
        var interfaceId = message.getInterfaceId();
        var endpoint = this.endpoints_.get(interfaceId);
        if (!endpoint || endpoint.closed) {
          return true;
        }

        if (!endpoint.client) {
          // We need to wait until a client is attached in order to dispatch
          // further messages.
          this.cachedMessageData = {message: message,
              messageValidator: messageValidator};
          this.connector_.pauseIncomingMethodCallProcessing();
          return true;
        }
        ok = endpoint.client.handleIncomingMessage(message, messageValidator);
      }
    }
    return ok;
  };

  Router.prototype.close = function() {
    this.connector_.close();
    // Closing the message pipe won't trigger connection error handler.
    // Explicitly call onPipeConnectionError() so that associated endpoints
    // will get notified.
    this.onPipeConnectionError();
  };

  Router.prototype.onPeerAssociatedEndpointClosed = function(interfaceId,
      reason) {
    var endpoint = this.endpoints_.get(interfaceId);
    if (!endpoint) {
      endpoint = new InterfaceEndpoint(this, interfaceId);
      this.endpoints_.set(interfaceId, endpoint);
    }

    if (reason) {
      endpoint.disconnectReason = reason;
    }

    if (!endpoint.peerClosed) {
      if (endpoint.client) {
        setTimeout(endpoint.client.notifyError.bind(endpoint.client, reason),
                   0);
      }
      this.updateEndpointStateMayRemove(endpoint,
          EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
    }
    return true;
  };

  Router.prototype.onPipeConnectionError = function() {
    this.encounteredError_ = true;

    for (var endpoint of this.endpoints_.values()) {
      if (endpoint.client) {
        setTimeout(
            endpoint.client.notifyError.bind(
                endpoint.client, endpoint.disconnectReason),
            0);
      }
      this.updateEndpointStateMayRemove(endpoint,
          EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
    }
  };

  Router.prototype.closeEndpointHandle = function(interfaceId, reason) {
    if (!internal.isValidInterfaceId(interfaceId)) {
      return;
    }
    var endpoint = this.endpoints_.get(interfaceId);
    check(endpoint);
    check(!endpoint.client);
    check(!endpoint.closed);

    this.updateEndpointStateMayRemove(endpoint,
        EndpointStateUpdateType.ENDPOINT_CLOSED);

    if (!internal.isPrimaryInterfaceId(interfaceId) || reason) {
      this.controlMessageProxy_.notifyPeerEndpointClosed(interfaceId, reason);
    }

    if (this.cachedMessageData && interfaceId ===
        this.cachedMessageData.message.getInterfaceId()) {
      this.cachedMessageData = null;
      this.connector_.resumeIncomingMethodCallProcessing();
    }
  };

  Router.prototype.updateEndpointStateMayRemove = function(endpoint,
      endpointStateUpdateType) {
    if (endpointStateUpdateType === EndpointStateUpdateType.ENDPOINT_CLOSED) {
      endpoint.closed = true;
    } else {
      endpoint.peerClosed = true;
    }
    if (endpoint.closed && endpoint.peerClosed) {
      this.endpoints_.delete(endpoint.id);
    }
  };

  internal.Router = Router;
})();
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Defines functions for translating between JavaScript strings and UTF8 strings
 * stored in ArrayBuffers. There is much room for optimization in this code if
 * it proves necessary.
 */
(function() {
  var internal = mojo.internal;
  var textDecoder = new TextDecoder('utf-8');
  var textEncoder = new TextEncoder('utf-8');

  /**
   * Decodes the UTF8 string from the given buffer.
   * @param {ArrayBufferView} buffer The buffer containing UTF8 string data.
   * @return {string} The corresponding JavaScript string.
   */
  function decodeUtf8String(buffer) {
    return textDecoder.decode(buffer);
  }

  /**
   * Encodes the given JavaScript string into UTF8.
   * @param {string} str The string to encode.
   * @param {ArrayBufferView} outputBuffer The buffer to contain the result.
   * Should be pre-allocated to hold enough space. Use |utf8Length| to determine
   * how much space is required.
   * @return {number} The number of bytes written to |outputBuffer|.
   */
  function encodeUtf8String(str, outputBuffer) {
    const utf8Buffer = textEncoder.encode(str);
    if (outputBuffer.length < utf8Buffer.length)
      throw new Error("Buffer too small for encodeUtf8String");
    outputBuffer.set(utf8Buffer);
    return utf8Buffer.length;
  }

  /**
   * Returns the number of bytes that a UTF8 encoding of the JavaScript string
   * |str| would occupy.
   */
  function utf8Length(str) {
    return textEncoder.encode(str).length;
  }

  internal.decodeUtf8String = decodeUtf8String;
  internal.encodeUtf8String = encodeUtf8String;
  internal.utf8Length = utf8Length;
})();
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
  var internal = mojo.internal;

  var validationError = {
    NONE: 'VALIDATION_ERROR_NONE',
    MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT',
    ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE',
    UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER',
    UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER',
    ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE',
    UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE',
    ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER',
    UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER',
    ILLEGAL_INTERFACE_ID: 'VALIDATION_ERROR_ILLEGAL_INTERFACE_ID',
    UNEXPECTED_INVALID_INTERFACE_ID:
        'VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID',
    MESSAGE_HEADER_INVALID_FLAGS:
        'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS',
    MESSAGE_HEADER_MISSING_REQUEST_ID:
        'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID',
    DIFFERENT_SIZED_ARRAYS_IN_MAP:
        'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
    INVALID_UNION_SIZE: 'VALIDATION_ERROR_INVALID_UNION_SIZE',
    UNEXPECTED_NULL_UNION: 'VALIDATION_ERROR_UNEXPECTED_NULL_UNION',
    UNKNOWN_ENUM_VALUE: 'VALIDATION_ERROR_UNKNOWN_ENUM_VALUE',
  };

  var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
  var gValidationErrorObserver = null;

  function reportValidationError(error) {
    if (gValidationErrorObserver) {
      gValidationErrorObserver.lastError = error;
    } else {
      console.warn('Invalid message: ' + error);
    }
  }

  var ValidationErrorObserverForTesting = (function() {
    function Observer() {
      this.lastError = validationError.NONE;
    }

    Observer.prototype.reset = function() {
      this.lastError = validationError.NONE;
    };

    return {
      getInstance: function() {
        if (!gValidationErrorObserver) {
          gValidationErrorObserver = new Observer();
        }
        return gValidationErrorObserver;
      }
    };
  })();

  function isTestingMode() {
    return Boolean(gValidationErrorObserver);
  }

  function clearTestingMode() {
    gValidationErrorObserver = null;
  }

  function isEnumClass(cls) {
    return cls instanceof internal.Enum;
  }

  function isStringClass(cls) {
    return cls === internal.String || cls === internal.NullableString;
  }

  function isHandleClass(cls) {
    return cls === internal.Handle || cls === internal.NullableHandle;
  }

  function isInterfaceClass(cls) {
    return cls instanceof internal.Interface;
  }

  function isInterfaceRequestClass(cls) {
    return cls === internal.InterfaceRequest ||
        cls === internal.NullableInterfaceRequest;
  }

  function isAssociatedInterfaceClass(cls) {
    return cls === internal.AssociatedInterfacePtrInfo ||
        cls === internal.NullableAssociatedInterfacePtrInfo;
  }

  function isAssociatedInterfaceRequestClass(cls) {
    return cls === internal.AssociatedInterfaceRequest ||
        cls === internal.NullableAssociatedInterfaceRequest;
  }

  function isNullable(type) {
    return type === internal.NullableString ||
        type === internal.NullableHandle ||
        type === internal.NullableAssociatedInterfacePtrInfo ||
        type === internal.NullableAssociatedInterfaceRequest ||
        type === internal.NullableInterface ||
        type === internal.NullableInterfaceRequest ||
        type instanceof internal.NullableArrayOf ||
        type instanceof internal.NullablePointerTo;
  }

  function Validator(message) {
    this.message = message;
    this.offset = 0;
    this.handleIndex = 0;
    this.associatedEndpointHandleIndex = 0;
    this.payloadInterfaceIds = null;
    this.offsetLimit = this.message.buffer.byteLength;
  }

  Object.defineProperty(Validator.prototype, "handleIndexLimit", {
    get: function() { return this.message.handles.length; }
  });

  Object.defineProperty(Validator.prototype, "associatedHandleIndexLimit", {
    get: function() {
      return this.payloadInterfaceIds ? this.payloadInterfaceIds.length : 0;
    }
  });

  // True if we can safely allocate a block of bytes from start to
  // to start + numBytes.
  Validator.prototype.isValidRange = function(start, numBytes) {
    // Only positive JavaScript integers that are less than 2^53
    // (Number.MAX_SAFE_INTEGER) can be represented exactly.
    if (start < this.offset || numBytes <= 0 ||
        !Number.isSafeInteger(start) ||
        !Number.isSafeInteger(numBytes))
      return false;

    var newOffset = start + numBytes;
    if (!Number.isSafeInteger(newOffset) || newOffset > this.offsetLimit)
      return false;

    return true;
  };

  Validator.prototype.claimRange = function(start, numBytes) {
    if (this.isValidRange(start, numBytes)) {
      this.offset = start + numBytes;
      return true;
    }
    return false;
  };

  Validator.prototype.claimHandle = function(index) {
    if (index === internal.kEncodedInvalidHandleValue)
      return true;

    if (index < this.handleIndex || index >= this.handleIndexLimit)
      return false;

    // This is safe because handle indices are uint32.
    this.handleIndex = index + 1;
    return true;
  };

  Validator.prototype.claimAssociatedEndpointHandle = function(index) {
    if (index === internal.kEncodedInvalidHandleValue) {
      return true;
    }

    if (index < this.associatedEndpointHandleIndex ||
        index >= this.associatedHandleIndexLimit) {
      return false;
    }

    // This is safe because handle indices are uint32.
    this.associatedEndpointHandleIndex = index + 1;
    return true;
  };

  Validator.prototype.validateEnum = function(offset, enumClass) {
    // Note: Assumes that enums are always 32 bits! But this matches
    // mojom::generate::pack::PackedField::GetSizeForKind, so it should be okay.
    var value = this.message.buffer.getInt32(offset);
    return enumClass.validate(value);
  }

  Validator.prototype.validateHandle = function(offset, nullable) {
    var index = this.message.buffer.getUint32(offset);

    if (index === internal.kEncodedInvalidHandleValue)
      return nullable ?
          validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE;

    if (!this.claimHandle(index))
      return validationError.ILLEGAL_HANDLE;

    return validationError.NONE;
  };

  Validator.prototype.validateAssociatedEndpointHandle = function(offset,
      nullable) {
    var index = this.message.buffer.getUint32(offset);

    if (index === internal.kEncodedInvalidHandleValue) {
      return nullable ? validationError.NONE :
          validationError.UNEXPECTED_INVALID_INTERFACE_ID;
    }

    if (!this.claimAssociatedEndpointHandle(index)) {
      return validationError.ILLEGAL_INTERFACE_ID;
    }

    return validationError.NONE;
  };

  Validator.prototype.validateInterface = function(offset, nullable) {
    return this.validateHandle(offset, nullable);
  };

  Validator.prototype.validateInterfaceRequest = function(offset, nullable) {
    return this.validateHandle(offset, nullable);
  };

  Validator.prototype.validateAssociatedInterface = function(offset,
      nullable) {
    return this.validateAssociatedEndpointHandle(offset, nullable);
  };

  Validator.prototype.validateAssociatedInterfaceRequest = function(
      offset, nullable) {
    return this.validateAssociatedEndpointHandle(offset, nullable);
  };

  Validator.prototype.validateStructHeader = function(offset, minNumBytes) {
    if (!internal.isAligned(offset))
      return validationError.MISALIGNED_OBJECT;

    if (!this.isValidRange(offset, internal.kStructHeaderSize))
      return validationError.ILLEGAL_MEMORY_RANGE;

    var numBytes = this.message.buffer.getUint32(offset);

    if (numBytes < minNumBytes)
      return validationError.UNEXPECTED_STRUCT_HEADER;

    if (!this.claimRange(offset, numBytes))
      return validationError.ILLEGAL_MEMORY_RANGE;

    return validationError.NONE;
  };

  Validator.prototype.validateStructVersion = function(offset, versionSizes) {
    var numBytes = this.message.buffer.getUint32(offset);
    var version = this.message.buffer.getUint32(offset + 4);

    if (version <= versionSizes[versionSizes.length - 1].version) {
      // Scan in reverse order to optimize for more recent versionSizes.
      for (var i = versionSizes.length - 1; i >= 0; --i) {
        if (version >= versionSizes[i].version) {
          if (numBytes == versionSizes[i].numBytes)
            break;
          return validationError.UNEXPECTED_STRUCT_HEADER;
        }
      }
    } else if (numBytes < versionSizes[versionSizes.length-1].numBytes) {
      return validationError.UNEXPECTED_STRUCT_HEADER;
    }

    return validationError.NONE;
  };

  Validator.prototype.isFieldInStructVersion = function(offset, fieldVersion) {
    var structVersion = this.message.buffer.getUint32(offset + 4);
    return fieldVersion <= structVersion;
  };

  Validator.prototype.validateMessageHeader = function() {
    var err = this.validateStructHeader(0, internal.kMessageV0HeaderSize);
    if (err != validationError.NONE) {
      return err;
    }

    var numBytes = this.message.getHeaderNumBytes();
    var version = this.message.getHeaderVersion();

    var validVersionAndNumBytes =
        (version == 0 && numBytes == internal.kMessageV0HeaderSize) ||
        (version == 1 && numBytes == internal.kMessageV1HeaderSize) ||
        (version == 2 && numBytes == internal.kMessageV2HeaderSize) ||
        (version > 2 && numBytes >= internal.kMessageV2HeaderSize);

    if (!validVersionAndNumBytes) {
      return validationError.UNEXPECTED_STRUCT_HEADER;
    }

    var expectsResponse = this.message.expectsResponse();
    var isResponse = this.message.isResponse();

    if (version == 0 && (expectsResponse || isResponse)) {
      return validationError.MESSAGE_HEADER_MISSING_REQUEST_ID;
    }

    if (isResponse && expectsResponse) {
      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
    }

    if (version < 2) {
      return validationError.NONE;
    }

    var err = this.validateArrayPointer(
        internal.kMessagePayloadInterfaceIdsPointerOffset,
        internal.Uint32.encodedSize, internal.Uint32, true, [0], 0);

    if (err != validationError.NONE) {
      return err;
    }

    this.payloadInterfaceIds = this.message.getPayloadInterfaceIds();
    if (this.payloadInterfaceIds) {
      for (var interfaceId of this.payloadInterfaceIds) {
        if (!internal.isValidInterfaceId(interfaceId) ||
            internal.isPrimaryInterfaceId(interfaceId)) {
          return validationError.ILLEGAL_INTERFACE_ID;
        }
      }
    }

    // Set offset to the start of the payload and offsetLimit to the start of
    // the payload interface Ids so that payload can be validated using the
    // same messageValidator.
    this.offset = this.message.getHeaderNumBytes();
    this.offsetLimit = this.decodePointer(
        internal.kMessagePayloadInterfaceIdsPointerOffset);

    return validationError.NONE;
  };

  Validator.prototype.validateMessageIsRequestWithoutResponse = function() {
    if (this.message.isResponse() || this.message.expectsResponse()) {
      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateMessageIsRequestExpectingResponse = function() {
    if (this.message.isResponse() || !this.message.expectsResponse()) {
      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateMessageIsResponse = function() {
    if (this.message.expectsResponse() || !this.message.isResponse()) {
      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
    }
    return validationError.NONE;
  };

  // Returns the message.buffer relative offset this pointer "points to",
  // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
  // pointer's value is not valid.
  Validator.prototype.decodePointer = function(offset) {
    var pointerValue = this.message.buffer.getUint64(offset);
    if (pointerValue === 0)
      return NULL_MOJO_POINTER;
    var bufferOffset = offset + pointerValue;
    return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
  };

  Validator.prototype.decodeUnionSize = function(offset) {
    return this.message.buffer.getUint32(offset);
  };

  Validator.prototype.decodeUnionTag = function(offset) {
    return this.message.buffer.getUint32(offset + 4);
  };

  Validator.prototype.validateArrayPointer = function(
      offset, elementSize, elementType, nullable, expectedDimensionSizes,
      currentDimension) {
    var arrayOffset = this.decodePointer(offset);
    if (arrayOffset === null)
      return validationError.ILLEGAL_POINTER;

    if (arrayOffset === NULL_MOJO_POINTER)
      return nullable ?
          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;

    return this.validateArray(arrayOffset, elementSize, elementType,
                              expectedDimensionSizes, currentDimension);
  };

  Validator.prototype.validateStructPointer = function(
      offset, structClass, nullable) {
    var structOffset = this.decodePointer(offset);
    if (structOffset === null)
      return validationError.ILLEGAL_POINTER;

    if (structOffset === NULL_MOJO_POINTER)
      return nullable ?
          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;

    return structClass.validate(this, structOffset);
  };

  Validator.prototype.validateUnion = function(
      offset, unionClass, nullable) {
    var size = this.message.buffer.getUint32(offset);
    if (size == 0) {
      return nullable ?
          validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
    }

    return unionClass.validate(this, offset);
  };

  Validator.prototype.validateNestedUnion = function(
      offset, unionClass, nullable) {
    var unionOffset = this.decodePointer(offset);
    if (unionOffset === null)
      return validationError.ILLEGAL_POINTER;

    if (unionOffset === NULL_MOJO_POINTER)
      return nullable ?
          validationError.NONE : validationError.UNEXPECTED_NULL_UNION;

    return this.validateUnion(unionOffset, unionClass, nullable);
  };

  // This method assumes that the array at arrayPointerOffset has
  // been validated.

  Validator.prototype.arrayLength = function(arrayPointerOffset) {
    var arrayOffset = this.decodePointer(arrayPointerOffset);
    return this.message.buffer.getUint32(arrayOffset + 4);
  };

  Validator.prototype.validateMapPointer = function(
      offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
    // Validate the implicit map struct:
    // struct {array<keyClass> keys; array<valueClass> values};
    var structOffset = this.decodePointer(offset);
    if (structOffset === null)
      return validationError.ILLEGAL_POINTER;

    if (structOffset === NULL_MOJO_POINTER)
      return mapIsNullable ?
          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;

    var mapEncodedSize = internal.kStructHeaderSize +
                         internal.kMapStructPayloadSize;
    var err = this.validateStructHeader(structOffset, mapEncodedSize);
    if (err !== validationError.NONE)
        return err;

    // Validate the keys array.
    var keysArrayPointerOffset = structOffset + internal.kStructHeaderSize;
    err = this.validateArrayPointer(
        keysArrayPointerOffset, keyClass.encodedSize, keyClass, false, [0], 0);
    if (err !== validationError.NONE)
        return err;

    // Validate the values array.
    var valuesArrayPointerOffset = keysArrayPointerOffset + 8;
    var valuesArrayDimensions = [0]; // Validate the actual length below.
    if (valueClass instanceof internal.ArrayOf)
      valuesArrayDimensions =
          valuesArrayDimensions.concat(valueClass.dimensions());
    var err = this.validateArrayPointer(valuesArrayPointerOffset,
                                        valueClass.encodedSize,
                                        valueClass,
                                        valueIsNullable,
                                        valuesArrayDimensions,
                                        0);
    if (err !== validationError.NONE)
        return err;

    // Validate the lengths of the keys and values arrays.
    var keysArrayLength = this.arrayLength(keysArrayPointerOffset);
    var valuesArrayLength = this.arrayLength(valuesArrayPointerOffset);
    if (keysArrayLength != valuesArrayLength)
      return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;

    return validationError.NONE;
  };

  Validator.prototype.validateStringPointer = function(offset, nullable) {
    return this.validateArrayPointer(
        offset, internal.Uint8.encodedSize, internal.Uint8, nullable, [0], 0);
  };

  // Similar to Array_Data<T>::Validate()
  // mojo/public/cpp/bindings/lib/array_internal.h

  Validator.prototype.validateArray =
      function (offset, elementSize, elementType, expectedDimensionSizes,
                currentDimension) {
    if (!internal.isAligned(offset))
      return validationError.MISALIGNED_OBJECT;

    if (!this.isValidRange(offset, internal.kArrayHeaderSize))
      return validationError.ILLEGAL_MEMORY_RANGE;

    var numBytes = this.message.buffer.getUint32(offset);
    var numElements = this.message.buffer.getUint32(offset + 4);

    // Note: this computation is "safe" because elementSize <= 8 and
    // numElements is a uint32.
    var elementsTotalSize = (elementType === internal.PackedBool) ?
        Math.ceil(numElements / 8) : (elementSize * numElements);

    if (numBytes < internal.kArrayHeaderSize + elementsTotalSize)
      return validationError.UNEXPECTED_ARRAY_HEADER;

    if (expectedDimensionSizes[currentDimension] != 0 &&
        numElements != expectedDimensionSizes[currentDimension]) {
      return validationError.UNEXPECTED_ARRAY_HEADER;
    }

    if (!this.claimRange(offset, numBytes))
      return validationError.ILLEGAL_MEMORY_RANGE;

    // Validate the array's elements if they are pointers or handles.

    var elementsOffset = offset + internal.kArrayHeaderSize;
    var nullable = isNullable(elementType);

    if (isHandleClass(elementType))
      return this.validateHandleElements(elementsOffset, numElements, nullable);
    if (isInterfaceClass(elementType))
      return this.validateInterfaceElements(
          elementsOffset, numElements, nullable);
    if (isInterfaceRequestClass(elementType))
      return this.validateInterfaceRequestElements(
          elementsOffset, numElements, nullable);
    if (isAssociatedInterfaceClass(elementType))
      return this.validateAssociatedInterfaceElements(
          elementsOffset, numElements, nullable);
    if (isAssociatedInterfaceRequestClass(elementType))
      return this.validateAssociatedInterfaceRequestElements(
          elementsOffset, numElements, nullable);
    if (isStringClass(elementType))
      return this.validateArrayElements(
          elementsOffset, numElements, internal.Uint8, nullable, [0], 0);
    if (elementType instanceof internal.PointerTo)
      return this.validateStructElements(
          elementsOffset, numElements, elementType.cls, nullable);
    if (elementType instanceof internal.ArrayOf)
      return this.validateArrayElements(
          elementsOffset, numElements, elementType.cls, nullable,
          expectedDimensionSizes, currentDimension + 1);
    if (isEnumClass(elementType))
      return this.validateEnumElements(elementsOffset, numElements,
                                       elementType.cls);

    return validationError.NONE;
  };

  // Note: the |offset + i * elementSize| computation in the validateFooElements
  // methods below is "safe" because elementSize <= 8, offset and
  // numElements are uint32, and 0 <= i < numElements.

  Validator.prototype.validateHandleElements =
      function(offset, numElements, nullable) {
    var elementSize = internal.Handle.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateHandle(elementOffset, nullable);
      if (err != validationError.NONE)
        return err;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateInterfaceElements =
      function(offset, numElements, nullable) {
    var elementSize = internal.Interface.prototype.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateInterface(elementOffset, nullable);
      if (err != validationError.NONE)
        return err;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateInterfaceRequestElements =
      function(offset, numElements, nullable) {
    var elementSize = internal.InterfaceRequest.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateInterfaceRequest(elementOffset, nullable);
      if (err != validationError.NONE)
        return err;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateAssociatedInterfaceElements =
      function(offset, numElements, nullable) {
    var elementSize = internal.AssociatedInterfacePtrInfo.prototype.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateAssociatedInterface(elementOffset, nullable);
      if (err != validationError.NONE) {
        return err;
      }
    }
    return validationError.NONE;
  };

  Validator.prototype.validateAssociatedInterfaceRequestElements =
      function(offset, numElements, nullable) {
    var elementSize = internal.AssociatedInterfaceRequest.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateAssociatedInterfaceRequest(elementOffset,
          nullable);
      if (err != validationError.NONE) {
        return err;
      }
    }
    return validationError.NONE;
  };

  // The elementClass parameter is the element type of the element arrays.
  Validator.prototype.validateArrayElements =
      function(offset, numElements, elementClass, nullable,
               expectedDimensionSizes, currentDimension) {
    var elementSize = internal.PointerTo.prototype.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateArrayPointer(
          elementOffset, elementClass.encodedSize, elementClass, nullable,
          expectedDimensionSizes, currentDimension);
      if (err != validationError.NONE)
        return err;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateStructElements =
      function(offset, numElements, structClass, nullable) {
    var elementSize = internal.PointerTo.prototype.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err =
          this.validateStructPointer(elementOffset, structClass, nullable);
      if (err != validationError.NONE)
        return err;
    }
    return validationError.NONE;
  };

  Validator.prototype.validateEnumElements =
      function(offset, numElements, enumClass) {
    var elementSize = internal.Enum.prototype.encodedSize;
    for (var i = 0; i < numElements; i++) {
      var elementOffset = offset + i * elementSize;
      var err = this.validateEnum(elementOffset, enumClass);
      if (err != validationError.NONE)
        return err;
    }
    return validationError.NONE;
  };

  internal.validationError = validationError;
  internal.Validator = Validator;
  internal.ValidationErrorObserverForTesting =
      ValidationErrorObserverForTesting;
  internal.reportValidationError = reportValidationError;
  internal.isTestingMode = isTestingMode;
  internal.clearTestingMode = clearTestingMode;
})();
// mojo/public/interfaces/bindings/interface_control_messages.mojom.js is auto generated by mojom_bindings_generator.py, do not edit

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

(function() {
  var mojomId = 'mojo/public/interfaces/bindings/interface_control_messages.mojom';
  if (mojo.internal.isMojomLoaded(mojomId)) {
    console.warn('The following mojom is loaded multiple times: ' + mojomId);
    return;
  }
  mojo.internal.markMojomLoaded(mojomId);
  var bindings = mojo;
  var associatedBindings = mojo;
  var codec = mojo.internal;
  var validator = mojo.internal;

  var exports = mojo.internal.exposeNamespace('mojo.interfaceControl');


  var RUN_MESSAGE_ID = 0xFFFFFFFF;
  var RUN_OR_CLOSE_PIPE_MESSAGE_ID = 0xFFFFFFFE;

  function RunMessageParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  RunMessageParams.prototype.initDefaults_ = function() {
    this.input = null;
  };
  RunMessageParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  RunMessageParams.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 24}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RunMessageParams.input
    err = messageValidator.validateUnion(offset + codec.kStructHeaderSize + 0, RunInput, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  RunMessageParams.encodedSize = codec.kStructHeaderSize + 16;

  RunMessageParams.decode = function(decoder) {
    var packed;
    var val = new RunMessageParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.input =
        decoder.decodeStruct(RunInput);
    return val;
  };

  RunMessageParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RunMessageParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(RunInput, val.input);
  };
  function RunResponseMessageParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  RunResponseMessageParams.prototype.initDefaults_ = function() {
    this.output = null;
  };
  RunResponseMessageParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  RunResponseMessageParams.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 24}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RunResponseMessageParams.output
    err = messageValidator.validateUnion(offset + codec.kStructHeaderSize + 0, RunOutput, true);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  RunResponseMessageParams.encodedSize = codec.kStructHeaderSize + 16;

  RunResponseMessageParams.decode = function(decoder) {
    var packed;
    var val = new RunResponseMessageParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.output =
        decoder.decodeStruct(RunOutput);
    return val;
  };

  RunResponseMessageParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RunResponseMessageParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(RunOutput, val.output);
  };
  function QueryVersion(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  QueryVersion.prototype.initDefaults_ = function() {
  };
  QueryVersion.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  QueryVersion.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 8}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  QueryVersion.encodedSize = codec.kStructHeaderSize + 0;

  QueryVersion.decode = function(decoder) {
    var packed;
    var val = new QueryVersion();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    return val;
  };

  QueryVersion.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(QueryVersion.encodedSize);
    encoder.writeUint32(0);
  };
  function QueryVersionResult(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  QueryVersionResult.prototype.initDefaults_ = function() {
    this.version = 0;
  };
  QueryVersionResult.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  QueryVersionResult.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 16}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  QueryVersionResult.encodedSize = codec.kStructHeaderSize + 8;

  QueryVersionResult.decode = function(decoder) {
    var packed;
    var val = new QueryVersionResult();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.version =
        decoder.decodeStruct(codec.Uint32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  QueryVersionResult.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(QueryVersionResult.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Uint32, val.version);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function FlushForTesting(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  FlushForTesting.prototype.initDefaults_ = function() {
  };
  FlushForTesting.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  FlushForTesting.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 8}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  FlushForTesting.encodedSize = codec.kStructHeaderSize + 0;

  FlushForTesting.decode = function(decoder) {
    var packed;
    var val = new FlushForTesting();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    return val;
  };

  FlushForTesting.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(FlushForTesting.encodedSize);
    encoder.writeUint32(0);
  };
  function RunOrClosePipeMessageParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  RunOrClosePipeMessageParams.prototype.initDefaults_ = function() {
    this.input = null;
  };
  RunOrClosePipeMessageParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  RunOrClosePipeMessageParams.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 24}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RunOrClosePipeMessageParams.input
    err = messageValidator.validateUnion(offset + codec.kStructHeaderSize + 0, RunOrClosePipeInput, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  RunOrClosePipeMessageParams.encodedSize = codec.kStructHeaderSize + 16;

  RunOrClosePipeMessageParams.decode = function(decoder) {
    var packed;
    var val = new RunOrClosePipeMessageParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.input =
        decoder.decodeStruct(RunOrClosePipeInput);
    return val;
  };

  RunOrClosePipeMessageParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RunOrClosePipeMessageParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(RunOrClosePipeInput, val.input);
  };
  function RequireVersion(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  RequireVersion.prototype.initDefaults_ = function() {
    this.version = 0;
  };
  RequireVersion.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  RequireVersion.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 16}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  RequireVersion.encodedSize = codec.kStructHeaderSize + 8;

  RequireVersion.decode = function(decoder) {
    var packed;
    var val = new RequireVersion();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.version =
        decoder.decodeStruct(codec.Uint32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  RequireVersion.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RequireVersion.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Uint32, val.version);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function EnableIdleTracking(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  EnableIdleTracking.prototype.initDefaults_ = function() {
    this.timeoutInMicroseconds = 0;
  };
  EnableIdleTracking.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  EnableIdleTracking.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 16}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  EnableIdleTracking.encodedSize = codec.kStructHeaderSize + 8;

  EnableIdleTracking.decode = function(decoder) {
    var packed;
    var val = new EnableIdleTracking();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.timeoutInMicroseconds =
        decoder.decodeStruct(codec.Int64);
    return val;
  };

  EnableIdleTracking.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(EnableIdleTracking.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int64, val.timeoutInMicroseconds);
  };
  function MessageAck(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MessageAck.prototype.initDefaults_ = function() {
  };
  MessageAck.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  MessageAck.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 8}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MessageAck.encodedSize = codec.kStructHeaderSize + 0;

  MessageAck.decode = function(decoder) {
    var packed;
    var val = new MessageAck();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    return val;
  };

  MessageAck.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MessageAck.encodedSize);
    encoder.writeUint32(0);
  };
  function NotifyIdle(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  NotifyIdle.prototype.initDefaults_ = function() {
  };
  NotifyIdle.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  NotifyIdle.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 8}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  NotifyIdle.encodedSize = codec.kStructHeaderSize + 0;

  NotifyIdle.decode = function(decoder) {
    var packed;
    var val = new NotifyIdle();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    return val;
  };

  NotifyIdle.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(NotifyIdle.encodedSize);
    encoder.writeUint32(0);
  };

  function RunInput(value) {
    this.initDefault_();
    this.initValue_(value);
  }


  RunInput.Tags = {
    queryVersion: 0,
    flushForTesting: 1,
  };

  RunInput.prototype.initDefault_ = function() {
    this.$data = null;
    this.$tag = undefined;
  }

  RunInput.prototype.initValue_ = function(value) {
    if (value == undefined) {
      return;
    }

    var keys = Object.keys(value);
    if (keys.length == 0) {
      return;
    }

    if (keys.length > 1) {
      throw new TypeError("You may set only one member on a union.");
    }

    var fields = [
        "queryVersion",
        "flushForTesting",
    ];

    if (fields.indexOf(keys[0]) < 0) {
      throw new ReferenceError(keys[0] + " is not a RunInput member.");

    }

    this[keys[0]] = value[keys[0]];
  }
  Object.defineProperty(RunInput.prototype, "queryVersion", {
    get: function() {
      if (this.$tag != RunInput.Tags.queryVersion) {
        throw new ReferenceError(
            "RunInput.queryVersion is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunInput.Tags.queryVersion;
      this.$data = value;
    }
  });
  Object.defineProperty(RunInput.prototype, "flushForTesting", {
    get: function() {
      if (this.$tag != RunInput.Tags.flushForTesting) {
        throw new ReferenceError(
            "RunInput.flushForTesting is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunInput.Tags.flushForTesting;
      this.$data = value;
    }
  });


    RunInput.encode = function(encoder, val) {
      if (val == null) {
        encoder.writeUint64(0);
        encoder.writeUint64(0);
        return;
      }
      if (val.$tag == undefined) {
        throw new TypeError("Cannot encode unions with an unknown member set.");
      }

      encoder.writeUint32(16);
      encoder.writeUint32(val.$tag);
      switch (val.$tag) {
        case RunInput.Tags.queryVersion:
          encoder.encodeStructPointer(QueryVersion, val.queryVersion);
          break;
        case RunInput.Tags.flushForTesting:
          encoder.encodeStructPointer(FlushForTesting, val.flushForTesting);
          break;
      }
      encoder.align();
    };


    RunInput.decode = function(decoder) {
      var size = decoder.readUint32();
      if (size == 0) {
        decoder.readUint32();
        decoder.readUint64();
        return null;
      }

      var result = new RunInput();
      var tag = decoder.readUint32();
      switch (tag) {
        case RunInput.Tags.queryVersion:
          result.queryVersion = decoder.decodeStructPointer(QueryVersion);
          break;
        case RunInput.Tags.flushForTesting:
          result.flushForTesting = decoder.decodeStructPointer(FlushForTesting);
          break;
      }
      decoder.align();

      return result;
    };


    RunInput.validate = function(messageValidator, offset) {
      var size = messageValidator.decodeUnionSize(offset);
      if (size != 16) {
        return validator.validationError.INVALID_UNION_SIZE;
      }

      var tag = messageValidator.decodeUnionTag(offset);
      var data_offset = offset + 8;
      var err;
      switch (tag) {
        case RunInput.Tags.queryVersion:
          

    // validate RunInput.queryVersion
    err = messageValidator.validateStructPointer(data_offset, QueryVersion, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case RunInput.Tags.flushForTesting:
          

    // validate RunInput.flushForTesting
    err = messageValidator.validateStructPointer(data_offset, FlushForTesting, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
      }

      return validator.validationError.NONE;
    };

  RunInput.encodedSize = 16;

  function RunOutput(value) {
    this.initDefault_();
    this.initValue_(value);
  }


  RunOutput.Tags = {
    queryVersionResult: 0,
  };

  RunOutput.prototype.initDefault_ = function() {
    this.$data = null;
    this.$tag = undefined;
  }

  RunOutput.prototype.initValue_ = function(value) {
    if (value == undefined) {
      return;
    }

    var keys = Object.keys(value);
    if (keys.length == 0) {
      return;
    }

    if (keys.length > 1) {
      throw new TypeError("You may set only one member on a union.");
    }

    var fields = [
        "queryVersionResult",
    ];

    if (fields.indexOf(keys[0]) < 0) {
      throw new ReferenceError(keys[0] + " is not a RunOutput member.");

    }

    this[keys[0]] = value[keys[0]];
  }
  Object.defineProperty(RunOutput.prototype, "queryVersionResult", {
    get: function() {
      if (this.$tag != RunOutput.Tags.queryVersionResult) {
        throw new ReferenceError(
            "RunOutput.queryVersionResult is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOutput.Tags.queryVersionResult;
      this.$data = value;
    }
  });


    RunOutput.encode = function(encoder, val) {
      if (val == null) {
        encoder.writeUint64(0);
        encoder.writeUint64(0);
        return;
      }
      if (val.$tag == undefined) {
        throw new TypeError("Cannot encode unions with an unknown member set.");
      }

      encoder.writeUint32(16);
      encoder.writeUint32(val.$tag);
      switch (val.$tag) {
        case RunOutput.Tags.queryVersionResult:
          encoder.encodeStructPointer(QueryVersionResult, val.queryVersionResult);
          break;
      }
      encoder.align();
    };


    RunOutput.decode = function(decoder) {
      var size = decoder.readUint32();
      if (size == 0) {
        decoder.readUint32();
        decoder.readUint64();
        return null;
      }

      var result = new RunOutput();
      var tag = decoder.readUint32();
      switch (tag) {
        case RunOutput.Tags.queryVersionResult:
          result.queryVersionResult = decoder.decodeStructPointer(QueryVersionResult);
          break;
      }
      decoder.align();

      return result;
    };


    RunOutput.validate = function(messageValidator, offset) {
      var size = messageValidator.decodeUnionSize(offset);
      if (size != 16) {
        return validator.validationError.INVALID_UNION_SIZE;
      }

      var tag = messageValidator.decodeUnionTag(offset);
      var data_offset = offset + 8;
      var err;
      switch (tag) {
        case RunOutput.Tags.queryVersionResult:
          

    // validate RunOutput.queryVersionResult
    err = messageValidator.validateStructPointer(data_offset, QueryVersionResult, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
      }

      return validator.validationError.NONE;
    };

  RunOutput.encodedSize = 16;

  function RunOrClosePipeInput(value) {
    this.initDefault_();
    this.initValue_(value);
  }


  RunOrClosePipeInput.Tags = {
    requireVersion: 0,
    enableIdleTracking: 1,
    messageAck: 2,
    notifyIdle: 3,
  };

  RunOrClosePipeInput.prototype.initDefault_ = function() {
    this.$data = null;
    this.$tag = undefined;
  }

  RunOrClosePipeInput.prototype.initValue_ = function(value) {
    if (value == undefined) {
      return;
    }

    var keys = Object.keys(value);
    if (keys.length == 0) {
      return;
    }

    if (keys.length > 1) {
      throw new TypeError("You may set only one member on a union.");
    }

    var fields = [
        "requireVersion",
        "enableIdleTracking",
        "messageAck",
        "notifyIdle",
    ];

    if (fields.indexOf(keys[0]) < 0) {
      throw new ReferenceError(keys[0] + " is not a RunOrClosePipeInput member.");

    }

    this[keys[0]] = value[keys[0]];
  }
  Object.defineProperty(RunOrClosePipeInput.prototype, "requireVersion", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.requireVersion) {
        throw new ReferenceError(
            "RunOrClosePipeInput.requireVersion is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.requireVersion;
      this.$data = value;
    }
  });
  Object.defineProperty(RunOrClosePipeInput.prototype, "enableIdleTracking", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.enableIdleTracking) {
        throw new ReferenceError(
            "RunOrClosePipeInput.enableIdleTracking is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.enableIdleTracking;
      this.$data = value;
    }
  });
  Object.defineProperty(RunOrClosePipeInput.prototype, "messageAck", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.messageAck) {
        throw new ReferenceError(
            "RunOrClosePipeInput.messageAck is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.messageAck;
      this.$data = value;
    }
  });
  Object.defineProperty(RunOrClosePipeInput.prototype, "notifyIdle", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.notifyIdle) {
        throw new ReferenceError(
            "RunOrClosePipeInput.notifyIdle is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.notifyIdle;
      this.$data = value;
    }
  });


    RunOrClosePipeInput.encode = function(encoder, val) {
      if (val == null) {
        encoder.writeUint64(0);
        encoder.writeUint64(0);
        return;
      }
      if (val.$tag == undefined) {
        throw new TypeError("Cannot encode unions with an unknown member set.");
      }

      encoder.writeUint32(16);
      encoder.writeUint32(val.$tag);
      switch (val.$tag) {
        case RunOrClosePipeInput.Tags.requireVersion:
          encoder.encodeStructPointer(RequireVersion, val.requireVersion);
          break;
        case RunOrClosePipeInput.Tags.enableIdleTracking:
          encoder.encodeStructPointer(EnableIdleTracking, val.enableIdleTracking);
          break;
        case RunOrClosePipeInput.Tags.messageAck:
          encoder.encodeStructPointer(MessageAck, val.messageAck);
          break;
        case RunOrClosePipeInput.Tags.notifyIdle:
          encoder.encodeStructPointer(NotifyIdle, val.notifyIdle);
          break;
      }
      encoder.align();
    };


    RunOrClosePipeInput.decode = function(decoder) {
      var size = decoder.readUint32();
      if (size == 0) {
        decoder.readUint32();
        decoder.readUint64();
        return null;
      }

      var result = new RunOrClosePipeInput();
      var tag = decoder.readUint32();
      switch (tag) {
        case RunOrClosePipeInput.Tags.requireVersion:
          result.requireVersion = decoder.decodeStructPointer(RequireVersion);
          break;
        case RunOrClosePipeInput.Tags.enableIdleTracking:
          result.enableIdleTracking = decoder.decodeStructPointer(EnableIdleTracking);
          break;
        case RunOrClosePipeInput.Tags.messageAck:
          result.messageAck = decoder.decodeStructPointer(MessageAck);
          break;
        case RunOrClosePipeInput.Tags.notifyIdle:
          result.notifyIdle = decoder.decodeStructPointer(NotifyIdle);
          break;
      }
      decoder.align();

      return result;
    };


    RunOrClosePipeInput.validate = function(messageValidator, offset) {
      var size = messageValidator.decodeUnionSize(offset);
      if (size != 16) {
        return validator.validationError.INVALID_UNION_SIZE;
      }

      var tag = messageValidator.decodeUnionTag(offset);
      var data_offset = offset + 8;
      var err;
      switch (tag) {
        case RunOrClosePipeInput.Tags.requireVersion:
          

    // validate RunOrClosePipeInput.requireVersion
    err = messageValidator.validateStructPointer(data_offset, RequireVersion, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case RunOrClosePipeInput.Tags.enableIdleTracking:
          

    // validate RunOrClosePipeInput.enableIdleTracking
    err = messageValidator.validateStructPointer(data_offset, EnableIdleTracking, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case RunOrClosePipeInput.Tags.messageAck:
          

    // validate RunOrClosePipeInput.messageAck
    err = messageValidator.validateStructPointer(data_offset, MessageAck, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case RunOrClosePipeInput.Tags.notifyIdle:
          

    // validate RunOrClosePipeInput.notifyIdle
    err = messageValidator.validateStructPointer(data_offset, NotifyIdle, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
      }

      return validator.validationError.NONE;
    };

  RunOrClosePipeInput.encodedSize = 16;
  exports.RUN_MESSAGE_ID = RUN_MESSAGE_ID;
  exports.RUN_OR_CLOSE_PIPE_MESSAGE_ID = RUN_OR_CLOSE_PIPE_MESSAGE_ID;
  exports.RunMessageParams = RunMessageParams;
  exports.RunResponseMessageParams = RunResponseMessageParams;
  exports.QueryVersion = QueryVersion;
  exports.QueryVersionResult = QueryVersionResult;
  exports.FlushForTesting = FlushForTesting;
  exports.RunOrClosePipeMessageParams = RunOrClosePipeMessageParams;
  exports.RequireVersion = RequireVersion;
  exports.EnableIdleTracking = EnableIdleTracking;
  exports.MessageAck = MessageAck;
  exports.NotifyIdle = NotifyIdle;
  exports.RunInput = RunInput;
  exports.RunOutput = RunOutput;
  exports.RunOrClosePipeInput = RunOrClosePipeInput;
})();// mojo/public/interfaces/bindings/pipe_control_messages.mojom.js is auto generated by mojom_bindings_generator.py, do not edit

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

(function() {
  var mojomId = 'mojo/public/interfaces/bindings/pipe_control_messages.mojom';
  if (mojo.internal.isMojomLoaded(mojomId)) {
    console.warn('The following mojom is loaded multiple times: ' + mojomId);
    return;
  }
  mojo.internal.markMojomLoaded(mojomId);
  var bindings = mojo;
  var associatedBindings = mojo;
  var codec = mojo.internal;
  var validator = mojo.internal;

  var exports = mojo.internal.exposeNamespace('mojo.pipeControl');


  var RUN_OR_CLOSE_PIPE_MESSAGE_ID = 0xFFFFFFFE;

  function RunOrClosePipeMessageParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  RunOrClosePipeMessageParams.prototype.initDefaults_ = function() {
    this.input = null;
  };
  RunOrClosePipeMessageParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  RunOrClosePipeMessageParams.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 24}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RunOrClosePipeMessageParams.input
    err = messageValidator.validateUnion(offset + codec.kStructHeaderSize + 0, RunOrClosePipeInput, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  RunOrClosePipeMessageParams.encodedSize = codec.kStructHeaderSize + 16;

  RunOrClosePipeMessageParams.decode = function(decoder) {
    var packed;
    var val = new RunOrClosePipeMessageParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.input =
        decoder.decodeStruct(RunOrClosePipeInput);
    return val;
  };

  RunOrClosePipeMessageParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RunOrClosePipeMessageParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(RunOrClosePipeInput, val.input);
  };
  function DisconnectReason(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  DisconnectReason.prototype.initDefaults_ = function() {
    this.customReason = 0;
    this.description = null;
  };
  DisconnectReason.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  DisconnectReason.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 24}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;



    // validate DisconnectReason.description
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 8, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  DisconnectReason.encodedSize = codec.kStructHeaderSize + 16;

  DisconnectReason.decode = function(decoder) {
    var packed;
    var val = new DisconnectReason();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.customReason =
        decoder.decodeStruct(codec.Uint32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.description =
        decoder.decodeStruct(codec.String);
    return val;
  };

  DisconnectReason.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(DisconnectReason.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Uint32, val.customReason);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.String, val.description);
  };
  function PeerAssociatedEndpointClosedEvent(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  PeerAssociatedEndpointClosedEvent.prototype.initDefaults_ = function() {
    this.id = 0;
    this.disconnectReason = null;
  };
  PeerAssociatedEndpointClosedEvent.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  PeerAssociatedEndpointClosedEvent.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 24}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;



    // validate PeerAssociatedEndpointClosedEvent.disconnectReason
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 8, DisconnectReason, true);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  PeerAssociatedEndpointClosedEvent.encodedSize = codec.kStructHeaderSize + 16;

  PeerAssociatedEndpointClosedEvent.decode = function(decoder) {
    var packed;
    var val = new PeerAssociatedEndpointClosedEvent();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.id =
        decoder.decodeStruct(codec.Uint32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.disconnectReason =
        decoder.decodeStructPointer(DisconnectReason);
    return val;
  };

  PeerAssociatedEndpointClosedEvent.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(PeerAssociatedEndpointClosedEvent.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Uint32, val.id);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStructPointer(DisconnectReason, val.disconnectReason);
  };
  function PauseUntilFlushCompletes(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  PauseUntilFlushCompletes.prototype.initDefaults_ = function() {
    this.flushPipe = null;
  };
  PauseUntilFlushCompletes.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  PauseUntilFlushCompletes.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 16}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    // validate PauseUntilFlushCompletes.flushPipe
    err = messageValidator.validateHandle(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  PauseUntilFlushCompletes.encodedSize = codec.kStructHeaderSize + 8;

  PauseUntilFlushCompletes.decode = function(decoder) {
    var packed;
    var val = new PauseUntilFlushCompletes();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.flushPipe =
        decoder.decodeStruct(codec.Handle);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  PauseUntilFlushCompletes.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(PauseUntilFlushCompletes.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Handle, val.flushPipe);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function FlushAsync(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  FlushAsync.prototype.initDefaults_ = function() {
    this.flusherPipe = null;
  };
  FlushAsync.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  FlushAsync.validate = function(messageValidator, offset) {
    var err;
    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
    if (err !== validator.validationError.NONE)
        return err;

    var kVersionSizes = [
      {version: 0, numBytes: 16}
    ];
    err = messageValidator.validateStructVersion(offset, kVersionSizes);
    if (err !== validator.validationError.NONE)
        return err;


    // validate FlushAsync.flusherPipe
    err = messageValidator.validateHandle(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  FlushAsync.encodedSize = codec.kStructHeaderSize + 8;

  FlushAsync.decode = function(decoder) {
    var packed;
    var val = new FlushAsync();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.flusherPipe =
        decoder.decodeStruct(codec.Handle);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  FlushAsync.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(FlushAsync.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Handle, val.flusherPipe);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };

  function RunOrClosePipeInput(value) {
    this.initDefault_();
    this.initValue_(value);
  }


  RunOrClosePipeInput.Tags = {
    peerAssociatedEndpointClosedEvent: 0,
    pauseUntilFlushCompletes: 1,
    flushAsync: 2,
  };

  RunOrClosePipeInput.prototype.initDefault_ = function() {
    this.$data = null;
    this.$tag = undefined;
  }

  RunOrClosePipeInput.prototype.initValue_ = function(value) {
    if (value == undefined) {
      return;
    }

    var keys = Object.keys(value);
    if (keys.length == 0) {
      return;
    }

    if (keys.length > 1) {
      throw new TypeError("You may set only one member on a union.");
    }

    var fields = [
        "peerAssociatedEndpointClosedEvent",
        "pauseUntilFlushCompletes",
        "flushAsync",
    ];

    if (fields.indexOf(keys[0]) < 0) {
      throw new ReferenceError(keys[0] + " is not a RunOrClosePipeInput member.");

    }

    this[keys[0]] = value[keys[0]];
  }
  Object.defineProperty(RunOrClosePipeInput.prototype, "peerAssociatedEndpointClosedEvent", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.peerAssociatedEndpointClosedEvent) {
        throw new ReferenceError(
            "RunOrClosePipeInput.peerAssociatedEndpointClosedEvent is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.peerAssociatedEndpointClosedEvent;
      this.$data = value;
    }
  });
  Object.defineProperty(RunOrClosePipeInput.prototype, "pauseUntilFlushCompletes", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.pauseUntilFlushCompletes) {
        throw new ReferenceError(
            "RunOrClosePipeInput.pauseUntilFlushCompletes is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.pauseUntilFlushCompletes;
      this.$data = value;
    }
  });
  Object.defineProperty(RunOrClosePipeInput.prototype, "flushAsync", {
    get: function() {
      if (this.$tag != RunOrClosePipeInput.Tags.flushAsync) {
        throw new ReferenceError(
            "RunOrClosePipeInput.flushAsync is not currently set.");
      }
      return this.$data;
    },

    set: function(value) {
      this.$tag = RunOrClosePipeInput.Tags.flushAsync;
      this.$data = value;
    }
  });


    RunOrClosePipeInput.encode = function(encoder, val) {
      if (val == null) {
        encoder.writeUint64(0);
        encoder.writeUint64(0);
        return;
      }
      if (val.$tag == undefined) {
        throw new TypeError("Cannot encode unions with an unknown member set.");
      }

      encoder.writeUint32(16);
      encoder.writeUint32(val.$tag);
      switch (val.$tag) {
        case RunOrClosePipeInput.Tags.peerAssociatedEndpointClosedEvent:
          encoder.encodeStructPointer(PeerAssociatedEndpointClosedEvent, val.peerAssociatedEndpointClosedEvent);
          break;
        case RunOrClosePipeInput.Tags.pauseUntilFlushCompletes:
          encoder.encodeStructPointer(PauseUntilFlushCompletes, val.pauseUntilFlushCompletes);
          break;
        case RunOrClosePipeInput.Tags.flushAsync:
          encoder.encodeStructPointer(FlushAsync, val.flushAsync);
          break;
      }
      encoder.align();
    };


    RunOrClosePipeInput.decode = function(decoder) {
      var size = decoder.readUint32();
      if (size == 0) {
        decoder.readUint32();
        decoder.readUint64();
        return null;
      }

      var result = new RunOrClosePipeInput();
      var tag = decoder.readUint32();
      switch (tag) {
        case RunOrClosePipeInput.Tags.peerAssociatedEndpointClosedEvent:
          result.peerAssociatedEndpointClosedEvent = decoder.decodeStructPointer(PeerAssociatedEndpointClosedEvent);
          break;
        case RunOrClosePipeInput.Tags.pauseUntilFlushCompletes:
          result.pauseUntilFlushCompletes = decoder.decodeStructPointer(PauseUntilFlushCompletes);
          break;
        case RunOrClosePipeInput.Tags.flushAsync:
          result.flushAsync = decoder.decodeStructPointer(FlushAsync);
          break;
      }
      decoder.align();

      return result;
    };


    RunOrClosePipeInput.validate = function(messageValidator, offset) {
      var size = messageValidator.decodeUnionSize(offset);
      if (size != 16) {
        return validator.validationError.INVALID_UNION_SIZE;
      }

      var tag = messageValidator.decodeUnionTag(offset);
      var data_offset = offset + 8;
      var err;
      switch (tag) {
        case RunOrClosePipeInput.Tags.peerAssociatedEndpointClosedEvent:
          

    // validate RunOrClosePipeInput.peerAssociatedEndpointClosedEvent
    err = messageValidator.validateStructPointer(data_offset, PeerAssociatedEndpointClosedEvent, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case RunOrClosePipeInput.Tags.pauseUntilFlushCompletes:
          

    // validate RunOrClosePipeInput.pauseUntilFlushCompletes
    err = messageValidator.validateStructPointer(data_offset, PauseUntilFlushCompletes, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case RunOrClosePipeInput.Tags.flushAsync:
          

    // validate RunOrClosePipeInput.flushAsync
    err = messageValidator.validateStructPointer(data_offset, FlushAsync, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
      }

      return validator.validationError.NONE;
    };

  RunOrClosePipeInput.encodedSize = 16;
  exports.RUN_OR_CLOSE_PIPE_MESSAGE_ID = RUN_OR_CLOSE_PIPE_MESSAGE_ID;
  exports.RunOrClosePipeMessageParams = RunOrClosePipeMessageParams;
  exports.DisconnectReason = DisconnectReason;
  exports.PeerAssociatedEndpointClosedEvent = PeerAssociatedEndpointClosedEvent;
  exports.PauseUntilFlushCompletes = PauseUntilFlushCompletes;
  exports.FlushAsync = FlushAsync;
  exports.RunOrClosePipeInput = RunOrClosePipeInput;
})();